pyrig-runtime 2.2.1__tar.gz → 2.3.0__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.
Files changed (30) hide show
  1. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/PKG-INFO +1 -1
  2. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/pyproject.toml +1 -1
  3. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/dependencies/discovery.py +9 -9
  4. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/dependencies/subclass.py +13 -10
  5. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/packages.py +27 -13
  6. {pyrig_runtime-2.2.1/src/pyrig_runtime/rig/cli → pyrig_runtime-2.3.0/src/pyrig_runtime/rig}/cli/cli.py +5 -4
  7. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/commands/version.py +1 -1
  8. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/main.py +1 -1
  9. pyrig_runtime-2.2.1/src/pyrig_runtime/rig/cli/cli/__init__.py +0 -1
  10. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/LICENSE +0 -0
  11. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/README.md +0 -0
  12. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/__init__.py +0 -0
  13. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/__init__.py +0 -0
  14. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/constants.py +0 -0
  15. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/dependencies/__init__.py +0 -0
  16. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/dependencies/graph.py +0 -0
  17. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/graph.py +0 -0
  18. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/__init__.py +0 -0
  19. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/classes.py +0 -0
  20. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/functions.py +0 -0
  21. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/inspection.py +0 -0
  22. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/introspection/modules.py +0 -0
  23. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/strings.py +0 -0
  24. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/core/wrappers.py +0 -0
  25. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/py.typed +0 -0
  26. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/__init__.py +0 -0
  27. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/__init__.py +0 -0
  28. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/commands/__init__.py +0 -0
  29. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/shared_subcommands.py +0 -0
  30. {pyrig_runtime-2.2.1 → pyrig_runtime-2.3.0}/src/pyrig_runtime/rig/cli/subcommands.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrig-runtime
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Runtime dependency and library for projects built with pyrig.
5
5
  Keywords: pyrig
6
6
  Author: Winipedia
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyrig-runtime"
3
- version = "2.2.1"
3
+ version = "2.3.0"
4
4
  description = "Runtime dependency and library for projects built with pyrig."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -21,34 +21,34 @@ logger = logging.getLogger(__name__)
21
21
 
22
22
  def discover_subclasses_across_dependencies[T](
23
23
  cls: type[T],
24
- package: ModuleType,
24
+ module: ModuleType,
25
25
  ) -> Iterator[type[T]]:
26
- """Yield subclasses of `cls` found in `package` and in dependent packages.
26
+ """Yield subclasses of `cls` found in `module` and in dependent packages.
27
27
 
28
28
  Args:
29
29
  cls: Base class whose subclasses should be discovered.
30
- package: Package to search first, also used to determine which root
30
+ module: Module to search first, also used to determine which root
31
31
  package to scan for dependents.
32
32
 
33
33
  Yields:
34
- Subclass types of `cls`, with `package` searched first, then
34
+ Subclass types of `cls`, with `module` searched first, then
35
35
  dependent packages in dependency order.
36
36
  """
37
37
  logger.debug(
38
38
  "Discovering subclasses of %s from modules in packages depending on %s",
39
39
  cls.__name__,
40
- package.__name__,
40
+ module.__name__,
41
41
  )
42
42
 
43
43
  return (
44
44
  subclass
45
- for pkg in chain(
46
- (package,),
47
- discover_equivalent_modules_across_dependents(module=package),
45
+ for mod in chain(
46
+ (module,),
47
+ discover_equivalent_modules_across_dependents(module=module),
48
48
  )
49
49
  for subclass in discover_subclasses_across_package(
50
50
  cls,
51
- package=pkg,
51
+ module=mod,
52
52
  )
53
53
  )
54
54
 
@@ -63,10 +63,11 @@ class DependencySubclassMeta(ABCMeta):
63
63
  class DependencySubclass(metaclass=DependencySubclassMeta):
64
64
  """Abstract base enabling plugin-style subclass discovery across installed packages.
65
65
 
66
- Subclasses declare a sub-package scope by overriding the discovery hook,
66
+ Subclasses declare a discovery scope by overriding the discovery hook,
67
67
  and the base class automatically finds all subclass implementations defined
68
- in that sub-package across every installed package that depends on the root
69
- package. No explicit registration is required.
68
+ in that scope across every installed package that depends on the root
69
+ package. The scope may be a single module or a whole sub-package. No
70
+ explicit registration is required.
70
71
  """
71
72
 
72
73
  def __str__(self) -> str:
@@ -75,17 +76,19 @@ class DependencySubclass(metaclass=DependencySubclassMeta):
75
76
 
76
77
  @classmethod
77
78
  @abstractmethod
78
- def dependency_package(cls) -> ModuleType:
79
- """Return the sub-package where this class's implementations are defined.
79
+ def discovery_module(cls) -> ModuleType:
80
+ """Return the module or package where this class's implementations are defined.
80
81
 
81
- Every concrete subclass must override this to return the sub-package
82
- module that contains its own implementation classes. The base class uses
83
- the returned module to scope cross-package subclass discovery.
82
+ Every concrete subclass must override this to return the module or
83
+ sub-package that contains its own implementation classes. When a
84
+ package is returned it is searched recursively; when a plain module is
85
+ returned only that module is searched. The base class uses the returned
86
+ module to scope cross-package subclass discovery.
84
87
 
85
88
  The base implementation returns `pyrig_runtime.rig`.
86
89
 
87
90
  Returns:
88
- The sub-package module to search for concrete implementations of
91
+ The module or package to search for concrete implementations of
89
92
  this class.
90
93
  """
