fractal-task-tools 0.0.8__tar.gz → 0.0.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fractal-task-tools might be problematic. Click here for more details.
- {fractal_task_tools-0.0.8/src/fractal_task_tools.egg-info → fractal_task_tools-0.0.9}/PKG-INFO +10 -2
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/pyproject.toml +9 -2
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/__init__.py +1 -1
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_create_manifest.py +17 -3
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_deepdiff.py +2 -2
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_descriptions.py +32 -16
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_package_name_tools.py +1 -1
- fractal_task_tools-0.0.9/src/fractal_task_tools/_task_arguments.py +75 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/task_models.py +75 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9/src/fractal_task_tools.egg-info}/PKG-INFO +10 -2
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/SOURCES.txt +3 -1
- fractal_task_tools-0.0.9/src/fractal_task_tools.egg-info/requires.txt +15 -0
- fractal_task_tools-0.0.9/tests/test_create_manifest.py +68 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_create_schema_for_single_task.py +48 -2
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_task_models.py +24 -0
- fractal_task_tools-0.0.9/tests/test_unit_lib_descriptions.py +58 -0
- fractal_task_tools-0.0.9/tests/test_validate_arguments.py +85 -0
- fractal_task_tools-0.0.8/src/fractal_task_tools.egg-info/requires.txt +0 -8
- fractal_task_tools-0.0.8/tests/test_create_manifest.py +0 -32
- fractal_task_tools-0.0.8/tests/test_unit_lib_descriptions.py +0 -28
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/LICENSE +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/README.md +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/setup.cfg +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_args_schemas.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_cli.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_cli_tools.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_pydantic_generatejsonschema.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_signature_constraints.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_task_docs.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_titles.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/task_wrapper.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/dependency_links.txt +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/entry_points.txt +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/top_level.txt +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_cli.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_deepdiff.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_extract_function.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_normalize_package_name.py +0 -0
- {fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_task_wrapper.py +0 -0
{fractal_task_tools-0.0.8/src/fractal_task_tools.egg-info → fractal_task_tools-0.0.9}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fractal-task-tools
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: Shared tools for Fractal tasks
|
|
5
5
|
Author-email: Tommaso Comparin <tommaso.comparin@exact-lab.it>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -17,6 +17,14 @@ Requires-Dist: bumpver==2024.1130; extra == "dev"
|
|
|
17
17
|
Requires-Dist: devtools==0.12.2; extra == "dev"
|
|
18
18
|
Requires-Dist: pytest<9.0.0,>=8.3.0; extra == "dev"
|
|
19
19
|
Requires-Dist: coverage<7.7.0,>=7.6.0; extra == "dev"
|
|
20
|
+
Requires-Dist: mkdocs==1.5.2; extra == "dev"
|
|
21
|
+
Requires-Dist: mkdocs-material==9.1.21; extra == "dev"
|
|
22
|
+
Requires-Dist: mkdocs-literate-nav==0.5.0; extra == "dev"
|
|
23
|
+
Requires-Dist: mkdocs-gen-files==0.4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: mkdocs-section-index==0.3.5; extra == "dev"
|
|
25
|
+
Requires-Dist: mkdocstrings[python]==0.25.2; extra == "dev"
|
|
26
|
+
Requires-Dist: mkdocs-include-markdown-plugin<6.0.0,>=5.0.0; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
20
28
|
|
|
21
29
|
# Fractal task tools
|
|
22
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fractal-task-tools"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.9"
|
|
4
4
|
description = "Shared tools for Fractal tasks"
|
|
5
5
|
authors = [
|
|
6
6
|
{name="Tommaso Comparin", email="tommaso.comparin@exact-lab.it"},
|
|
@@ -18,6 +18,13 @@ dev = [
|
|
|
18
18
|
"devtools ==0.12.2",
|
|
19
19
|
"pytest >=8.3.0, <9.0.0",
|
|
20
20
|
"coverage >=7.6.0,<7.7.0",
|
|
21
|
+
"mkdocs ==1.5.2",
|
|
22
|
+
"mkdocs-material ==9.1.21",
|
|
23
|
+
"mkdocs-literate-nav ==0.5.0",
|
|
24
|
+
"mkdocs-gen-files ==0.4.0",
|
|
25
|
+
"mkdocs-section-index ==0.3.5",
|
|
26
|
+
"mkdocstrings[python] ==0.25.2",
|
|
27
|
+
"mkdocs-include-markdown-plugin >=5.0.0,<6.0.0",
|
|
21
28
|
]
|
|
22
29
|
|
|
23
30
|
[project.urls]
|
|
@@ -34,7 +41,7 @@ build-backend = "setuptools.build_meta"
|
|
|
34
41
|
fractal-manifest = "fractal_task_tools._cli:main"
|
|
35
42
|
|
|
36
43
|
[tool.bumpver]
|
|
37
|
-
current_version = "0.0.
|
|
44
|
+
current_version = "0.0.9"
|
|
38
45
|
version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
|
|
39
46
|
commit_message = "bump version {old_version} -> {new_version}"
|
|
40
47
|
commit = true
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_create_manifest.py
RENAMED
|
@@ -7,9 +7,10 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from ._args_schemas import create_schema_for_single_task
|
|
9
9
|
from ._package_name_tools import normalize_package_name
|
|
10
|
+
from ._task_arguments import validate_arguments
|
|
10
11
|
from ._task_docs import create_docs_info
|
|
11
12
|
from ._task_docs import read_docs_info_from_file
|
|
12
|
-
|
|
13
|
+
from .task_models import _BaseTask
|
|
13
14
|
|
|
14
15
|
ARGS_SCHEMA_VERSION = "pydantic_v2"
|
|
15
16
|
MANIFEST_FILENAME = "__FRACTAL_MANIFEST__.json"
|
|
@@ -60,7 +61,7 @@ def create_manifest(
|
|
|
60
61
|
task_list_module = import_module(f"{package_name}.{task_list_path}")
|
|
61
62
|
|
|
62
63
|
# Load TASK_LIST
|
|
63
|
-
TASK_LIST = getattr(task_list_module, "TASK_LIST")
|
|
64
|
+
TASK_LIST: list[_BaseTask] = getattr(task_list_module, "TASK_LIST")
|
|
64
65
|
|
|
65
66
|
# Load INPUT_MODELS
|
|
66
67
|
try:
|
|
@@ -89,9 +90,15 @@ def create_manifest(
|
|
|
89
90
|
for task_obj in TASK_LIST:
|
|
90
91
|
# Convert Pydantic object to dictionary
|
|
91
92
|
task_dict = task_obj.model_dump(
|
|
92
|
-
exclude={
|
|
93
|
+
exclude={
|
|
94
|
+
"meta_init",
|
|
95
|
+
"executable_init",
|
|
96
|
+
"meta",
|
|
97
|
+
"executable",
|
|
98
|
+
},
|
|
93
99
|
exclude_unset=True,
|
|
94
100
|
)
|
|
101
|
+
task_dict["type"] = task_obj.type
|
|
95
102
|
|
|
96
103
|
# Copy some properties from `task_obj` to `task_dict`
|
|
97
104
|
if task_obj.executable_non_parallel is not None:
|
|
@@ -115,6 +122,13 @@ def create_manifest(
|
|
|
115
122
|
package=package_name,
|
|
116
123
|
pydantic_models=INPUT_MODELS,
|
|
117
124
|
)
|
|
125
|
+
|
|
126
|
+
validate_arguments(
|
|
127
|
+
task_type=task_obj.type,
|
|
128
|
+
schema=schema,
|
|
129
|
+
executable_kind=kind,
|
|
130
|
+
)
|
|
131
|
+
|
|
118
132
|
logging.info(f"[{executable}] END (new schema)")
|
|
119
133
|
task_dict[f"args_schema_{kind}"] = schema
|
|
120
134
|
|
|
@@ -17,7 +17,7 @@ def deepdiff(
|
|
|
17
17
|
if type(old_object) is not type(new_object):
|
|
18
18
|
raise ValueError(
|
|
19
19
|
f"[{path}] Type difference:\n"
|
|
20
|
-
f"\tOld: {type(old_object)}\n\tNew:{type(new_object)}"
|
|
20
|
+
f"\tOld: {type(old_object)}\n\tNew: {type(new_object)}"
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
if type(old_object) not in [list, dict, str, int, float, bool, type(None)]:
|
|
@@ -64,5 +64,5 @@ def deepdiff(
|
|
|
64
64
|
if old_object != new_object:
|
|
65
65
|
raise ValueError(
|
|
66
66
|
f"{path} Values are different:\n"
|
|
67
|
-
f"\tOld: '{old_object}'\n\tNew:'{new_object}'"
|
|
67
|
+
f"\tOld: '{old_object}'\n\tNew: '{new_object}'"
|
|
68
68
|
)
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_descriptions.py
RENAMED
|
@@ -122,24 +122,18 @@ def _get_function_args_descriptions(
|
|
|
122
122
|
return descriptions
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
def
|
|
126
|
-
|
|
125
|
+
def _get_class_attrs_descriptions_from_file(
|
|
126
|
+
*,
|
|
127
|
+
module_path: Path,
|
|
128
|
+
class_name: str,
|
|
127
129
|
) -> dict[str, str]:
|
|
128
130
|
"""
|
|
129
|
-
Extract attribute descriptions from a
|
|
131
|
+
Extract class-attribute descriptions from a Python script
|
|
130
132
|
|
|
131
133
|
Args:
|
|
132
|
-
|
|
133
|
-
module_relative_path: Example `lib_channels.py`.
|
|
134
|
+
module_path: Example `/something/my_class.py`.
|
|
134
135
|
class_name: Example `OmeroChannel`.
|
|
135
136
|
"""
|
|
136
|
-
|
|
137
|
-
if not module_relative_path.endswith(".py"):
|
|
138
|
-
raise ValueError(f"Module {module_relative_path} must end with '.py'")
|
|
139
|
-
|
|
140
|
-
# Get the class ast.ClassDef object
|
|
141
|
-
package_path = Path(import_module(package_name).__file__).parent
|
|
142
|
-
module_path = package_path / module_relative_path
|
|
143
137
|
tree = ast.parse(module_path.read_text())
|
|
144
138
|
try:
|
|
145
139
|
_class = next(
|
|
@@ -148,10 +142,7 @@ def _get_class_attrs_descriptions(
|
|
|
148
142
|
if (isinstance(c, ast.ClassDef) and c.name == class_name)
|
|
149
143
|
)
|
|
150
144
|
except StopIteration:
|
|
151
|
-
raise RuntimeError(
|
|
152
|
-
f"Cannot find {class_name=} for {package_name=} "
|
|
153
|
-
f"and {module_relative_path=}"
|
|
154
|
-
)
|
|
145
|
+
raise RuntimeError(f"Cannot find {class_name=} in {module_path}.")
|
|
155
146
|
docstring = ast.get_docstring(_class)
|
|
156
147
|
parsed_docstring = docparse(docstring)
|
|
157
148
|
descriptions = {
|
|
@@ -160,6 +151,31 @@ def _get_class_attrs_descriptions(
|
|
|
160
151
|
else "Missing description"
|
|
161
152
|
for x in parsed_docstring.params
|
|
162
153
|
}
|
|
154
|
+
return descriptions
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _get_class_attrs_descriptions(
|
|
158
|
+
package_name: str, module_relative_path: str, class_name: str
|
|
159
|
+
) -> dict[str, str]:
|
|
160
|
+
"""
|
|
161
|
+
Extract class-attribute descriptions from an imported module
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
package_name: Example `fractal_tasks_core`.
|
|
165
|
+
module_relative_path: Example `lib_channels.py`.
|
|
166
|
+
class_name: Example `OmeroChannel`.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
if not module_relative_path.endswith(".py"):
|
|
170
|
+
raise ValueError(f"Module {module_relative_path} must end with '.py'")
|
|
171
|
+
|
|
172
|
+
# Get the class ast.ClassDef object
|
|
173
|
+
package_path = Path(import_module(package_name).__file__).parent
|
|
174
|
+
module_path = package_path / module_relative_path
|
|
175
|
+
descriptions = _get_class_attrs_descriptions_from_file(
|
|
176
|
+
module_path=module_path,
|
|
177
|
+
class_name=class_name,
|
|
178
|
+
)
|
|
163
179
|
logging.info(f"[_get_class_attrs_descriptions] END ({class_name=})")
|
|
164
180
|
return descriptions
|
|
165
181
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
REQUIRED_ARGUMENTS: dict[tuple[str, str], set[str]] = {
|
|
7
|
+
("non_parallel", "non_parallel"): {"zarr_urls", "zarr_dir"},
|
|
8
|
+
("compound", "non_parallel"): {"zarr_urls", "zarr_dir"},
|
|
9
|
+
("parallel", "parallel"): {"zarr_url"},
|
|
10
|
+
("compound", "parallel"): {"zarr_url", "init_args"},
|
|
11
|
+
("converter_non_parallel", "non_parallel"): {"zarr_dir"},
|
|
12
|
+
("converter_compound", "non_parallel"): {"zarr_dir"},
|
|
13
|
+
("converter_compound", "parallel"): {"zarr_url", "init_args"},
|
|
14
|
+
}
|
|
15
|
+
FORBIDDEN_ARGUMENTS: dict[tuple[str, str], set[str]] = {
|
|
16
|
+
("non_parallel", "non_parallel"): {"zarr_url"},
|
|
17
|
+
("compound", "non_parallel"): {"zarr_url"},
|
|
18
|
+
("parallel", "parallel"): {"zarr_urls", "zarr_dir"},
|
|
19
|
+
("compound", "parallel"): {"zarr_urls", "zarr_dir"},
|
|
20
|
+
("converter_non_parallel", "non_parallel"): {"zarr_url", "zarr_urls"},
|
|
21
|
+
("converter_compound", "non_parallel"): {"zarr_url", "zarr_urls"},
|
|
22
|
+
("converter_compound", "parallel"): {"zarr_urls", "zarr_dir"},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def validate_arguments(
|
|
27
|
+
*,
|
|
28
|
+
task_type: Literal["parallel", "non_parallel", "compound"],
|
|
29
|
+
executable_kind: Literal["parallel", "non_parallel"],
|
|
30
|
+
schema: dict[str, Any],
|
|
31
|
+
) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Validate schema arguments against required/forbidden ones.
|
|
34
|
+
|
|
35
|
+
Arguments:
|
|
36
|
+
task_type:
|
|
37
|
+
executable_kind: The `parallel`/`non_parallel` part of the task.
|
|
38
|
+
schema:
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
key = (task_type, executable_kind)
|
|
42
|
+
if not (key in REQUIRED_ARGUMENTS and key in FORBIDDEN_ARGUMENTS):
|
|
43
|
+
logging.error(f"Invalid {task_type=}, {executable_kind=}.")
|
|
44
|
+
raise ValueError(f"Invalid {task_type=}, {executable_kind=}.")
|
|
45
|
+
|
|
46
|
+
required_args = REQUIRED_ARGUMENTS[key]
|
|
47
|
+
forbidden_args = FORBIDDEN_ARGUMENTS[key]
|
|
48
|
+
|
|
49
|
+
schema_properties = set(schema["properties"].keys())
|
|
50
|
+
|
|
51
|
+
logging.info(
|
|
52
|
+
f"[validate_arguments] Task has arguments: {schema_properties}"
|
|
53
|
+
)
|
|
54
|
+
logging.info(f"[validate_arguments] Required arguments: {required_args}")
|
|
55
|
+
logging.info(f"[validate_arguments] Forbidden arguments: {forbidden_args}")
|
|
56
|
+
|
|
57
|
+
missing_required_arguments = {
|
|
58
|
+
arg for arg in required_args if arg not in schema_properties
|
|
59
|
+
}
|
|
60
|
+
if missing_required_arguments:
|
|
61
|
+
error_msg = (
|
|
62
|
+
"[validate_arguments] Required arguments "
|
|
63
|
+
f"{missing_required_arguments} are missing."
|
|
64
|
+
)
|
|
65
|
+
logging.error(error_msg)
|
|
66
|
+
raise ValueError(error_msg)
|
|
67
|
+
|
|
68
|
+
present_forbidden_args = forbidden_args.intersection(schema_properties)
|
|
69
|
+
if present_forbidden_args:
|
|
70
|
+
error_msg = (
|
|
71
|
+
"[validate_arguments] Forbidden arguments "
|
|
72
|
+
f"{present_forbidden_args} are present."
|
|
73
|
+
)
|
|
74
|
+
logging.error(error_msg)
|
|
75
|
+
raise ValueError(error_msg)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from typing import Any
|
|
2
|
+
from typing import Literal
|
|
2
3
|
from typing import Optional
|
|
3
4
|
|
|
4
5
|
from pydantic import BaseModel
|
|
@@ -18,6 +19,23 @@ class _BaseTask(BaseModel):
|
|
|
18
19
|
modality: Optional[str] = None
|
|
19
20
|
tags: list[str] = Field(default_factory=list)
|
|
20
21
|
docs_info: Optional[str] = None
|
|
22
|
+
type: str
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def executable_non_parallel(self) -> str:
|
|
26
|
+
raise NotImplementedError()
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def meta_non_parallel(self) -> Optional[dict[str, Any]]:
|
|
30
|
+
raise NotImplementedError()
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def executable_parallel(self) -> str:
|
|
34
|
+
raise NotImplementedError()
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def meta_parallel(self) -> Optional[dict[str, Any]]:
|
|
38
|
+
raise NotImplementedError()
|
|
21
39
|
|
|
22
40
|
|
|
23
41
|
class CompoundTask(_BaseTask):
|
|
@@ -29,6 +47,34 @@ class CompoundTask(_BaseTask):
|
|
|
29
47
|
|
|
30
48
|
executable_init: str
|
|
31
49
|
meta_init: Optional[dict[str, Any]] = None
|
|
50
|
+
type: Literal["compound"] = "compound"
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def executable_non_parallel(self) -> str:
|
|
54
|
+
return self.executable_init
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def meta_non_parallel(self) -> Optional[dict[str, Any]]:
|
|
58
|
+
return self.meta_init
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def executable_parallel(self) -> str:
|
|
62
|
+
return self.executable
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def meta_parallel(self) -> Optional[dict[str, Any]]:
|
|
66
|
+
return self.meta
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ConverterCompoundTask(_BaseTask):
|
|
70
|
+
"""
|
|
71
|
+
A `ConverterCompoundTask` task is the same as a `CompoundTask`, but it
|
|
72
|
+
is executed differently in the Fractal backend.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
executable_init: str
|
|
76
|
+
meta_init: Optional[dict[str, Any]] = None
|
|
77
|
+
type: Literal["converter_compound"] = "converter_compound"
|
|
32
78
|
|
|
33
79
|
@property
|
|
34
80
|
def executable_non_parallel(self) -> str:
|
|
@@ -53,6 +99,33 @@ class NonParallelTask(_BaseTask):
|
|
|
53
99
|
may include the `meta` attribute.
|
|
54
100
|
"""
|
|
55
101
|
|
|
102
|
+
type: Literal["non_parallel"] = "non_parallel"
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def executable_non_parallel(self) -> str:
|
|
106
|
+
return self.executable
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def meta_non_parallel(self) -> Optional[dict[str, Any]]:
|
|
110
|
+
return self.meta
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def executable_parallel(self) -> None:
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def meta_parallel(self) -> None:
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class ConverterNonParallelTask(_BaseTask):
|
|
122
|
+
"""
|
|
123
|
+
A `ConverterNonParallelTask` task is the same as a `NonParallelTask`, but
|
|
124
|
+
it is executed differently in the Fractal backend.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
type: Literal["converter_non_parallel"] = "converter_non_parallel"
|
|
128
|
+
|
|
56
129
|
@property
|
|
57
130
|
def executable_non_parallel(self) -> str:
|
|
58
131
|
return self.executable
|
|
@@ -76,6 +149,8 @@ class ParallelTask(_BaseTask):
|
|
|
76
149
|
include the `meta` attribute.
|
|
77
150
|
"""
|
|
78
151
|
|
|
152
|
+
type: Literal["parallel"] = "parallel"
|
|
153
|
+
|
|
79
154
|
@property
|
|
80
155
|
def executable_non_parallel(self) -> None:
|
|
81
156
|
return None
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9/src/fractal_task_tools.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fractal-task-tools
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: Shared tools for Fractal tasks
|
|
5
5
|
Author-email: Tommaso Comparin <tommaso.comparin@exact-lab.it>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -17,6 +17,14 @@ Requires-Dist: bumpver==2024.1130; extra == "dev"
|
|
|
17
17
|
Requires-Dist: devtools==0.12.2; extra == "dev"
|
|
18
18
|
Requires-Dist: pytest<9.0.0,>=8.3.0; extra == "dev"
|
|
19
19
|
Requires-Dist: coverage<7.7.0,>=7.6.0; extra == "dev"
|
|
20
|
+
Requires-Dist: mkdocs==1.5.2; extra == "dev"
|
|
21
|
+
Requires-Dist: mkdocs-material==9.1.21; extra == "dev"
|
|
22
|
+
Requires-Dist: mkdocs-literate-nav==0.5.0; extra == "dev"
|
|
23
|
+
Requires-Dist: mkdocs-gen-files==0.4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: mkdocs-section-index==0.3.5; extra == "dev"
|
|
25
|
+
Requires-Dist: mkdocstrings[python]==0.25.2; extra == "dev"
|
|
26
|
+
Requires-Dist: mkdocs-include-markdown-plugin<6.0.0,>=5.0.0; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
20
28
|
|
|
21
29
|
# Fractal task tools
|
|
22
30
|
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/SOURCES.txt
RENAMED
|
@@ -11,6 +11,7 @@ src/fractal_task_tools/_descriptions.py
|
|
|
11
11
|
src/fractal_task_tools/_package_name_tools.py
|
|
12
12
|
src/fractal_task_tools/_pydantic_generatejsonschema.py
|
|
13
13
|
src/fractal_task_tools/_signature_constraints.py
|
|
14
|
+
src/fractal_task_tools/_task_arguments.py
|
|
14
15
|
src/fractal_task_tools/_task_docs.py
|
|
15
16
|
src/fractal_task_tools/_titles.py
|
|
16
17
|
src/fractal_task_tools/task_models.py
|
|
@@ -29,4 +30,5 @@ tests/test_extract_function.py
|
|
|
29
30
|
tests/test_normalize_package_name.py
|
|
30
31
|
tests/test_task_models.py
|
|
31
32
|
tests/test_task_wrapper.py
|
|
32
|
-
tests/test_unit_lib_descriptions.py
|
|
33
|
+
tests/test_unit_lib_descriptions.py
|
|
34
|
+
tests/test_validate_arguments.py
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
pydantic<=2.8.2,>=2.0.0
|
|
2
|
+
docstring-parser==0.15
|
|
3
|
+
|
|
4
|
+
[dev]
|
|
5
|
+
bumpver==2024.1130
|
|
6
|
+
devtools==0.12.2
|
|
7
|
+
pytest<9.0.0,>=8.3.0
|
|
8
|
+
coverage<7.7.0,>=7.6.0
|
|
9
|
+
mkdocs==1.5.2
|
|
10
|
+
mkdocs-material==9.1.21
|
|
11
|
+
mkdocs-literate-nav==0.5.0
|
|
12
|
+
mkdocs-gen-files==0.4.0
|
|
13
|
+
mkdocs-section-index==0.3.5
|
|
14
|
+
mkdocstrings[python]==0.25.2
|
|
15
|
+
mkdocs-include-markdown-plugin<6.0.0,>=5.0.0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from devtools import debug
|
|
8
|
+
from fractal_task_tools._cli import check_manifest
|
|
9
|
+
from fractal_task_tools._cli import write_manifest_to_file
|
|
10
|
+
from fractal_task_tools._create_manifest import create_manifest
|
|
11
|
+
from fractal_task_tools._create_manifest import MANIFEST_FILENAME
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_create_manifest(tmp_path: Path, caplog):
|
|
15
|
+
subprocess.check_call(
|
|
16
|
+
[
|
|
17
|
+
sys.executable,
|
|
18
|
+
"-m",
|
|
19
|
+
"pip",
|
|
20
|
+
"install",
|
|
21
|
+
"./tests/fake-tasks",
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
import fake_tasks
|
|
26
|
+
|
|
27
|
+
manifest = create_manifest(
|
|
28
|
+
raw_package_name="fake-tasks",
|
|
29
|
+
task_list_path="task_list",
|
|
30
|
+
)
|
|
31
|
+
debug(manifest)
|
|
32
|
+
write_manifest_to_file(
|
|
33
|
+
raw_package_name="fake-tasks",
|
|
34
|
+
manifest=manifest,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
check_manifest(
|
|
38
|
+
raw_package_name="fake-tasks",
|
|
39
|
+
manifest=manifest,
|
|
40
|
+
ignore_keys_order=False,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
MANIFEST_PATH = Path(fake_tasks.__file__).parent / MANIFEST_FILENAME
|
|
44
|
+
with MANIFEST_PATH.open("w") as f:
|
|
45
|
+
json.dump(dict(fake="manifest"), f)
|
|
46
|
+
|
|
47
|
+
caplog.clear()
|
|
48
|
+
with pytest.raises(SystemExit):
|
|
49
|
+
check_manifest(
|
|
50
|
+
raw_package_name="fake-tasks",
|
|
51
|
+
manifest=manifest,
|
|
52
|
+
ignore_keys_order=False,
|
|
53
|
+
)
|
|
54
|
+
assert "On-disk manifest is not up to date." in caplog.text
|
|
55
|
+
|
|
56
|
+
# Clean up
|
|
57
|
+
MANIFEST_PATH.unlink()
|
|
58
|
+
|
|
59
|
+
subprocess.check_call(
|
|
60
|
+
[
|
|
61
|
+
sys.executable,
|
|
62
|
+
"-m",
|
|
63
|
+
"pip",
|
|
64
|
+
"uninstall",
|
|
65
|
+
"fake-tasks",
|
|
66
|
+
"--yes",
|
|
67
|
+
]
|
|
68
|
+
)
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/tests/test_create_schema_for_single_task.py
RENAMED
|
@@ -131,7 +131,36 @@ def test_enum_argument():
|
|
|
131
131
|
verbose=True,
|
|
132
132
|
)
|
|
133
133
|
debug(schema)
|
|
134
|
-
|
|
134
|
+
assert schema["$defs"]["ColorA"] == {
|
|
135
|
+
"enum": [
|
|
136
|
+
"this-is-red",
|
|
137
|
+
"this-is-green",
|
|
138
|
+
],
|
|
139
|
+
"title": "ColorA",
|
|
140
|
+
"type": "string",
|
|
141
|
+
"description": "Missing description for ColorA.",
|
|
142
|
+
}
|
|
143
|
+
assert schema["$defs"]["ColorB"] == {
|
|
144
|
+
"enum": [
|
|
145
|
+
"this-is-red",
|
|
146
|
+
"this-is-green",
|
|
147
|
+
],
|
|
148
|
+
"title": "ColorB",
|
|
149
|
+
"type": "string",
|
|
150
|
+
"description": "Missing description for ColorB.",
|
|
151
|
+
}
|
|
152
|
+
assert schema["properties"] == {
|
|
153
|
+
"arg_A": {
|
|
154
|
+
"$ref": "#/$defs/ColorA",
|
|
155
|
+
"title": "Arg A",
|
|
156
|
+
"description": "Description of arg_A.",
|
|
157
|
+
},
|
|
158
|
+
"arg_B": {
|
|
159
|
+
"$ref": "#/$defs/ColorB",
|
|
160
|
+
"title": "Arg B",
|
|
161
|
+
"description": "Description of arg_B.",
|
|
162
|
+
},
|
|
163
|
+
}
|
|
135
164
|
|
|
136
165
|
|
|
137
166
|
@validate_call
|
|
@@ -199,4 +228,21 @@ def test_tuple_argument():
|
|
|
199
228
|
verbose=True,
|
|
200
229
|
)
|
|
201
230
|
debug(schema)
|
|
202
|
-
|
|
231
|
+
assert schema["properties"] == {
|
|
232
|
+
"arg_A": {
|
|
233
|
+
"default": [1, 1],
|
|
234
|
+
"maxItems": 2,
|
|
235
|
+
"minItems": 2,
|
|
236
|
+
"prefixItems": [
|
|
237
|
+
{
|
|
238
|
+
"type": "integer",
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"type": "integer",
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
"title": "Arg A",
|
|
245
|
+
"type": "array",
|
|
246
|
+
"description": "Description of arg_A.",
|
|
247
|
+
},
|
|
248
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
from fractal_task_tools.task_models import CompoundTask
|
|
2
|
+
from fractal_task_tools.task_models import ConverterCompoundTask
|
|
3
|
+
from fractal_task_tools.task_models import ConverterNonParallelTask
|
|
2
4
|
from fractal_task_tools.task_models import NonParallelTask
|
|
3
5
|
from fractal_task_tools.task_models import ParallelTask
|
|
4
6
|
|
|
@@ -22,6 +24,18 @@ def test_compound_task_model():
|
|
|
22
24
|
assert t.executable_parallel == EXECUTABLE
|
|
23
25
|
assert t.meta_parallel == META
|
|
24
26
|
|
|
27
|
+
t = ConverterCompoundTask(
|
|
28
|
+
name=NAME,
|
|
29
|
+
executable_init=EXECUTABLE_INIT,
|
|
30
|
+
meta_init=META_INIT,
|
|
31
|
+
executable=EXECUTABLE,
|
|
32
|
+
meta=META,
|
|
33
|
+
)
|
|
34
|
+
assert t.executable_non_parallel == EXECUTABLE_INIT
|
|
35
|
+
assert t.meta_non_parallel == META_INIT
|
|
36
|
+
assert t.executable_parallel == EXECUTABLE
|
|
37
|
+
assert t.meta_parallel == META
|
|
38
|
+
|
|
25
39
|
|
|
26
40
|
def test_non_parallel_task_model():
|
|
27
41
|
t = NonParallelTask(
|
|
@@ -34,6 +48,16 @@ def test_non_parallel_task_model():
|
|
|
34
48
|
assert t.executable_parallel is None
|
|
35
49
|
assert t.meta_parallel is None
|
|
36
50
|
|
|
51
|
+
t = ConverterNonParallelTask(
|
|
52
|
+
name=NAME,
|
|
53
|
+
executable=EXECUTABLE_INIT,
|
|
54
|
+
meta=META_INIT,
|
|
55
|
+
)
|
|
56
|
+
assert t.executable_non_parallel == EXECUTABLE_INIT
|
|
57
|
+
assert t.meta_non_parallel == META_INIT
|
|
58
|
+
assert t.executable_parallel is None
|
|
59
|
+
assert t.meta_parallel is None
|
|
60
|
+
|
|
37
61
|
|
|
38
62
|
def test_parallel_task_model():
|
|
39
63
|
t = ParallelTask(
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from devtools import debug
|
|
5
|
+
from fractal_task_tools._descriptions import _get_class_attrs_descriptions
|
|
6
|
+
from fractal_task_tools._descriptions import (
|
|
7
|
+
_get_class_attrs_descriptions_from_file,
|
|
8
|
+
)
|
|
9
|
+
from fractal_task_tools._descriptions import _get_function_args_descriptions
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MyClass(BaseModel):
|
|
14
|
+
"""
|
|
15
|
+
Init Args for MIP task.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
arg1: Description of `arg1`.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
arg1: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_get_function_args_descriptions():
|
|
25
|
+
args_descriptions = _get_function_args_descriptions(
|
|
26
|
+
package_name="fractal_task_tools",
|
|
27
|
+
module_path="_signature_constraints.py",
|
|
28
|
+
function_name="_extract_function",
|
|
29
|
+
)
|
|
30
|
+
debug(args_descriptions)
|
|
31
|
+
assert args_descriptions.keys() == set(
|
|
32
|
+
("package_name", "module_relative_path", "function_name", "verbose")
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_get_class_attrs_descriptions_from_file():
|
|
37
|
+
attrs_descriptions = _get_class_attrs_descriptions_from_file(
|
|
38
|
+
module_path=Path(__file__),
|
|
39
|
+
class_name="MyClass",
|
|
40
|
+
)
|
|
41
|
+
debug(attrs_descriptions)
|
|
42
|
+
assert attrs_descriptions == {"arg1": "Description of `arg1`."}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_failures():
|
|
46
|
+
with pytest.raises(ValueError, match="must end with '.py'"):
|
|
47
|
+
_get_class_attrs_descriptions(
|
|
48
|
+
package_name="fractal_task_tools",
|
|
49
|
+
module_relative_path="task_models",
|
|
50
|
+
class_name="MyClass",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
with pytest.raises(RuntimeError, match="Cannot find class_name"):
|
|
54
|
+
_get_class_attrs_descriptions(
|
|
55
|
+
package_name="fractal_task_tools",
|
|
56
|
+
module_relative_path="task_models.py",
|
|
57
|
+
class_name="MyClass",
|
|
58
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from fractal_task_tools._task_arguments import validate_arguments
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _fake_schema(*args: list[str]):
|
|
6
|
+
return dict(properties={key: None for key in args})
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_validate_arguments():
|
|
10
|
+
with pytest.raises(ValueError, match="Invalid task_type="):
|
|
11
|
+
validate_arguments(
|
|
12
|
+
task_type="invalid",
|
|
13
|
+
executable_kind="non_parallel",
|
|
14
|
+
schema={},
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
with pytest.raises(ValueError, match="Invalid task_type="):
|
|
18
|
+
validate_arguments(
|
|
19
|
+
task_type="compound",
|
|
20
|
+
executable_kind="invalid",
|
|
21
|
+
schema={},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
with pytest.raises(ValueError, match="Required arguments"):
|
|
25
|
+
validate_arguments(
|
|
26
|
+
task_type="non_parallel",
|
|
27
|
+
executable_kind="non_parallel",
|
|
28
|
+
schema=_fake_schema("zarr_dir", "arg1"),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
with pytest.raises(ValueError, match="Forbidden arguments"):
|
|
32
|
+
validate_arguments(
|
|
33
|
+
task_type="non_parallel",
|
|
34
|
+
executable_kind="non_parallel",
|
|
35
|
+
schema=_fake_schema("zarr_urls", "zarr_dir", "zarr_url", "arg1"),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
validate_arguments(
|
|
39
|
+
task_type="non_parallel",
|
|
40
|
+
executable_kind="non_parallel",
|
|
41
|
+
schema=_fake_schema("zarr_urls", "zarr_dir", "arg1"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
validate_arguments(
|
|
45
|
+
task_type="compound",
|
|
46
|
+
executable_kind="non_parallel",
|
|
47
|
+
schema=_fake_schema("zarr_urls", "zarr_dir", "arg1"),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
validate_arguments(
|
|
51
|
+
task_type="compound",
|
|
52
|
+
executable_kind="parallel",
|
|
53
|
+
schema=_fake_schema("zarr_url", "init_args", "arg1"),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
validate_arguments(
|
|
57
|
+
task_type="parallel",
|
|
58
|
+
executable_kind="parallel",
|
|
59
|
+
schema=_fake_schema("zarr_url", "arg1"),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
with pytest.raises(ValueError, match="Forbidden arguments"):
|
|
63
|
+
validate_arguments(
|
|
64
|
+
task_type="converter_non_parallel",
|
|
65
|
+
executable_kind="non_parallel",
|
|
66
|
+
schema=_fake_schema("zarr_urls", "zarr_dir", "arg1"),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
validate_arguments(
|
|
70
|
+
task_type="converter_non_parallel",
|
|
71
|
+
executable_kind="non_parallel",
|
|
72
|
+
schema=_fake_schema("zarr_dir", "arg1"),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
validate_arguments(
|
|
76
|
+
task_type="converter_compound",
|
|
77
|
+
executable_kind="non_parallel",
|
|
78
|
+
schema=_fake_schema("zarr_dir", "arg1"),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
validate_arguments(
|
|
82
|
+
task_type="converter_compound",
|
|
83
|
+
executable_kind="parallel",
|
|
84
|
+
schema=_fake_schema("zarr_url", "init_args", "arg1"),
|
|
85
|
+
)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
from fractal_task_tools._create_manifest import create_manifest
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_create_manifest():
|
|
8
|
-
subprocess.check_call(
|
|
9
|
-
[
|
|
10
|
-
sys.executable,
|
|
11
|
-
"-m",
|
|
12
|
-
"pip",
|
|
13
|
-
"install",
|
|
14
|
-
"./tests/fake-tasks",
|
|
15
|
-
]
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
create_manifest(
|
|
19
|
-
raw_package_name="fake-tasks",
|
|
20
|
-
task_list_path="task_list",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
subprocess.check_call(
|
|
24
|
-
[
|
|
25
|
-
sys.executable,
|
|
26
|
-
"-m",
|
|
27
|
-
"pip",
|
|
28
|
-
"uninstall",
|
|
29
|
-
"fake-tasks",
|
|
30
|
-
"--yes",
|
|
31
|
-
]
|
|
32
|
-
)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
from devtools import debug
|
|
3
|
-
from fractal_task_tools._descriptions import _get_class_attrs_descriptions
|
|
4
|
-
from fractal_task_tools._descriptions import _get_function_args_descriptions
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@pytest.mark.xfail(reason="FIXME: depends on fractal-tasks-core")
|
|
8
|
-
def test_get_function_args_descriptions():
|
|
9
|
-
args_descriptions = _get_function_args_descriptions(
|
|
10
|
-
package_name="fractal_tasks_core",
|
|
11
|
-
module_path="dev/lib_signature_constraints.py",
|
|
12
|
-
function_name="_extract_function",
|
|
13
|
-
)
|
|
14
|
-
debug(args_descriptions)
|
|
15
|
-
assert args_descriptions.keys() == set(
|
|
16
|
-
("package_name", "module_relative_path", "function_name", "verbose")
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@pytest.mark.xfail(reason="FIXME: depends on fractal-tasks-core")
|
|
21
|
-
def test_get_class_attrs_descriptions():
|
|
22
|
-
attrs_descriptions = _get_class_attrs_descriptions(
|
|
23
|
-
package_name="fractal_tasks_core",
|
|
24
|
-
module_relative_path="channels.py",
|
|
25
|
-
class_name="ChannelInputModel",
|
|
26
|
-
)
|
|
27
|
-
debug(attrs_descriptions)
|
|
28
|
-
assert attrs_descriptions.keys() == set(("wavelength_id", "label"))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/_args_schemas.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools/task_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fractal_task_tools-0.0.8 → fractal_task_tools-0.0.9}/src/fractal_task_tools.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|