pyrig-runtime 2.1.2__tar.gz → 2.2.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.
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/PKG-INFO +1 -1
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/pyproject.toml +1 -1
- pyrig_runtime-2.2.1/src/pyrig_runtime/__init__.py +5 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/dependencies/discovery.py +2 -5
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/dependencies/subclass.py +1 -1
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/graph.py +10 -7
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/functions.py +6 -3
- pyrig_runtime-2.2.1/src/pyrig_runtime/core/introspection/modules.py +197 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/strings.py +3 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/wrappers.py +0 -4
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/cli/cli.py +10 -11
- pyrig_runtime-2.1.2/src/pyrig_runtime/__init__.py +0 -5
- pyrig_runtime-2.1.2/src/pyrig_runtime/core/introspection/modules.py +0 -126
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/LICENSE +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/README.md +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/constants.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/dependencies/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/dependencies/graph.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/classes.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/inspection.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/packages.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/py.typed +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/cli/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/commands/__init__.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/commands/version.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/main.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/shared_subcommands.py +0 -0
- {pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/rig/cli/subcommands.py +0 -0
{pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/dependencies/discovery.py
RENAMED
|
@@ -9,8 +9,8 @@ from types import ModuleType
|
|
|
9
9
|
from pyrig_runtime.core.dependencies.graph import DependencyGraph
|
|
10
10
|
from pyrig_runtime.core.introspection.modules import (
|
|
11
11
|
import_modules,
|
|
12
|
+
replace_root_module,
|
|
12
13
|
root_module,
|
|
13
|
-
safe_import_module,
|
|
14
14
|
)
|
|
15
15
|
from pyrig_runtime.core.introspection.packages import (
|
|
16
16
|
discover_subclasses_across_package,
|
|
@@ -79,10 +79,7 @@ def discover_equivalent_modules_across_dependents(
|
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
for package in deps_depending_on_dep(dependency):
|
|
82
|
-
|
|
83
|
-
dependency.__name__, package.__name__, 1
|
|
84
|
-
)
|
|
85
|
-
package_module = safe_import_module(package_module_name, default=None)
|
|
82
|
+
package_module = replace_root_module(module, package.__name__, default=None)
|
|
86
83
|
if package_module is not None:
|
|
87
84
|
yield package_module
|
|
88
85
|
|
|
@@ -114,7 +114,7 @@ class DependencySubclass(metaclass=DependencySubclassMeta):
|
|
|
114
114
|
subclasses are found. May be abstract.
|
|
115
115
|
|
|
116
116
|
Raises:
|
|
117
|
-
RuntimeError: If more than one subclass is discovered across
|
|
117
|
+
RuntimeError: If more than one leaf subclass is discovered across
|
|
118
118
|
the dependent packages.
|
|
119
119
|
"""
|
|
120
120
|
subclasses = cls.subclasses()
|
|
@@ -105,10 +105,10 @@ class DiGraph(ABC):
|
|
|
105
105
|
|
|
106
106
|
Returns:
|
|
107
107
|
List of ancestor node identifiers in topological order.
|
|
108
|
-
Returns an empty list if the target has no ancestors
|
|
109
|
-
in the graph.
|
|
108
|
+
Returns an empty list if the target has no ancestors.
|
|
110
109
|
|
|
111
110
|
Raises:
|
|
111
|
+
KeyError: If the target node is not in the graph.
|
|
112
112
|
RuntimeError: If the ancestor subgraph contains a cycle, making
|
|
113
113
|
topological sorting impossible.
|
|
114
114
|
"""
|
|
@@ -124,16 +124,19 @@ class DiGraph(ABC):
|
|
|
124
124
|
|
|
125
125
|
Returns:
|
|
126
126
|
Set of all nodes with a directed path to the target, excluding the
|
|
127
|
-
target itself.
|
|
127
|
+
target itself.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
KeyError: If the target node is not in the graph.
|
|
128
131
|
"""
|
|
129
132
|
visited: set[str] = set()
|
|
130
|
-
queue: deque[str] = deque(self.reverse_edges
|
|
133
|
+
queue: deque[str] = deque(self.reverse_edges[target])
|
|
131
134
|
|
|
132
135
|
while queue:
|
|
133
136
|
node = queue.popleft()
|
|
134
137
|
if node not in visited:
|
|
135
138
|
visited.add(node)
|
|
136
|
-
for neighbor in self.reverse_edges
|
|
139
|
+
for neighbor in self.reverse_edges[node]:
|
|
137
140
|
if neighbor not in visited:
|
|
138
141
|
queue.append(neighbor)
|
|
139
142
|
|
|
@@ -164,7 +167,7 @@ class DiGraph(ABC):
|
|
|
164
167
|
out_degree: dict[str, int] = dict.fromkeys(nodes, 0)
|
|
165
168
|
|
|
166
169
|
for node in nodes:
|
|
167
|
-
for dependency in self.edges
|
|
170
|
+
for dependency in self.edges[node]:
|
|
168
171
|
if dependency in nodes:
|
|
169
172
|
out_degree[node] += 1
|
|
170
173
|
|
|
@@ -176,7 +179,7 @@ class DiGraph(ABC):
|
|
|
176
179
|
node = heapq.heappop(heap)
|
|
177
180
|
result.append(node)
|
|
178
181
|
|
|
179
|
-
for dependent in self.reverse_edges
|
|
182
|
+
for dependent in self.reverse_edges[node]:
|
|
180
183
|
if dependent in nodes:
|
|
181
184
|
out_degree[dependent] -= 1
|
|
182
185
|
if out_degree[dependent] == 0:
|
{pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/functions.py
RENAMED
|
@@ -24,7 +24,10 @@ def module_functions(
|
|
|
24
24
|
Yields:
|
|
25
25
|
Each function defined in `module`.
|
|
26
26
|
"""
|
|
27
|
-
for _name,
|
|
28
|
-
|
|
29
|
-
if
|
|
27
|
+
for _name, func in obj_members(module):
|
|
28
|
+
unwrapped_func = unwrap_obj(func)
|
|
29
|
+
if (
|
|
30
|
+
inspect.isfunction(unwrapped_func)
|
|
31
|
+
and inspect.getmodule(unwrapped_func) is module
|
|
32
|
+
):
|
|
30
33
|
yield func
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Utilities for Python modules."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Iterable, Iterator
|
|
5
|
+
from importlib import import_module
|
|
6
|
+
from pkgutil import iter_modules as pkgutil_iter_modules
|
|
7
|
+
from types import ModuleType
|
|
8
|
+
from typing import Any, overload
|
|
9
|
+
|
|
10
|
+
from pyrig_runtime.core.constants import MISSING
|
|
11
|
+
from pyrig_runtime.core.wrappers import safe_call
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@overload
|
|
17
|
+
def replace_root_module(module: ModuleType, root: str) -> ModuleType: ...
|
|
18
|
+
@overload
|
|
19
|
+
def replace_root_module[T](
|
|
20
|
+
module: ModuleType, root: str, default: T
|
|
21
|
+
) -> ModuleType | T: ...
|
|
22
|
+
def replace_root_module(
|
|
23
|
+
module: ModuleType, root: str, default: Any = MISSING
|
|
24
|
+
) -> ModuleType | Any:
|
|
25
|
+
"""Import the equivalent module under a different root package.
|
|
26
|
+
|
|
27
|
+
Replaces the first dotted segment of `module`'s name with `root` and
|
|
28
|
+
attempts to import the resulting module name. Later segments are left
|
|
29
|
+
untouched even if they happen to share the old root's name.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
module: Module whose root segment should be swapped.
|
|
33
|
+
root: Root package name to substitute in.
|
|
34
|
+
default: Value to return if the import fails. If not provided,
|
|
35
|
+
the exception propagates unchanged.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
The imported module at the equivalent sub-path under `root`, or
|
|
39
|
+
`default` if the import fails and `default` was provided.
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
>>> from some_package.subpackage import module
|
|
43
|
+
>>> replace_root_module(module, "other_package")
|
|
44
|
+
<module 'other_package.subpackage.module'
|
|
45
|
+
from '/path/to/other_package/subpackage/module.py'>
|
|
46
|
+
"""
|
|
47
|
+
return safe_import_module(replace_root_module_name(module, root), default=default)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def replace_root_module_name(module: ModuleType, root: str) -> str:
|
|
51
|
+
"""Return the equivalent module name under a different root package.
|
|
52
|
+
|
|
53
|
+
Replaces the first dotted segment of `module.__name__` with `root`. Later
|
|
54
|
+
segments are left untouched even if they happen to share the old root's
|
|
55
|
+
name.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
module: Module whose root segment should be swapped.
|
|
59
|
+
root: Root package name to substitute in.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
The equivalent dotted module name under `root`.
|
|
63
|
+
|
|
64
|
+
Example:
|
|
65
|
+
>>> replace_root_module_name(module, "other_package")
|
|
66
|
+
'other_package.subpackage.module'
|
|
67
|
+
"""
|
|
68
|
+
return module.__name__.replace(root_module_name(module), root, 1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def root_module(module: ModuleType) -> ModuleType:
|
|
72
|
+
"""Import and return the top-level package of the given module.
|
|
73
|
+
|
|
74
|
+
For a module named `"package.subpackage.module"`, the module corresponding
|
|
75
|
+
to `"package"` is returned. For a top-level module with no dots in its name,
|
|
76
|
+
the module for that same name is returned.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
module: Module to resolve the root package for.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
The module corresponding to the first segment of the dotted name.
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
>>> from some_package.subpackage import module
|
|
86
|
+
>>> root_module(module)
|
|
87
|
+
<module 'some_package' from '/path/to/some_package/__init__.py'>
|
|
88
|
+
"""
|
|
89
|
+
return import_module(root_module_name(module))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def root_module_name(module: ModuleType) -> str:
|
|
93
|
+
"""Return the name of the top-level package of the given module.
|
|
94
|
+
|
|
95
|
+
For a module named `"package.subpackage.module"`, the string `"package"`
|
|
96
|
+
is returned. For a top-level module with no dots in its name, that same
|
|
97
|
+
name is returned.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
module: Module to resolve the root package name for.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
The first segment of the dotted module name.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
>>> from some_package.subpackage import module
|
|
107
|
+
>>> root_module_name(module)
|
|
108
|
+
'some_package'
|
|
109
|
+
"""
|
|
110
|
+
return module.__name__.split(".", 1)[0]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@overload
|
|
114
|
+
def safe_import_module(
|
|
115
|
+
module_name: str,
|
|
116
|
+
package: str | None = ...,
|
|
117
|
+
*,
|
|
118
|
+
exceptions: tuple[type[BaseException], ...] = ...,
|
|
119
|
+
) -> ModuleType: ...
|
|
120
|
+
@overload
|
|
121
|
+
def safe_import_module[T](
|
|
122
|
+
module_name: str,
|
|
123
|
+
package: str | None = ...,
|
|
124
|
+
*,
|
|
125
|
+
default: T,
|
|
126
|
+
exceptions: tuple[type[BaseException], ...] = ...,
|
|
127
|
+
) -> ModuleType | T: ...
|
|
128
|
+
def safe_import_module(
|
|
129
|
+
module_name: str,
|
|
130
|
+
package: str | None = None,
|
|
131
|
+
*,
|
|
132
|
+
default: Any = MISSING,
|
|
133
|
+
exceptions: tuple[type[BaseException], ...] = (Exception,),
|
|
134
|
+
) -> ModuleType | Any:
|
|
135
|
+
"""Import a module by name, with an optional fallback on failure.
|
|
136
|
+
|
|
137
|
+
Any `Exception` raised during import — not just `ImportError` — is
|
|
138
|
+
handled, so errors at module level (e.g., `ValueError` raised on
|
|
139
|
+
import) are also covered.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
module_name: Dotted module name (e.g., `"package.subpackage.module"`).
|
|
143
|
+
package: Anchor package for relative imports, forwarded to `import_module`.
|
|
144
|
+
default: Value to return if the import raises. If not provided,
|
|
145
|
+
the exception propagates unchanged.
|
|
146
|
+
exceptions: Tuple of exception types to catch. Defaults to `(Exception,)`.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
The imported module, or `default` if an exception is raised and
|
|
150
|
+
`default` was provided.
|
|
151
|
+
"""
|
|
152
|
+
return safe_call(
|
|
153
|
+
import_module,
|
|
154
|
+
module_name,
|
|
155
|
+
package,
|
|
156
|
+
default=default,
|
|
157
|
+
exceptions=exceptions,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def import_modules(module_names: Iterable[str]) -> Iterator[ModuleType]:
|
|
162
|
+
"""Import multiple modules by name, lazily.
|
|
163
|
+
|
|
164
|
+
Modules are imported on demand as the result is iterated, not eagerly.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
module_names: Dotted module names to import.
|
|
168
|
+
|
|
169
|
+
Yields:
|
|
170
|
+
Each imported module, in the order the names are iterated.
|
|
171
|
+
"""
|
|
172
|
+
return (import_module(name) for name in module_names)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def iter_modules(package: ModuleType) -> Iterator[tuple[ModuleType, bool]]:
|
|
176
|
+
"""Import and yield each direct child of a package, in discovery order.
|
|
177
|
+
|
|
178
|
+
Only the immediate children are visited; nested sub-packages are not
|
|
179
|
+
recursed into.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
package: Package to iterate. Must have a `__path__` attribute
|
|
183
|
+
(i.e., must be a package, not a plain module).
|
|
184
|
+
|
|
185
|
+
Yields:
|
|
186
|
+
`(module, is_package)` pairs where `module` is the imported child and
|
|
187
|
+
`is_package` is `True` when the child is itself a sub-package.
|
|
188
|
+
|
|
189
|
+
Note:
|
|
190
|
+
Importing each child is a deliberate side effect — any module-level
|
|
191
|
+
code in those children executes on demand as the iterator is consumed.
|
|
192
|
+
"""
|
|
193
|
+
for _finder, name, is_package in pkgutil_iter_modules(
|
|
194
|
+
package.__path__, prefix=package.__name__ + "."
|
|
195
|
+
):
|
|
196
|
+
mod = import_module(name)
|
|
197
|
+
yield mod, is_package
|
|
@@ -68,6 +68,9 @@ def fully_qualified_name(obj: MethodType | FunctionType | type) -> str:
|
|
|
68
68
|
def distribution_summary(name: str) -> str:
|
|
69
69
|
"""Return the summary recorded in an installed distribution's metadata.
|
|
70
70
|
|
|
71
|
+
This function assumes that the package is installed and its
|
|
72
|
+
metadata has a "Summary" field.
|
|
73
|
+
|
|
71
74
|
Args:
|
|
72
75
|
name: Name of an installed distribution (e.g. `"requests"`).
|
|
73
76
|
|
|
@@ -14,8 +14,6 @@ def safe_call[T, D](
|
|
|
14
14
|
exceptions: tuple[type[BaseException], ...] = ...,
|
|
15
15
|
**kwargs: Any,
|
|
16
16
|
) -> T | D: ...
|
|
17
|
-
|
|
18
|
-
|
|
19
17
|
@overload
|
|
20
18
|
def safe_call[T](
|
|
21
19
|
func: Callable[..., T],
|
|
@@ -23,8 +21,6 @@ def safe_call[T](
|
|
|
23
21
|
exceptions: tuple[type[BaseException], ...] = ...,
|
|
24
22
|
**kwargs: Any,
|
|
25
23
|
) -> T: ...
|
|
26
|
-
|
|
27
|
-
|
|
28
24
|
def safe_call(
|
|
29
25
|
func: Callable[..., Any],
|
|
30
26
|
*args: Any,
|
|
@@ -15,8 +15,7 @@ from pyrig_runtime.core.dependencies.discovery import (
|
|
|
15
15
|
from pyrig_runtime.core.dependencies.subclass import DependencySubclass
|
|
16
16
|
from pyrig_runtime.core.introspection.functions import module_functions
|
|
17
17
|
from pyrig_runtime.core.introspection.modules import (
|
|
18
|
-
|
|
19
|
-
safe_import_module,
|
|
18
|
+
replace_root_module,
|
|
20
19
|
)
|
|
21
20
|
from pyrig_runtime.core.strings import (
|
|
22
21
|
distribution_summary,
|
|
@@ -144,14 +143,15 @@ class CLI(DependencySubclass):
|
|
|
144
143
|
level -= step * verbose
|
|
145
144
|
level += step * quiet
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
verbose_modules =
|
|
146
|
+
verbose_names = 1
|
|
147
|
+
verbose_modules = verbose_names + 1
|
|
148
|
+
verbose_timestamps = verbose_modules + 1
|
|
149
149
|
|
|
150
150
|
if verbose >= verbose_timestamps:
|
|
151
151
|
fmt = "%(asctime)s %(levelname)s [%(name)s] %(message)s"
|
|
152
152
|
elif verbose == verbose_modules:
|
|
153
153
|
fmt = "%(levelname)s [%(name)s] %(message)s"
|
|
154
|
-
elif verbose ==
|
|
154
|
+
elif verbose == verbose_names:
|
|
155
155
|
fmt = "%(levelname)s: %(message)s"
|
|
156
156
|
else:
|
|
157
157
|
fmt = "%(message)s"
|
|
@@ -171,10 +171,9 @@ class CLI(DependencySubclass):
|
|
|
171
171
|
If the invoking project's subcommands module cannot be imported,
|
|
172
172
|
registration is silently skipped.
|
|
173
173
|
"""
|
|
174
|
-
|
|
175
|
-
subcommands,
|
|
174
|
+
subcommands_module = replace_root_module(
|
|
175
|
+
subcommands, root=self.package_name(), default=None
|
|
176
176
|
)
|
|
177
|
-
subcommands_module = safe_import_module(subcommands_module_name, default=None)
|
|
178
177
|
|
|
179
178
|
if subcommands_module is None:
|
|
180
179
|
return
|
|
@@ -258,10 +257,10 @@ class CLI(DependencySubclass):
|
|
|
258
257
|
return kebab_to_snake_case(self.project_name())
|
|
259
258
|
|
|
260
259
|
def project_name(self) -> str:
|
|
261
|
-
"""Return the
|
|
260
|
+
"""Return the stem of `sys.argv[0]` as the invoking project name.
|
|
262
261
|
|
|
263
262
|
When a project is invoked through a registered console-script entry point
|
|
264
263
|
(e.g. `uv run my-project`), `sys.argv[0]` is the path to that script, so
|
|
265
|
-
its
|
|
264
|
+
its stem is the project name as it was registered.
|
|
266
265
|
"""
|
|
267
|
-
return Path(sys.argv[0]).
|
|
266
|
+
return Path(sys.argv[0]).stem
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
"""Utilities for Python modules."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from collections.abc import Iterable, Iterator
|
|
5
|
-
from importlib import import_module
|
|
6
|
-
from pkgutil import iter_modules as pkgutil_iter_modules
|
|
7
|
-
from types import ModuleType
|
|
8
|
-
from typing import Any
|
|
9
|
-
|
|
10
|
-
from pyrig_runtime.core.constants import MISSING
|
|
11
|
-
from pyrig_runtime.core.wrappers import safe_call
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def root_module(module: ModuleType) -> ModuleType:
|
|
17
|
-
"""Import and return the top-level package of the given module.
|
|
18
|
-
|
|
19
|
-
For a module named `"package.subpackage.module"`, the module corresponding
|
|
20
|
-
to `"package"` is returned. For a top-level module with no dots in its name,
|
|
21
|
-
the module for that same name is returned.
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
module: Module to resolve the root package for.
|
|
25
|
-
|
|
26
|
-
Returns:
|
|
27
|
-
The module corresponding to the first segment of the dotted name.
|
|
28
|
-
"""
|
|
29
|
-
return import_module(module.__name__.split(".")[0])
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def safe_import_module(
|
|
33
|
-
module_name: str,
|
|
34
|
-
*args: Any,
|
|
35
|
-
default: Any = MISSING,
|
|
36
|
-
exceptions: tuple[type[BaseException], ...] = (Exception,),
|
|
37
|
-
**kwargs: Any,
|
|
38
|
-
) -> ModuleType | Any:
|
|
39
|
-
"""Import a module by name, with an optional fallback on failure.
|
|
40
|
-
|
|
41
|
-
Any `Exception` raised during import — not just `ImportError` — is
|
|
42
|
-
handled, so errors at module level (e.g., `ValueError` raised on
|
|
43
|
-
import) are also covered.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
module_name: Dotted module name (e.g., `"package.subpackage.module"`).
|
|
47
|
-
*args: Positional arguments forwarded to `import_module`.
|
|
48
|
-
default: Value to return if the import raises. If not provided,
|
|
49
|
-
the exception propagates unchanged.
|
|
50
|
-
exceptions: Tuple of exception types to catch. Defaults to `(Exception,)`.
|
|
51
|
-
**kwargs: Keyword arguments forwarded to `import_module`.
|
|
52
|
-
|
|
53
|
-
Returns:
|
|
54
|
-
The imported module, or `default` if an exception is raised and
|
|
55
|
-
`default` was provided.
|
|
56
|
-
"""
|
|
57
|
-
return safe_call(
|
|
58
|
-
import_module,
|
|
59
|
-
module_name,
|
|
60
|
-
*args,
|
|
61
|
-
**kwargs,
|
|
62
|
-
default=default,
|
|
63
|
-
exceptions=exceptions,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def replace_root_module_name(module: ModuleType, root_module_name: str) -> str:
|
|
68
|
-
"""Replace the root package segment in a module's fully qualified name.
|
|
69
|
-
|
|
70
|
-
Only the first segment is replaced; later segments are left untouched even
|
|
71
|
-
if they happen to share the old root's name.
|
|
72
|
-
|
|
73
|
-
Args:
|
|
74
|
-
module: Module whose name to transform.
|
|
75
|
-
root_module_name: Root package name to substitute in.
|
|
76
|
-
|
|
77
|
-
Returns:
|
|
78
|
-
The module name with its first dotted segment replaced.
|
|
79
|
-
|
|
80
|
-
Example:
|
|
81
|
-
>>> from types import ModuleType
|
|
82
|
-
>>> mod = ModuleType("some_package.sub.module")
|
|
83
|
-
>>> replace_root_module_name(mod, "my_project")
|
|
84
|
-
'my_project.sub.module'
|
|
85
|
-
"""
|
|
86
|
-
module_current_start = module.__name__.split(".")[0]
|
|
87
|
-
return module.__name__.replace(module_current_start, root_module_name, 1)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def import_modules(module_names: Iterable[str]) -> Iterator[ModuleType]:
|
|
91
|
-
"""Import multiple modules by name, lazily.
|
|
92
|
-
|
|
93
|
-
Modules are imported on demand as the result is iterated, not eagerly.
|
|
94
|
-
|
|
95
|
-
Args:
|
|
96
|
-
module_names: Dotted module names to import.
|
|
97
|
-
|
|
98
|
-
Yields:
|
|
99
|
-
Each imported module, in the order the names are iterated.
|
|
100
|
-
"""
|
|
101
|
-
return (import_module(name) for name in module_names)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def iter_modules(package: ModuleType) -> Iterator[tuple[ModuleType, bool]]:
|
|
105
|
-
"""Import and yield each direct child of a package, in discovery order.
|
|
106
|
-
|
|
107
|
-
Only the immediate children are visited; nested sub-packages are not
|
|
108
|
-
recursed into.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
package: Package to iterate. Must have a `__path__` attribute
|
|
112
|
-
(i.e., must be a package, not a plain module).
|
|
113
|
-
|
|
114
|
-
Yields:
|
|
115
|
-
`(module, is_package)` pairs where `module` is the imported child and
|
|
116
|
-
`is_package` is `True` when the child is itself a sub-package.
|
|
117
|
-
|
|
118
|
-
Note:
|
|
119
|
-
Importing each child is a deliberate side effect — any module-level
|
|
120
|
-
code in those children executes on demand as the iterator is consumed.
|
|
121
|
-
"""
|
|
122
|
-
for _finder, name, is_package in pkgutil_iter_modules(
|
|
123
|
-
package.__path__, prefix=package.__name__ + "."
|
|
124
|
-
):
|
|
125
|
-
mod = import_module(name)
|
|
126
|
-
yield mod, is_package
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/inspection.py
RENAMED
|
File without changes
|
{pyrig_runtime-2.1.2 → pyrig_runtime-2.2.1}/src/pyrig_runtime/core/introspection/packages.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|