91
94
  return rig
@@ -158,7 +161,7 @@ Found subclasses:
158
161
  return discard_parent_classes(
159
162
  discover_subclasses_across_dependencies(
160
163
  cls,
161
- package=cls.dependency_package(),
164
+ module=cls.discovery_module(),
162
165
  )
163
166
  )
164
167
 
@@ -1,4 +1,4 @@
1
- """Subclass discovery scoped to a package's full module hierarchy."""
1
+ """Subclass discovery scoped to a single module or a package's module hierarchy."""
2
2
 
3
3
  from collections.abc import Iterator
4
4
  from functools import cache
@@ -10,31 +10,33 @@ from pyrig_runtime.core.introspection.modules import iter_modules
10
10
 
11
11
  def discover_subclasses_across_package[T](
12
12
  cls: type[T],
13
- package: ModuleType,
13
+ module: ModuleType,
14
14
  ) -> set[type[T]]:
15
- """Discover all subclasses of `cls` defined within a package.
15
+ """Discover all subclasses of `cls` defined within a module or package.
16
16
 
17
- The package is scanned recursively, so subclasses are found in its
18
- sub-modules at any nesting depth, including ones not yet imported when this
19
- is called. Only subclasses whose defining module is a proper sub-module of
20
- `package` are returned; a class defined directly in the package's own
21
- `__init__` module is not discovered, so implementations belong in
22
- sub-modules rather than the package `__init__`.
17
+ When `module` is a package, it is scanned recursively, so subclasses are
18
+ found in its sub-modules at any nesting depth, including ones not yet
19
+ imported when this is called. When `module` is a plain module, only
20
+ subclasses defined directly in that module are returned.
21
+
22
+ A subclass matches when its defining module is `module` itself or a
23
+ sub-module of it.
23
24
 
24
25
  Args:
25
26
  cls: Base class whose subclasses should be discovered.
26
- package: Package to scope discovery to.
27
+ module: Module or package to scope discovery to.
27
28
 
28
29
  Returns:
29
30
  Set of all transitive subclass types of `cls` defined within
30
- `package`, excluding `cls` itself.
31
+ `module`, excluding `cls` itself.
31
32
  """
32
- register_package_modules(package)
33
+ if is_package(module):
34
+ register_package_modules(module)
33
35
  subclasses = discover_subclasses(cls)
34
36
  return {
35
37
  subclass
36
38
  for subclass in subclasses
37
- if subclass.__module__.startswith(f"{package.__name__}.")
39
+ if subclass.__module__.startswith(module.__name__)
38
40
  }
39
41
 
40
42
 
@@ -71,3 +73,15 @@ def walk_package(package: ModuleType) -> Iterator[tuple[ModuleType, bool]]:
71
73
  yield from walk_package(module)
72
74
  else:
73
75
  yield module, False
76
+
77
+
78
+ def is_package(module: ModuleType) -> bool:
79
+ """Return True if `module` is a package, False otherwise.
80
+
81
+ Args:
82
+ module: Module to check.
83
+
84
+ Returns:
85
+ True if `module` is a package, False otherwise.
86
+ """
87
+ return hasattr(module, "__path__")
@@ -2,6 +2,7 @@
2
2
 
3
3
  import logging
4
4
  import sys
5
+ from importlib import import_module
5
6
  from itertools import chain
6
7
  from pathlib import Path
7
8
  from types import ModuleType
@@ -22,7 +23,7 @@ from pyrig_runtime.core.strings import (
22
23
  kebab_to_snake_case,
23
24
  snake_to_kebab_case,
24
25
  )
25
- from pyrig_runtime.rig.cli import cli, shared_subcommands, subcommands
26
+ from pyrig_runtime.rig.cli import shared_subcommands, subcommands
26
27
 
27
28
 
28
29
  class CLI(DependencySubclass):
@@ -34,9 +35,9 @@ class CLI(DependencySubclass):
34
35
  """
35
36
 
36
37
  @classmethod
37
- def dependency_package(cls) -> ModuleType:
38
- """Return the `pyrig_runtime.rig.cli.cli` package module."""
39
- return cli
38
+ def discovery_module(cls) -> ModuleType:
39
+ """Return the `pyrig_runtime.rig.cli.cli` module."""
40
+ return import_module(CLI.__module__)
40
41
 
41
42
  def run(self) -> None:
42
43
  """Build and invoke the Typer application."""
@@ -4,7 +4,7 @@ from importlib.metadata import version
4
4
 
5
5
  import typer
6
6
 
7
- from pyrig_runtime.rig.cli.cli.cli import CLI
7
+ from pyrig_runtime.rig.cli.cli import CLI
8
8
 
9
9
 
10
10
  def project_version() -> None:
@@ -1,6 +1,6 @@
1
1
  """Console-script entry point for pyrig-runtime-based projects."""
2
2
 
3
- from pyrig_runtime.rig.cli.cli.cli import CLI
3
+ from pyrig_runtime.rig.cli.cli import CLI
4
4
 
5
5
 
6
6
  def main() -> None:
@@ -1 +0,0 @@
1
- """Extensible CLI builder for pyrig-runtime-based projects."""
File without changes
File without changes