pipeline-component-system 0.0.1__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.
@@ -0,0 +1,5 @@
1
+ Copyright 2024 Daniel Cauchi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.1
2
+ Name: pipeline-component-system
3
+ Version: 0.0.1
4
+ Summary: A strange programming framework
5
+ Author-email: Daniel Cauchi <cowkeyman@gmail.com>
6
+ Project-URL: Homepage, https://github.com/CowKeyMan/PCS
7
+ Project-URL: Issues, https://github.com/CowKeyMan/PCS/issues
8
+ Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: License :: OSI Approved :: MIT No Attribution License (MIT-0)
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Natural Language :: English
13
+ Classifier: Intended Audience :: Developers
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+
18
+ # Pipeline Component System (PCS)
19
+
20
+
@@ -0,0 +1,3 @@
1
+ # Pipeline Component System (PCS)
2
+
3
+
File without changes
@@ -0,0 +1,82 @@
1
+ import yaml
2
+ import argparse
3
+
4
+
5
+ class Args(argparse.Namespace):
6
+ def __init__(self):
7
+ super().__init__()
8
+ self.args_files: str = ""
9
+ self.rest: list[str] = []
10
+
11
+
12
+ def parse_arguments(obj: object):
13
+ args = do_parse_arguments()
14
+ update_dict = get_update_dict_from_comma_separated_file_list(args.args_files)
15
+ update_dict_with_rest_arguments(update_dict, args.rest)
16
+ update_object(obj, update_dict)
17
+
18
+
19
+ def do_parse_arguments() -> Args:
20
+ parser = argparse.ArgumentParser()
21
+ _ = parser.add_argument(
22
+ "--args-files",
23
+ "-f",
24
+ required=False,
25
+ help=(
26
+ "A list of comma separated yaml files, where the keys in the "
27
+ "latest files will overwrite those in previous files"
28
+ ),
29
+ )
30
+ _ = parser.add_argument(
31
+ "--rest",
32
+ "-r",
33
+ nargs="+",
34
+ help=(
35
+ "Set a number of key-value pairs like <key>=<value>. "
36
+ "Values may have spaces if the whole value is wrapped"
37
+ 'in quotes such as <key>="this is a value". These arguments'
38
+ "take precedence over those that come from files"
39
+ ),
40
+ )
41
+ args = Args()
42
+ args = parser.parse_args(namespace=args)
43
+ return args
44
+
45
+
46
+ def get_update_dict_from_comma_separated_file_list(files: str) -> dict[str, object]:
47
+ return get_update_dict_from_files(files.split(","))
48
+
49
+
50
+ def get_update_dict_from_files(files: list[str]) -> dict[str, object]:
51
+ if len(files) == 1 and files[0] == "":
52
+ return {}
53
+ args: dict[str, object] = {}
54
+ for file in files:
55
+ with open(file, "r", encoding="utf-8") as f:
56
+ args |= yaml.safe_load(f)
57
+ return args
58
+
59
+
60
+ def update_dict_with_rest_arguments(update_dict: dict[str, object], rest: list[str]):
61
+ for r in rest:
62
+ key, value = r.split("=")
63
+ if value.isdigit():
64
+ value = int(value)
65
+ else:
66
+ try:
67
+ value = float(value)
68
+ except ValueError:
69
+ print("Not a float")
70
+ update_dict[key] = value
71
+
72
+
73
+ def update_object(obj: object, update_dict: dict[str, object]):
74
+ for key, value in update_dict.items():
75
+ assert hasattr(obj, key), f"obj has no attribute {key}"
76
+ target_type: type = obj.__annotations__[key]
77
+ assert isinstance(value, target_type), (
78
+ f"Key: {key} with value: {value} of type {type(value)} "
79
+ f"does not have the target type of {target_type}"
80
+ )
81
+ setattr(obj, key, value)
82
+
@@ -0,0 +1,6 @@
1
+ from typing import TypeVar
2
+
3
+ T = TypeVar('T')
4
+
5
+ def initialize_object_nones(Cls: type[T]) -> T:
6
+ return Cls(*([None] * len(Cls.__annotations__)))
@@ -0,0 +1,89 @@
1
+ import inspect
2
+ from collections.abc import Mapping
3
+ from typing import Callable, TypeAlias
4
+
5
+ System: TypeAlias = Callable[..., None | Mapping[str, object]]
6
+
7
+
8
+ class Pipeline:
9
+ def __init__(
10
+ self,
11
+ component: object,
12
+ systems: list[System],
13
+ do_null_checks: bool = True,
14
+ do_type_checks: bool = True,
15
+ ):
16
+ assert len(systems) > 0, "Systems in an empty list"
17
+ self.component: object = component
18
+ self.systems: list[System] = systems
19
+ self.do_null_checks: bool = do_null_checks
20
+ self.do_type_checks: bool = do_type_checks
21
+ self.current_system: System = systems[0]
22
+
23
+ def execute(self):
24
+ for system in self.systems:
25
+ self.current_system = system
26
+ self.check_for_nulls(system)
27
+ self.check_for_types(system)
28
+ result = system(
29
+ *[
30
+ getattr(self.component, param_name)
31
+ for param_name in inspect.signature(system).parameters
32
+ ]
33
+ )
34
+ self.set_component(result)
35
+
36
+ def check_for_nulls(self, system: System):
37
+ if not self.do_null_checks:
38
+ return
39
+ for parameter in inspect.signature(system).parameters:
40
+ assert (
41
+ getattr(self.component, parameter) is not None
42
+ ), f"System: {system.__name__} - Parameter {parameter} was None"
43
+
44
+ def check_for_types(self, system: System):
45
+ if not self.do_type_checks:
46
+ return
47
+ parameters = inspect.signature(system).parameters
48
+ for param in parameters:
49
+ self.assert_type_annotation(
50
+ self.component.__annotations__[param], # pyright: ignore[reportAny]
51
+ parameters[param].annotation, # pyright: ignore[reportAny]
52
+ f"System {system.__name__} - Input {param} has wrong type",
53
+ )
54
+
55
+ def set_component(self, result: None | Mapping[str, object]):
56
+ if result is None:
57
+ return
58
+ assert isinstance(result, dict), (
59
+ f"System {self.current_system.__name__} - "
60
+ f"Result is not None or a dictionary"
61
+ )
62
+ for name, obj in result.items():
63
+ self.assert_type_obj(
64
+ self.component.__annotations__[name], # pyright: ignore[reportAny]
65
+ obj,
66
+ (
67
+ f"System {self.current_system.__name__} "
68
+ f"- Output {name} has wrong type"
69
+ ),
70
+ )
71
+ setattr(self.component, name, obj)
72
+
73
+ @staticmethod
74
+ def assert_type_obj(parent_annotation: type, obj: object, message: str):
75
+ parent_origin = getattr(parent_annotation, "__origin__", parent_annotation)
76
+ assert (type(obj) is parent_annotation) or isinstance(
77
+ obj, parent_origin
78
+ ), message
79
+
80
+ @staticmethod
81
+ def assert_type_annotation(
82
+ parent_annotation: TypeAlias, child_annotation: TypeAlias, message: str
83
+ ):
84
+ child_origin = getattr(child_annotation, "__origin__", child_annotation)
85
+ parent_origin = getattr(parent_annotation, "__origin__", parent_annotation)
86
+ assert isinstance(parent_origin, type) or parent_origin is TypeAlias
87
+ assert (child_annotation == parent_annotation) or isinstance(
88
+ child_origin, parent_origin
89
+ ), message
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.1
2
+ Name: pipeline-component-system
3
+ Version: 0.0.1
4
+ Summary: A strange programming framework
5
+ Author-email: Daniel Cauchi <cowkeyman@gmail.com>
6
+ Project-URL: Homepage, https://github.com/CowKeyMan/PCS
7
+ Project-URL: Issues, https://github.com/CowKeyMan/PCS/issues
8
+ Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: License :: OSI Approved :: MIT No Attribution License (MIT-0)
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Natural Language :: English
13
+ Classifier: Intended Audience :: Developers
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+
18
+ # Pipeline Component System (PCS)
19
+
20
+
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ pcs/__init__.py
5
+ pcs/argument_parser.py
6
+ pcs/init.py
7
+ pcs/pipeline.py
8
+ pipeline_component_system.egg-info/PKG-INFO
9
+ pipeline_component_system.egg-info/SOURCES.txt
10
+ pipeline_component_system.egg-info/dependency_links.txt
11
+ pipeline_component_system.egg-info/top_level.txt
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "pipeline-component-system"
3
+ version = "0.0.1"
4
+ authors = [
5
+ { name="Daniel Cauchi", email="cowkeyman@gmail.com" },
6
+ ]
7
+ description = "A strange programming framework"
8
+ readme = "README.md"
9
+ requires-python = ">=3.9"
10
+ classifiers = [
11
+ "Development Status :: 2 - Pre-Alpha",
12
+ "License :: OSI Approved :: MIT No Attribution License (MIT-0)",
13
+ "Operating System :: POSIX :: Linux",
14
+ "Programming Language :: Python :: 3 :: Only",
15
+ "Natural Language :: English",
16
+ "Intended Audience :: Developers"
17
+ ]
18
+
19
+ [project.urls]
20
+ Homepage = "https://github.com/CowKeyMan/PCS"
21
+ Issues = "https://github.com/CowKeyMan/PCS/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+