swarmauri-typing 0.7.0.dev2__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,154 @@
1
+ Metadata-Version: 2.3
2
+ Name: swarmauri-typing
3
+ Version: 0.7.0.dev2
4
+ Summary: This repository includes typing used in the Swarmauri framework.
5
+ License: Apache-2.0
6
+ Author: Jacob Stewart
7
+ Author-email: jacob@swarmauri.com
8
+ Requires-Python: >=3.10,<3.13
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Description-Content-Type: text/markdown
14
+
15
+ ![Swamauri Logo](https://res.cloudinary.com/dbjmpekvl/image/upload/v1730099724/Swarmauri-logo-lockup-2048x757_hww01w.png)
16
+
17
+ <p align="center">
18
+ <a href="https://pypi.org/project/swarmauri/">
19
+ <img src="https://img.shields.io/pypi/dm/swarmauri" alt="PyPI - Downloads"/></a>
20
+ <a href="https://github.com/swarmauri/swarmauri-sdk">
21
+ <img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://github.com/swarmauri/swarmauri-sdk&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false" alt="GitHub Hits"/></a>
22
+ <a href="https://pypi.org/project/swarmauri_typing/">
23
+ <img src="https://img.shields.io/pypi/pyversions/swarmauri" alt="PyPI - Python Version"/></a>
24
+ <a href="https://pypi.org/project/swarmauri_typing/">
25
+ <img src="https://img.shields.io/pypi/l/swarmauri_typing" alt="PyPI - License"/></a>
26
+ <br />
27
+ <a href="https://pypi.org/project/swarmauri/">
28
+ <img src="https://img.shields.io/pypi/v/swarmauri?label=swarmauri_typing&color=green" alt="PyPI - swarmauri_core"/></a>
29
+ </p>
30
+
31
+
32
+ # Swarmauri Typing Library
33
+
34
+ The Swarmauri Typing Library provides advanced type utilities for Python, enabling more expressive and flexible type annotations. It includes tools for creating intersection and union types dynamically.
35
+
36
+ ## Features
37
+
38
+ - **Intersection Types**: Create intersection types that combine multiple classes.
39
+
40
+ ```python
41
+ from typing import Type, TypeVar, Union, Any, Annotated, Tuple
42
+
43
+ T = TypeVar("T")
44
+
45
+ class IntersectionMetadata:
46
+ def __init__(self, classes: Tuple[Type[T]]):
47
+ self.classes = classes
48
+
49
+ def __repr__(self):
50
+ return f"IntersectionMetadata(classes={self.classes!r})"
51
+
52
+ class Intersection(type):
53
+ def __class_getitem__(cls, classes: Union[Type, Tuple[Type, ...]]) -> type:
54
+ if not isinstance(classes, tuple):
55
+ classes = (classes,)
56
+
57
+ common = set(classes[0].__mro__)
58
+ for c in classes[1:]:
59
+ common.intersection_update(c.__mro__)
60
+
61
+ ordered_common = [c for c in classes[0].__mro__ if c in common]
62
+
63
+ if not ordered_common:
64
+ return Annotated[Any, IntersectionMetadata(classes=(classes))]
65
+ else:
66
+ union_type = Union[tuple(ordered_common)]
67
+ return Annotated[union_type, IntersectionMetadata(classes=(classes))]
68
+ ```
69
+
70
+ - **Union Factory**: Dynamically create union types based on a provided function.
71
+
72
+ ```python
73
+ from typing import Type, TypeVar, Callable, List, Union, Any, Annotated, get_args, Optional
74
+
75
+ T = TypeVar("T")
76
+
77
+ class UnionFactoryMetadata:
78
+ def __init__(self, data: Any, name: Optional[str] = None):
79
+ self.data = data
80
+ self.name = name or self.__class__.__name__
81
+
82
+ def __repr__(self):
83
+ return f"UnionFactoryMetadata(name={self.name!r}, data={self.data!r})"
84
+
85
+ class UnionFactory:
86
+ def __init__(self, bound: Callable[[Type[T]], List[type]], name: str = None, annotation_extenders: List[Any] = None):
87
+ self.name = name or self.__class__.__name__
88
+ self._union_types_getter = bound
89
+ self._annotation_extenders = annotation_extenders or []
90
+
91
+ def _add_metadata(self, annotated_type: Any, new_metadata: Any) -> Any:
92
+ if not (hasattr(annotated_type, '__origin__') and annotated_type.__origin__ is Annotated):
93
+ return Annotated[annotated_type, new_metadata]
94
+
95
+ args = get_args(annotated_type)
96
+ base_type = args[0]
97
+ old_metadata = args[1:]
98
+ return Annotated[base_type, *old_metadata, new_metadata]
99
+
100
+ def __getitem__(self, input_data: Union[Type[T], str]) -> type:
101
+ if isinstance(input_data, str):
102
+ model_name = input_data
103
+ else:
104
+ model_name = input_data.__name__
105
+
106
+ union_members = self._union_types_getter(model_name)
107
+
108
+ if not union_members:
109
+ final_annotated = Annotated[Any, UnionFactoryMetadata(data=model_name, name=self.name)]
110
+ else:
111
+ union_type = Union[tuple(union_members)]
112
+ final_annotated = Annotated[union_type, UnionFactoryMetadata(data=model_name, name=self.name)]
113
+
114
+ for extension in self._annotation_extenders:
115
+ final_annotated = self._add_metadata(final_annotated, extension)
116
+
117
+ return final_annotated
118
+ ```
119
+
120
+ ## Getting Started
121
+
122
+ To start using the Swarmauri Typing Library, include it as a module in your Python project. Ensure you have Python 3.10 or later installed.
123
+
124
+ ### Steps to install via pypi
125
+
126
+ ```sh
127
+ pip install swarmauri-typing
128
+ ```
129
+
130
+ ### Usage Example
131
+
132
+ ```python
133
+ from swarmauri_typing import Intersection, UnionFactory
134
+
135
+ # Example of using Intersection
136
+ class A: pass
137
+ class B: pass
138
+
139
+ IntersectionType = Intersection[A, B]
140
+
141
+ # Example of using UnionFactory
142
+ def my_types_getter(name: str):
143
+ return [A, B]
144
+
145
+ union_factory = UnionFactory(my_types_getter)
146
+ MyUnion = union_factory["MyModel"]
147
+ ```
148
+
149
+
150
+ ## Contributing
151
+
152
+ Contributions are welcome! If you'd like to add a new feature, fix a bug, or improve documentation, kindly go through the [contributions guidelines](https://github.com/swarmauri/swarmauri-sdk/blob/master/contributing.md) first.
153
+
154
+
@@ -0,0 +1,139 @@
1
+ ![Swamauri Logo](https://res.cloudinary.com/dbjmpekvl/image/upload/v1730099724/Swarmauri-logo-lockup-2048x757_hww01w.png)
2
+
3
+ <p align="center">
4
+ <a href="https://pypi.org/project/swarmauri/">
5
+ <img src="https://img.shields.io/pypi/dm/swarmauri" alt="PyPI - Downloads"/></a>
6
+ <a href="https://github.com/swarmauri/swarmauri-sdk">
7
+ <img src="https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://github.com/swarmauri/swarmauri-sdk&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false" alt="GitHub Hits"/></a>
8
+ <a href="https://pypi.org/project/swarmauri_typing/">
9
+ <img src="https://img.shields.io/pypi/pyversions/swarmauri" alt="PyPI - Python Version"/></a>
10
+ <a href="https://pypi.org/project/swarmauri_typing/">
11
+ <img src="https://img.shields.io/pypi/l/swarmauri_typing" alt="PyPI - License"/></a>
12
+ <br />
13
+ <a href="https://pypi.org/project/swarmauri/">
14
+ <img src="https://img.shields.io/pypi/v/swarmauri?label=swarmauri_typing&color=green" alt="PyPI - swarmauri_core"/></a>
15
+ </p>
16
+
17
+
18
+ # Swarmauri Typing Library
19
+
20
+ The Swarmauri Typing Library provides advanced type utilities for Python, enabling more expressive and flexible type annotations. It includes tools for creating intersection and union types dynamically.
21
+
22
+ ## Features
23
+
24
+ - **Intersection Types**: Create intersection types that combine multiple classes.
25
+
26
+ ```python
27
+ from typing import Type, TypeVar, Union, Any, Annotated, Tuple
28
+
29
+ T = TypeVar("T")
30
+
31
+ class IntersectionMetadata:
32
+ def __init__(self, classes: Tuple[Type[T]]):
33
+ self.classes = classes
34
+
35
+ def __repr__(self):
36
+ return f"IntersectionMetadata(classes={self.classes!r})"
37
+
38
+ class Intersection(type):
39
+ def __class_getitem__(cls, classes: Union[Type, Tuple[Type, ...]]) -> type:
40
+ if not isinstance(classes, tuple):
41
+ classes = (classes,)
42
+
43
+ common = set(classes[0].__mro__)
44
+ for c in classes[1:]:
45
+ common.intersection_update(c.__mro__)
46
+
47
+ ordered_common = [c for c in classes[0].__mro__ if c in common]
48
+
49
+ if not ordered_common:
50
+ return Annotated[Any, IntersectionMetadata(classes=(classes))]
51
+ else:
52
+ union_type = Union[tuple(ordered_common)]
53
+ return Annotated[union_type, IntersectionMetadata(classes=(classes))]
54
+ ```
55
+
56
+ - **Union Factory**: Dynamically create union types based on a provided function.
57
+
58
+ ```python
59
+ from typing import Type, TypeVar, Callable, List, Union, Any, Annotated, get_args, Optional
60
+
61
+ T = TypeVar("T")
62
+
63
+ class UnionFactoryMetadata:
64
+ def __init__(self, data: Any, name: Optional[str] = None):
65
+ self.data = data
66
+ self.name = name or self.__class__.__name__
67
+
68
+ def __repr__(self):
69
+ return f"UnionFactoryMetadata(name={self.name!r}, data={self.data!r})"
70
+
71
+ class UnionFactory:
72
+ def __init__(self, bound: Callable[[Type[T]], List[type]], name: str = None, annotation_extenders: List[Any] = None):
73
+ self.name = name or self.__class__.__name__
74
+ self._union_types_getter = bound
75
+ self._annotation_extenders = annotation_extenders or []
76
+
77
+ def _add_metadata(self, annotated_type: Any, new_metadata: Any) -> Any:
78
+ if not (hasattr(annotated_type, '__origin__') and annotated_type.__origin__ is Annotated):
79
+ return Annotated[annotated_type, new_metadata]
80
+
81
+ args = get_args(annotated_type)
82
+ base_type = args[0]
83
+ old_metadata = args[1:]
84
+ return Annotated[base_type, *old_metadata, new_metadata]
85
+
86
+ def __getitem__(self, input_data: Union[Type[T], str]) -> type:
87
+ if isinstance(input_data, str):
88
+ model_name = input_data
89
+ else:
90
+ model_name = input_data.__name__
91
+
92
+ union_members = self._union_types_getter(model_name)
93
+
94
+ if not union_members:
95
+ final_annotated = Annotated[Any, UnionFactoryMetadata(data=model_name, name=self.name)]
96
+ else:
97
+ union_type = Union[tuple(union_members)]
98
+ final_annotated = Annotated[union_type, UnionFactoryMetadata(data=model_name, name=self.name)]
99
+
100
+ for extension in self._annotation_extenders:
101
+ final_annotated = self._add_metadata(final_annotated, extension)
102
+
103
+ return final_annotated
104
+ ```
105
+
106
+ ## Getting Started
107
+
108
+ To start using the Swarmauri Typing Library, include it as a module in your Python project. Ensure you have Python 3.10 or later installed.
109
+
110
+ ### Steps to install via pypi
111
+
112
+ ```sh
113
+ pip install swarmauri-typing
114
+ ```
115
+
116
+ ### Usage Example
117
+
118
+ ```python
119
+ from swarmauri_typing import Intersection, UnionFactory
120
+
121
+ # Example of using Intersection
122
+ class A: pass
123
+ class B: pass
124
+
125
+ IntersectionType = Intersection[A, B]
126
+
127
+ # Example of using UnionFactory
128
+ def my_types_getter(name: str):
129
+ return [A, B]
130
+
131
+ union_factory = UnionFactory(my_types_getter)
132
+ MyUnion = union_factory["MyModel"]
133
+ ```
134
+
135
+
136
+ ## Contributing
137
+
138
+ Contributions are welcome! If you'd like to add a new feature, fix a bug, or improve documentation, kindly go through the [contributions guidelines](https://github.com/swarmauri/swarmauri-sdk/blob/master/contributing.md) first.
139
+
@@ -0,0 +1,57 @@
1
+ [project]
2
+ name = "swarmauri-typing"
3
+ version = "0.7.0.dev2"
4
+ description = "This repository includes typing used in the Swarmauri framework."
5
+ authors = [
6
+ { name = "Jacob Stewart", email = "jacob@swarmauri.com" },
7
+ ]
8
+ license = "Apache-2.0"
9
+ readme = { file = "README.md", content-type = "text/markdown" }
10
+ repository = "http://github.com/swarmauri/swarmauri-sdk"
11
+ classifiers = [
12
+ "License :: OSI Approved :: Apache Software License",
13
+ "Programming Language :: Python :: 3.10",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12"
16
+ ]
17
+ requires-python = ">=3.10,<3.13"
18
+
19
+ [tool.uv.sources]
20
+ swarmauri_core = { workspace = true }
21
+
22
+ [dependency-groups]
23
+ dev = [
24
+ "toml>=0.10.2",
25
+ "pytest>=8.0.0",
26
+ "pytest-xdist>=3.6.1",
27
+ "pytest-asyncio>=0.24.0",
28
+ "pytest-timeout>=2.3.1",
29
+ "pytest-json-report>=1.5.0",
30
+ "python-dotenv>=1.0.0",
31
+ "pytest-mock>=3.14.0",
32
+ "jsonschema>=4.18.5",
33
+ "ruff>=0.9.9",
34
+ ]
35
+
36
+ [tool.pytest.ini_options]
37
+ markers = [
38
+ "test: standard test",
39
+ "unit: Unit tests",
40
+ "i9n: Integration Tests",
41
+ "r8n: Regression Tests",
42
+ "timeout: mark test to timeout after X seconds",
43
+ "xfail: Expected failures",
44
+ "xpass: Expected passes",
45
+ "acceptance: Acceptance tests"
46
+ ]
47
+
48
+ log_cli = true
49
+ log_cli_level = "INFO"
50
+ log_cli_format = "%(asctime)s [%(levelname)s] %(message)s"
51
+ log_cli_date_format = "%Y-%m-%d %H:%M:%S"
52
+
53
+ asyncio_default_fixture_loop_scope = "function"
54
+
55
+ [build-system]
56
+ requires = ["poetry-core>=1.0.0"]
57
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,47 @@
1
+ from typing import Type, TypeVar, Union, Any, Annotated, Tuple
2
+
3
+ T = TypeVar("T")
4
+
5
+
6
+ class IntersectionMetadata:
7
+ def __init__(self, classes: Tuple[Type[T]]):
8
+ self.classes = classes
9
+
10
+ def __repr__(self):
11
+ # Return a more 'developer-focused' string, e.g.:
12
+ return f"IntersectionMetadata(classes={self.classes!r})"
13
+
14
+
15
+ # The Intersection metaclass as provided.
16
+ class Intersection(type):
17
+ """
18
+ A generic metaclass to create an intersection of discriminated subclasses.
19
+ Usage:
20
+ Intersection[TypeA, TypeB, ...]
21
+ will return an Annotated Union of all registered classes that are common to
22
+ all given resource types.
23
+ """
24
+
25
+ def __class_getitem__(cls, classes: Union[Type, Tuple[Type, ...]]) -> type:
26
+ # Allow a single type or a tuple of types.
27
+ if not isinstance(classes, tuple):
28
+ classes = (classes,)
29
+
30
+ # Compute the intersection of all MRO sets.
31
+ common = set(classes[0].__mro__)
32
+ for c in classes[1:]:
33
+ common.intersection_update(c.__mro__)
34
+
35
+ # Order the common classes as they appear in the first class's MRO.
36
+ ordered_common = [c for c in classes[0].__mro__ if c in common]
37
+
38
+ if not ordered_common:
39
+ # Fallback to Any (should not happen as 'object' is always common)
40
+ return Annotated[Any, IntersectionMetadata(classes=(classes))]
41
+ else:
42
+ # Construct a Union type from the ordered common bases.
43
+ union_type = Union[tuple(ordered_common)]
44
+ return Annotated[
45
+ union_type,
46
+ IntersectionMetadata(classes=(classes)),
47
+ ]
@@ -0,0 +1,109 @@
1
+ from typing import (
2
+ Type,
3
+ TypeVar,
4
+ Callable,
5
+ List,
6
+ Union,
7
+ Any,
8
+ Annotated,
9
+ get_args,
10
+ Optional,
11
+ )
12
+
13
+ T = TypeVar("T")
14
+
15
+
16
+ class UnionFactoryMetadata:
17
+ """
18
+ Stores any metadata related to the union created by 'UnionFactory'.
19
+ You can store anything you like in here (e.g., the original input
20
+ or other context data).
21
+ """
22
+
23
+ def __init__(self, data: Any, name: Optional[str] = None):
24
+ self.data = data
25
+ self.name = name or self.__class__.__name__
26
+
27
+ def __repr__(self):
28
+ # Return a more 'developer-focused' string, e.g.:
29
+ return f"UnionFactoryMetadata(name={self.name!r}, data={self.data!r})"
30
+
31
+
32
+ class UnionFactory:
33
+ """
34
+ A configurable factory for creating Annotated Union types.
35
+
36
+ This can be used for many scenarios—e.g., uniting a set of classes
37
+ discovered dynamically, or enumerating a set of allowed types
38
+ based on a function you supply.
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ bound: Callable[[Type[T]], List[type]],
44
+ name: "str" = None,
45
+ annotation_extenders: List[Any] = None,
46
+ ):
47
+ """
48
+ :param bound:
49
+ A function that takes an input (like a parent class or any other
50
+ context) and returns a list of types to be included in the union.
51
+ :param annotation_extenders:
52
+ A list of metadata items to be appended (in order) to the final
53
+ Annotated[...] union (beyond the default UnionFactoryMetadata).
54
+ """
55
+ self.name = name or self.__class__.__name__
56
+ self._union_types_getter = bound
57
+ self._annotation_extenders = annotation_extenders or []
58
+
59
+ def _add_metadata(self, annotated_type: Any, new_metadata: Any) -> Any:
60
+ """
61
+ Appends 'new_metadata' to an existing Annotated type,
62
+ or wraps a bare type in Annotated if it's not already Annotated.
63
+ """
64
+ if not (
65
+ hasattr(annotated_type, "__origin__")
66
+ and annotated_type.__origin__ is Annotated
67
+ ):
68
+ return Annotated[annotated_type, new_metadata]
69
+
70
+ args = get_args(annotated_type)
71
+ base_type = args[0]
72
+ old_metadata = args[1:]
73
+ return Annotated[base_type, *old_metadata, new_metadata]
74
+
75
+ def __getitem__(self, input_data: Union[Type[T], str]) -> type:
76
+ """
77
+ Usage example:
78
+ union_factory = UnionFactory(my_types_getter, [meta1, meta2])
79
+ MyUnion = union_factory[MyParentClassOrOtherInput]
80
+
81
+ Returns:
82
+ An Annotated[...] union (or Annotated[Any, ...]) with:
83
+ • A UnionFactoryMetadata object referencing 'input_data'
84
+ • Any additional metadata from 'annotation_extenders'
85
+ """
86
+
87
+ if isinstance(input_data, str):
88
+ model_name = input_data
89
+ else:
90
+ model_name = input_data.__name__
91
+
92
+ union_members = self._union_types_getter(model_name)
93
+
94
+ # If no types are returned, fall back to Annotated[Any, UnionFactoryMetadata]
95
+ if not union_members:
96
+ final_annotated = Annotated[
97
+ Any, UnionFactoryMetadata(data=model_name, name=self.name)
98
+ ]
99
+ else:
100
+ union_type = Union[tuple(union_members)]
101
+ final_annotated = Annotated[
102
+ union_type, UnionFactoryMetadata(data=model_name, name=self.name)
103
+ ]
104
+
105
+ # Add any additional metadata
106
+ for extension in self._annotation_extenders:
107
+ final_annotated = self._add_metadata(final_annotated, extension)
108
+
109
+ return final_annotated
@@ -0,0 +1,22 @@
1
+ from .UnionFactory import UnionFactory, UnionFactoryMetadata
2
+ from .Intersection import Intersection, IntersectionMetadata
3
+
4
+ __all__ = [
5
+ "UnionFactory",
6
+ "UnionFactoryMetadata",
7
+ "Intersection",
8
+ "IntersectionMetadata",
9
+ ]
10
+
11
+ try:
12
+ # For Python 3.8 and newer
13
+ from importlib.metadata import version, PackageNotFoundError
14
+ except ImportError:
15
+ # For older Python versions, use the backport
16
+ from importlib_metadata import version, PackageNotFoundError
17
+
18
+ try:
19
+ __version__ = version("swarmauri_typing")
20
+ except PackageNotFoundError:
21
+ # If the package is not installed (for example, during development)
22
+ __version__ = "0.0.0"