Skip to content

Commit

Permalink
Merge pull request #738 from fractal-analytics-platform/737-align-wit…
Browse files Browse the repository at this point in the history
…h-upcoming-fractal-server-29

737 align with upcoming fractal server 2.9
  • Loading branch information
tcompa authored Nov 8, 2024
2 parents a0e934d + f531166 commit b8545e8
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 152 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
**Note**: Numbers like (\#123) point to closed Pull Requests on the fractal repository.

# 2.5.0

* Update task-collection commands, to align with [fractal-server 2.9.0](https://github.com/fractal-analytics-platform/fractal-server/blob/main/CHANGELOG.md#290) (\#738).
* Remove (internal) obsolete `do_not_separate_logs` argument (\#738).

# 2.4.0

> WARNING: This release has a breaking change in the `project add-dataset` command.
Expand Down
15 changes: 9 additions & 6 deletions fractal_client/cmd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
from ._task import get_task_list
from ._task import patch_task
from ._task import post_task
from ._task import task_collect_custom
from ._task import task_collect_pip
from ._task import task_collection_check
from ._task_collection import show_task_group_activity
from ._task_collection import task_collect_custom
from ._task_collection import task_collect_pip
from ._user import user_edit
from ._user import user_list
from ._user import user_register
Expand Down Expand Up @@ -153,9 +153,12 @@ def task(
function_kwargs = get_kwargs(parameters, kwargs)
iface = task_collect_custom(client, batch=batch, **function_kwargs)
elif subcmd == "check-collection":
parameters = ["state_id", "include_logs", "do_not_separate_logs"]
parameters = [
"task_group_activity_id",
"include_logs",
]
function_kwargs = get_kwargs(parameters, kwargs)
iface = task_collection_check(client, **function_kwargs)
iface = show_task_group_activity(client, **function_kwargs)
elif subcmd == "new":
parameters = [
"name",
Expand Down Expand Up @@ -271,7 +274,7 @@ def job(
function_kwargs = get_kwargs(parameters, kwargs)
iface = get_job_list(client, batch=batch, **function_kwargs)
elif subcmd == "show":
parameters = ["project_id", "job_id", "do_not_separate_logs"]
parameters = ["project_id", "job_id"]
function_kwargs = get_kwargs(parameters, kwargs)
iface = get_job(client, batch=batch, **function_kwargs)
elif subcmd == "download-logs":
Expand Down
117 changes: 0 additions & 117 deletions fractal_client/cmd/_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,123 +16,6 @@ def get_task_list(client: AuthClient) -> Interface:
return Interface(retcode=0, data=task_list)


def task_collect_pip(
client: AuthClient,
*,
package: str,
package_version: str | None = None,
python_version: str | None = None,
package_extras: str | None = None,
pinned_dependency: list[str] | None = None,
private: bool = False,
batch: bool = False,
) -> Interface:

# Construct TaskCollectPip object
task_collect = dict(package=package)
if package_version:
task_collect["package_version"] = package_version
if python_version:
task_collect["python_version"] = python_version
if package_extras:
task_collect["package_extras"] = package_extras
if pinned_dependency:
for pin in pinned_dependency:
if len(pin.split("=")) != 2:
logging.error(
f"Invalid pin: {pin}.\nPins must be written as "
"'--pinned-dependency PACKAGE_NAME=PACKAGE_VERSION'"
)
sys.exit(1)
task_collect["pinned_package_versions"] = {
_name: _version
for _name, _version in (p.split("=") for p in pinned_dependency)
}

is_private = "?private=true" if private else ""

res = client.post(
f"{settings.BASE_URL}/task/collect/pip/{is_private}", json=task_collect
)

state = check_response(res, expected_status_code=[200, 201])
if batch:
output = f"{state['id']} {state['data']['venv_path']}"
return Interface(retcode=0, data=output)
else:
return Interface(retcode=0, data=state)


def task_collect_custom(
client: AuthClient,
*,
label: str,
python_interpreter: str,
manifest: str,
version: str | None = None,
package_name: str | None = None,
package_root: str | None = None,
private: bool = False,
batch: bool = False,
) -> Interface:

try:
with open(manifest, "r") as f:
manifest_dict = json.load(f)
except FileNotFoundError as e:
raise FileNotFoundError(
f"Fractal Client cannot find the file {manifest}. "
"Note that the file must be on the same machine where Fractal "
f"Client is running.\nOriginal error: {e}."
)

task_collect = dict(
label=label,
python_interpreter=python_interpreter,
manifest=manifest_dict,
)
if version:
task_collect["version"] = version
if package_name:
task_collect["package_name"] = package_name
if package_root:
task_collect["package_root"] = package_root
is_private = "?private=true" if private else ""

res = client.post(
f"{settings.BASE_URL}/task/collect/custom/{is_private}",
json=task_collect,
)

task_list = check_response(
res, expected_status_code=201, redact_long_payload=True
)

if batch:
task_ids = [str(task["id"]) for task in task_list]
return Interface(retcode=0, data=" ".join(task_ids))
else:
return Interface(retcode=0, data=task_list)


def task_collection_check(
client: AuthClient,
*,
state_id: int,
include_logs: bool,
) -> Interface:

res = client.get(f"{settings.BASE_URL}/task/collect/{state_id}/")
state = check_response(res, expected_status_code=200)

# Remove key-value pairs with None value
state["data"] = {key: val for (key, val) in state["data"].items() if val}
if (include_logs is False) and ("log" in state["data"]):
state["data"]["log"] = None

return Interface(retcode=0, data=state)


def post_task(
client: AuthClient,
*,
Expand Down
125 changes: 125 additions & 0 deletions fractal_client/cmd/_task_collection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import json
import logging
import sys

from fractal_client.authclient import AuthClient
from fractal_client.config import settings
from fractal_client.interface import Interface
from fractal_client.response import check_response


def task_collect_pip(
client: AuthClient,
*,
package: str,
package_version: str | None = None,
python_version: str | None = None,
package_extras: str | None = None,
pinned_dependency: list[str] | None = None,
private: bool = False,
batch: bool = False,
) -> Interface:

# Construct TaskCollectPip object
task_collect = dict(package=package)
if package_version:
task_collect["package_version"] = package_version
if python_version:
task_collect["python_version"] = python_version
if package_extras:
task_collect["package_extras"] = package_extras
if pinned_dependency:
for pin in pinned_dependency:
if len(pin.split("=")) != 2:
logging.error(
f"Invalid pin: {pin}.\nPins must be written as "
"'--pinned-dependency PACKAGE_NAME=PACKAGE_VERSION'"
)
sys.exit(1)
task_collect["pinned_package_versions"] = {
_name: _version
for _name, _version in (p.split("=") for p in pinned_dependency)
}

is_private = "?private=true" if private else ""

res = client.post(
f"{settings.BASE_URL}/task/collect/pip/{is_private}",
json=task_collect,
)

task_group_activity = check_response(res, expected_status_code=202)
if batch:
return Interface(retcode=0, data=task_group_activity["id"])
else:
return Interface(retcode=0, data=task_group_activity)


def task_collect_custom(
client: AuthClient,
*,
label: str,
python_interpreter: str,
manifest: str,
version: str | None = None,
package_name: str | None = None,
package_root: str | None = None,
private: bool = False,
batch: bool = False,
) -> Interface:

try:
with open(manifest, "r") as f:
manifest_dict = json.load(f)
except FileNotFoundError as e:
raise FileNotFoundError(
f"Fractal Client cannot find the file {manifest}. "
"Note that the file must be on the same machine where Fractal "
f"Client is running.\nOriginal error: {e}."
)

task_collect = dict(
label=label,
python_interpreter=python_interpreter,
manifest=manifest_dict,
)
if version:
task_collect["version"] = version
if package_name:
task_collect["package_name"] = package_name
if package_root:
task_collect["package_root"] = package_root
is_private = "?private=true" if private else ""

res = client.post(
f"{settings.BASE_URL}/task/collect/custom/{is_private}",
json=task_collect,
)

task_list = check_response(
res, expected_status_code=201, redact_long_payload=True
)

if batch:
task_ids = [str(task["id"]) for task in task_list]
return Interface(retcode=0, data=" ".join(task_ids))
else:
return Interface(retcode=0, data=task_list)


def show_task_group_activity(
client: AuthClient,
*,
task_group_activity_id: int,
include_logs: bool,
) -> Interface:
res = client.get(
f"{settings.BASE_URL}/task-group/activity/{task_group_activity_id}/"
)
task_group_activity = check_response(res, expected_status_code=200)

# Remove key-value pairs with None value
if include_logs is False:
task_group_activity["log"] = None

return Interface(retcode=0, data=task_group_activity)
4 changes: 2 additions & 2 deletions fractal_client/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@
allow_abbrev=False,
)
task_check_collection_parser.add_argument(
"state_id",
help="State ID of the collection (see output of task collect).",
"task_group_activity_id",
help="Activity ID of the collection (see output of `task collect`).",
type=int,
)
task_check_collection_parser.add_argument(
Expand Down
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions tests/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def test_job_submit(
PACKAGE_PATH = "/tmp/fractal_tasks_mock-0.0.1-py3-none-any.whl"
urlretrieve(PACKAGE_URL, PACKAGE_PATH)

res = invoke(f"task collect {PACKAGE_PATH}")
res = invoke(f"--batch task collect {PACKAGE_PATH}")
assert res.retcode == 0
state_id = res.data["id"]
activity_id = res.data

# Create a project
project = project_factory(name=new_name())
Expand All @@ -41,8 +41,8 @@ def test_job_submit(
# Wait for task collection to end
starting_time = time.perf_counter()
while True:
res1 = invoke(f"task check-collection {state_id}")
if res1.data["data"]["status"] == "OK":
res1 = invoke(f"task check-collection {activity_id}")
if res1.data["status"] == "OK":
debug(res1.data)
break
time.sleep(0.1)
Expand Down
Loading

0 comments on commit b8545e8

Please sign in to comment.