fractal-task-tools 0.0.3__tar.gz → 0.0.5__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.

Files changed (29) hide show
  1. {fractal_task_tools-0.0.3/src/fractal_task_tools.egg-info → fractal_task_tools-0.0.5}/PKG-INFO +1 -1
  2. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/pyproject.toml +2 -2
  3. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/__init__.py +1 -1
  4. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/task_models.py +2 -3
  5. fractal_task_tools-0.0.5/src/fractal_task_tools/task_wrapper.py +71 -0
  6. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5/src/fractal_task_tools.egg-info}/PKG-INFO +1 -1
  7. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools.egg-info/SOURCES.txt +4 -0
  8. fractal_task_tools-0.0.5/tests/test_normalize_package_name.py +7 -0
  9. fractal_task_tools-0.0.5/tests/test_task_models.py +47 -0
  10. fractal_task_tools-0.0.5/tests/test_task_wrapper.py +88 -0
  11. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/LICENSE +0 -0
  12. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/README.md +0 -0
  13. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/setup.cfg +0 -0
  14. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_args_schemas.py +0 -0
  15. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_cli.py +0 -0
  16. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_create_manifest.py +0 -0
  17. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_descriptions.py +0 -0
  18. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_package_name_tools.py +0 -0
  19. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_pydantic_generatejsonschema.py +0 -0
  20. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_signature_constraints.py +0 -0
  21. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_task_docs.py +0 -0
  22. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools/_titles.py +0 -0
  23. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools.egg-info/dependency_links.txt +0 -0
  24. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools.egg-info/entry_points.txt +0 -0
  25. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools.egg-info/requires.txt +0 -0
  26. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/src/fractal_task_tools.egg-info/top_level.txt +0 -0
  27. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/tests/test_create_schema_for_single_task.py +0 -0
  28. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/tests/test_extract_function.py +0 -0
  29. {fractal_task_tools-0.0.3 → fractal_task_tools-0.0.5}/tests/test_unit_lib_descriptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fractal-task-tools
3
- Version: 0.0.3
3
+ Version: 0.0.5
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fractal-task-tools"
3
- version = "0.0.3"
3
+ version = "0.0.5"
4
4
  description = "Shared tools for Fractal tasks"
5
5
  authors = [
6
6
  {name="Tommaso Comparin", email="tommaso.comparin@exact-lab.it"},
@@ -34,7 +34,7 @@ build-backend = "setuptools.build_meta"
34
34
  fractal-manifest = "fractal_task_tools._cli:main"
35
35
 
36
36
  [tool.bumpver]
37
- current_version = "0.0.3"
37
+ current_version = "0.0.5"
38
38
  version_pattern = "MAJOR.MINOR.PATCH[PYTAGNUM]"
39
39
  commit_message = "bump version {old_version} -> {new_version}"
40
40
  commit = true
@@ -2,4 +2,4 @@ import logging
2
2
 
3
3
  logging.basicConfig(level=logging.INFO)
4
4
 
5
- __VERSION__ = "0.0.3"
5
+ __VERSION__ = "0.0.5"
@@ -2,13 +2,12 @@ from typing import Any
2
2
  from typing import Optional
3
3
 
4
4
  from pydantic import BaseModel
5
+ from pydantic import ConfigDict
5
6
  from pydantic import Field
6
7
 
7
8
 
8
9
  class _BaseTask(BaseModel):
9
- class Config:
10
- arbitrary_types_allowed = True
11
- extra = "forbid"
10
+ model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
12
11
 
13
12
  name: str
14
13
  executable: str
@@ -0,0 +1,71 @@
1
+ """
2
+ Standard input/output interface for tasks.
3
+ """
4
+ import json
5
+ import logging
6
+ from argparse import ArgumentParser
7
+ from json import JSONEncoder
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+
12
+ class TaskParameterEncoder(JSONEncoder):
13
+ """
14
+ Custom JSONEncoder that transforms Path objects to strings.
15
+
16
+ Ref https://docs.python.org/3/library/json.html
17
+ """
18
+
19
+ def default(self, obj):
20
+ if isinstance(obj, Path):
21
+ return obj.as_posix()
22
+ return super().default(obj)
23
+
24
+
25
+ def run_fractal_task(
26
+ *,
27
+ task_function: callable,
28
+ logger_name: Optional[str] = None,
29
+ ):
30
+ """
31
+ Implement standard task interface and call task_function.
32
+
33
+ Args:
34
+ task_function: the callable function that runs the task.
35
+ logger_name: TBD
36
+ """
37
+
38
+ # Parse `-j` and `--metadata-out` arguments
39
+ parser = ArgumentParser()
40
+ parser.add_argument(
41
+ "--args-json", help="Read parameters from json file", required=True
42
+ )
43
+ parser.add_argument(
44
+ "--out-json",
45
+ help="Output file to redirect serialised returned data",
46
+ required=True,
47
+ )
48
+ parsed_args = parser.parse_args()
49
+
50
+ # Set logger
51
+ logger = logging.getLogger(logger_name)
52
+
53
+ # Preliminary check
54
+ if Path(parsed_args.out_json).exists():
55
+ logger.error(
56
+ f"Output file {parsed_args.out_json} already exists. Terminating"
57
+ )
58
+ exit(1)
59
+
60
+ # Read parameters dictionary
61
+ with open(parsed_args.args_json, "r") as f:
62
+ pars = json.load(f)
63
+
64
+ # Run task
65
+ logger.info(f"START {task_function.__name__} task")
66
+ metadata_update = task_function(**pars)
67
+ logger.info(f"END {task_function.__name__} task")
68
+
69
+ # Write output metadata to file, with custom JSON encoder
70
+ with open(parsed_args.out_json, "w") as fout:
71
+ json.dump(metadata_update, fout, cls=TaskParameterEncoder, indent=2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fractal-task-tools
3
- Version: 0.0.3
3
+ Version: 0.0.5
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
@@ -12,6 +12,7 @@ src/fractal_task_tools/_signature_constraints.py
12
12
  src/fractal_task_tools/_task_docs.py
13
13
  src/fractal_task_tools/_titles.py
14
14
  src/fractal_task_tools/task_models.py
15
+ src/fractal_task_tools/task_wrapper.py
15
16
  src/fractal_task_tools.egg-info/PKG-INFO
16
17
  src/fractal_task_tools.egg-info/SOURCES.txt
17
18
  src/fractal_task_tools.egg-info/dependency_links.txt
@@ -20,4 +21,7 @@ src/fractal_task_tools.egg-info/requires.txt
20
21
  src/fractal_task_tools.egg-info/top_level.txt
21
22
  tests/test_create_schema_for_single_task.py
22
23
  tests/test_extract_function.py
24
+ tests/test_normalize_package_name.py
25
+ tests/test_task_models.py
26
+ tests/test_task_wrapper.py
23
27
  tests/test_unit_lib_descriptions.py
@@ -0,0 +1,7 @@
1
+ from fractal_task_tools._package_name_tools import normalize_package_name
2
+
3
+
4
+ def test_normalize_package_name():
5
+ raw_name = "Aa-_.Aa"
6
+ normalized_name = "aa_aa"
7
+ assert normalize_package_name(raw_name) == normalized_name
@@ -0,0 +1,47 @@
1
+ from fractal_task_tools.task_models import CompoundTask
2
+ from fractal_task_tools.task_models import NonParallelTask
3
+ from fractal_task_tools.task_models import ParallelTask
4
+
5
+ NAME = "name"
6
+ EXECUTABLE = "executable"
7
+ EXECUTABLE_INIT = "executable_init"
8
+ META = {"some": "thing"}
9
+ META_INIT = {"some": "thing-init"}
10
+
11
+
12
+ def test_compound_task_model():
13
+ t = CompoundTask(
14
+ name=NAME,
15
+ executable_init=EXECUTABLE_INIT,
16
+ meta_init=META_INIT,
17
+ executable=EXECUTABLE,
18
+ meta=META,
19
+ )
20
+ assert t.executable_non_parallel == EXECUTABLE_INIT
21
+ assert t.meta_non_parallel == META_INIT
22
+ assert t.executable_parallel == EXECUTABLE
23
+ assert t.meta_parallel == META
24
+
25
+
26
+ def test_non_parallel_task_model():
27
+ t = NonParallelTask(
28
+ name=NAME,
29
+ executable=EXECUTABLE_INIT,
30
+ meta=META_INIT,
31
+ )
32
+ assert t.executable_non_parallel == EXECUTABLE_INIT
33
+ assert t.meta_non_parallel == META_INIT
34
+ assert t.executable_parallel is None
35
+ assert t.meta_parallel is None
36
+
37
+
38
+ def test_parallel_task_model():
39
+ t = ParallelTask(
40
+ name=NAME,
41
+ executable=EXECUTABLE,
42
+ meta=META,
43
+ )
44
+ assert t.executable_non_parallel is None
45
+ assert t.meta_non_parallel is None
46
+ assert t.executable_parallel == EXECUTABLE
47
+ assert t.meta_parallel == META
@@ -0,0 +1,88 @@
1
+ import json
2
+ from datetime import datetime
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+ from fractal_task_tools.task_wrapper import run_fractal_task
7
+ from pydantic import ValidationError
8
+ from pydantic.validate_call_decorator import validate_call
9
+
10
+ TASK_OUTPUT = {
11
+ "some": "thing",
12
+ "path": Path("/something"),
13
+ }
14
+
15
+ SERIALIZED_TASK_OUTPUT = {
16
+ "some": "thing",
17
+ "path": "/something",
18
+ }
19
+
20
+
21
+ @validate_call
22
+ def fake_task(zarr_url: str, parameter: float):
23
+ return TASK_OUTPUT
24
+
25
+
26
+ @validate_call
27
+ def fake_task_invalid_output(zarr_url: str, parameter: float):
28
+ return dict(non_json_serializable=datetime.now())
29
+
30
+
31
+ def test_run_fractal_task(tmp_path, monkeypatch, caplog):
32
+
33
+ ARGS_PATH = tmp_path / "args.json"
34
+ METADIFF_PATH = tmp_path / "metadiff.json"
35
+
36
+ # Mock argparse.ArgumentParser
37
+ class MockArgumentParser:
38
+ def add_argument(self, *args, **kwargs):
39
+ pass
40
+
41
+ def parse_args(self, *args, **kwargs):
42
+ class Args(object):
43
+ def __init__(self):
44
+ self.args_json = str(ARGS_PATH)
45
+ self.out_json = str(METADIFF_PATH)
46
+
47
+ return Args()
48
+
49
+ import fractal_task_tools.task_wrapper # noqa: F401
50
+
51
+ monkeypatch.setattr(
52
+ "fractal_task_tools.task_wrapper.ArgumentParser",
53
+ MockArgumentParser,
54
+ )
55
+
56
+ # Success
57
+ args = dict(zarr_url="/somewhere", parameter=1.0)
58
+ with ARGS_PATH.open("w") as f:
59
+ json.dump(args, f, indent=2)
60
+ function_output = run_fractal_task(task_function=fake_task)
61
+ assert function_output is None
62
+ with METADIFF_PATH.open("r") as f:
63
+ task_output = json.load(f)
64
+ assert task_output == SERIALIZED_TASK_OUTPUT
65
+
66
+ # Failure (metadiff file already exists)
67
+ caplog.clear()
68
+ with pytest.raises(SystemExit):
69
+ run_fractal_task(task_function=fake_task)
70
+ assert "already exists" in caplog.text
71
+
72
+ # Failure (invalid output)
73
+ METADIFF_PATH.unlink()
74
+ with pytest.raises(
75
+ TypeError,
76
+ match="datetime is not JSON serializable",
77
+ ):
78
+ run_fractal_task(task_function=fake_task_invalid_output)
79
+
80
+ # Failure (invalid input)
81
+ METADIFF_PATH.unlink()
82
+ args = dict(zarr_url="/somewhere", parameter=None)
83
+ with ARGS_PATH.open("w") as f:
84
+ json.dump(args, f, indent=2)
85
+ with pytest.raises(
86
+ ValidationError, match="validation error for fake_task"
87
+ ):
88
+ run_fractal_task(task_function=fake_task)