rats-apps 0.1.3.dev57__py3-none-any.whl → 0.1.3.dev61__py3-none-any.whl
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.
- rats/annotations/__init__.py +25 -0
- rats/annotations/_functions.py +125 -0
- rats/annotations/py.typed +0 -0
- rats/apps/__init__.py +11 -1
- rats/apps/_annotations.py +2 -1
- rats/apps/_plugins.py +17 -0
- rats/cli/__init__.py +19 -0
- rats/cli/_annotations.py +40 -0
- rats/cli/_click.py +38 -0
- rats/cli/_executable.py +23 -0
- rats/cli/_plugins.py +81 -0
- rats/cli/py.typed +0 -0
- {rats_apps-0.1.3.dev57.dist-info → rats_apps-0.1.3.dev61.dist-info}/METADATA +2 -1
- rats_apps-0.1.3.dev61.dist-info/RECORD +23 -0
- rats_apps-0.1.3.dev57.dist-info/RECORD +0 -13
- {rats_apps-0.1.3.dev57.dist-info → rats_apps-0.1.3.dev61.dist-info}/WHEEL +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
"""
|
2
|
+
General purpose library to attach annotations to functions.
|
3
|
+
|
4
|
+
Annotations are typically, but not exclusively, attached using decorators.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from ._functions import (
|
8
|
+
AnnotationsContainer,
|
9
|
+
DecoratorType,
|
10
|
+
GroupAnnotations,
|
11
|
+
T_GroupType,
|
12
|
+
annotation,
|
13
|
+
get_annotations,
|
14
|
+
get_class_annotations,
|
15
|
+
)
|
16
|
+
|
17
|
+
__all__ = [
|
18
|
+
"annotation",
|
19
|
+
"DecoratorType",
|
20
|
+
"AnnotationsContainer",
|
21
|
+
"get_annotations",
|
22
|
+
"get_class_annotations",
|
23
|
+
"GroupAnnotations",
|
24
|
+
"T_GroupType",
|
25
|
+
]
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# type: ignore
|
2
|
+
from __future__ import annotations
|
3
|
+
|
4
|
+
from collections import defaultdict
|
5
|
+
from collections.abc import Callable
|
6
|
+
from functools import cache
|
7
|
+
from typing import Any, Generic, ParamSpec, TypeVar
|
8
|
+
from typing import NamedTuple as tNamedTuple
|
9
|
+
|
10
|
+
from typing_extensions import NamedTuple
|
11
|
+
|
12
|
+
T_GroupType = TypeVar("T_GroupType", bound=NamedTuple)
|
13
|
+
|
14
|
+
|
15
|
+
class GroupAnnotations(NamedTuple, Generic[T_GroupType]):
|
16
|
+
"""The list of T_GroupType objects identified by a given name in a namespace."""
|
17
|
+
|
18
|
+
name: str
|
19
|
+
"""The name of the annotation, typically the name of the function in a class"""
|
20
|
+
namespace: str
|
21
|
+
"""All the groups in a namespace are expected to be of the same T_GroupType."""
|
22
|
+
groups: tuple[T_GroupType, ...]
|
23
|
+
|
24
|
+
|
25
|
+
class AnnotationsContainer(NamedTuple):
|
26
|
+
"""
|
27
|
+
Holds metadata about the annotated service provider.
|
28
|
+
|
29
|
+
Loosely inspired by: https://peps.python.org/pep-3107/.
|
30
|
+
"""
|
31
|
+
|
32
|
+
annotations: tuple[GroupAnnotations[...], ...]
|
33
|
+
|
34
|
+
@staticmethod
|
35
|
+
def empty() -> AnnotationsContainer:
|
36
|
+
return AnnotationsContainer(annotations=())
|
37
|
+
|
38
|
+
def with_group(
|
39
|
+
self,
|
40
|
+
namespace: str,
|
41
|
+
group_id: T_GroupType,
|
42
|
+
) -> AnnotationsContainer:
|
43
|
+
return AnnotationsContainer(
|
44
|
+
annotations=tuple(
|
45
|
+
[
|
46
|
+
annotation_group
|
47
|
+
for x in self.with_namespace(namespace)
|
48
|
+
for annotation_group in x
|
49
|
+
if group_id in annotation_group.groups
|
50
|
+
]
|
51
|
+
),
|
52
|
+
)
|
53
|
+
|
54
|
+
def with_namespace(
|
55
|
+
self,
|
56
|
+
namespace: str,
|
57
|
+
) -> AnnotationsContainer:
|
58
|
+
return AnnotationsContainer(
|
59
|
+
annotations=tuple([x for x in self.annotations if x.namespace == namespace]),
|
60
|
+
)
|
61
|
+
|
62
|
+
|
63
|
+
class AnnotationsBuilder:
|
64
|
+
_group_ids: dict[str, set[Any]]
|
65
|
+
|
66
|
+
def __init__(self) -> None:
|
67
|
+
self._group_ids = defaultdict(set)
|
68
|
+
|
69
|
+
def add(self, namespace: str, group_id: NamedTuple | tNamedTuple) -> None:
|
70
|
+
self._group_ids[namespace].add(group_id)
|
71
|
+
|
72
|
+
def make(self, name: str) -> AnnotationsContainer:
|
73
|
+
return AnnotationsContainer(
|
74
|
+
annotations=tuple(
|
75
|
+
[
|
76
|
+
GroupAnnotations[Any](name=name, namespace=namespace, groups=tuple(groups))
|
77
|
+
for namespace, groups in self._group_ids.items()
|
78
|
+
]
|
79
|
+
),
|
80
|
+
)
|
81
|
+
|
82
|
+
|
83
|
+
DecoratorType = TypeVar("DecoratorType", bound=Callable[..., Any])
|
84
|
+
|
85
|
+
|
86
|
+
def annotation(
|
87
|
+
namespace: str,
|
88
|
+
group_id: NamedTuple | tNamedTuple,
|
89
|
+
) -> Callable[[DecoratorType], DecoratorType]:
|
90
|
+
def decorator(fn: DecoratorType) -> DecoratorType:
|
91
|
+
if not hasattr(fn, "__rats_annotations__"):
|
92
|
+
fn.__rats_annotations__ = AnnotationsBuilder() # type: ignore[reportFunctionMemberAccess]
|
93
|
+
|
94
|
+
fn.__rats_annotations__.add(namespace, group_id) # type: ignore[reportFunctionMemberAccess]
|
95
|
+
|
96
|
+
return fn
|
97
|
+
|
98
|
+
return decorator
|
99
|
+
|
100
|
+
|
101
|
+
@cache
|
102
|
+
def get_class_annotations(cls: type) -> AnnotationsContainer:
|
103
|
+
tates = []
|
104
|
+
|
105
|
+
for method_name in dir(cls):
|
106
|
+
method = getattr(cls, method_name)
|
107
|
+
if not hasattr(method, "__rats_annotations__"):
|
108
|
+
continue
|
109
|
+
|
110
|
+
tates.extend(method.__rats_annotations__.make(method_name).annotations)
|
111
|
+
|
112
|
+
return AnnotationsContainer(annotations=tuple(tates))
|
113
|
+
|
114
|
+
|
115
|
+
P = ParamSpec("P")
|
116
|
+
|
117
|
+
|
118
|
+
def get_annotations(fn: Callable[..., Any]) -> AnnotationsContainer:
|
119
|
+
builder: AnnotationsBuilder = getattr(
|
120
|
+
fn,
|
121
|
+
"__rats_annotations__",
|
122
|
+
AnnotationsBuilder(),
|
123
|
+
)
|
124
|
+
|
125
|
+
return builder.make(fn.__name__)
|
File without changes
|
rats/apps/__init__.py
CHANGED
@@ -18,11 +18,18 @@ from ._annotations import (
|
|
18
18
|
service,
|
19
19
|
)
|
20
20
|
from ._composite_container import CompositeContainer
|
21
|
-
from ._container import
|
21
|
+
from ._container import (
|
22
|
+
ConfigProvider,
|
23
|
+
Container,
|
24
|
+
DuplicateServiceError,
|
25
|
+
ServiceNotFoundError,
|
26
|
+
ServiceProvider,
|
27
|
+
)
|
22
28
|
from ._executables import App, AppContainer, Executable
|
23
29
|
from ._ids import ConfigId, ServiceId
|
24
30
|
from ._namespaces import ProviderNamespaces
|
25
31
|
from ._plugin_container import PluginContainers
|
32
|
+
from ._plugins import PluginRunner
|
26
33
|
from ._scoping import autoscope
|
27
34
|
|
28
35
|
__all__ = [
|
@@ -36,12 +43,15 @@ __all__ = [
|
|
36
43
|
"Executable",
|
37
44
|
"PluginContainers",
|
38
45
|
"ProviderNamespaces",
|
46
|
+
"ConfigProvider",
|
47
|
+
"ServiceProvider",
|
39
48
|
"ServiceId",
|
40
49
|
"ServiceNotFoundError",
|
41
50
|
"autoid_service",
|
42
51
|
"autoscope",
|
43
52
|
"config",
|
44
53
|
"container",
|
54
|
+
"PluginRunner",
|
45
55
|
"fallback_config",
|
46
56
|
"fallback_group",
|
47
57
|
"fallback_service",
|
rats/apps/_annotations.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import abc
|
1
2
|
from collections import defaultdict
|
2
3
|
from collections.abc import Callable, Iterator
|
3
4
|
from functools import cache
|
@@ -70,7 +71,7 @@ class FunctionAnnotationsBuilder:
|
|
70
71
|
)
|
71
72
|
|
72
73
|
|
73
|
-
class AnnotatedContainer(Container):
|
74
|
+
class AnnotatedContainer(Container, abc.ABC):
|
74
75
|
def get_namespaced_group(
|
75
76
|
self,
|
76
77
|
namespace: str,
|
rats/apps/_plugins.py
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
from collections.abc import Callable, Iterator
|
2
|
+
from typing import Generic, TypeVar
|
3
|
+
|
4
|
+
T_PluginType = TypeVar("T_PluginType")
|
5
|
+
|
6
|
+
|
7
|
+
class PluginRunner(Generic[T_PluginType]):
|
8
|
+
"""Client to apply a function to a list of plugins."""
|
9
|
+
|
10
|
+
_plugins: Iterator[T_PluginType]
|
11
|
+
|
12
|
+
def __init__(self, plugins: Iterator[T_PluginType]) -> None:
|
13
|
+
self._plugins = plugins
|
14
|
+
|
15
|
+
def apply(self, handler: Callable[[T_PluginType], None]) -> None:
|
16
|
+
for plugin in self._plugins:
|
17
|
+
handler(plugin)
|
rats/cli/__init__.py
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
"""Uses `rats.annotations` to streamline the creation of CLI commands written with Click."""
|
2
|
+
|
3
|
+
from ._annotations import CommandId, command, group
|
4
|
+
from ._click import ClickCommandGroup, ClickCommandMapper
|
5
|
+
from ._executable import ClickExecutable
|
6
|
+
from ._plugins import AttachClickCommands, AttachClickGroup, ClickGroupPlugin, CommandContainer
|
7
|
+
|
8
|
+
__all__ = [
|
9
|
+
"CommandId",
|
10
|
+
"command",
|
11
|
+
"group",
|
12
|
+
"ClickCommandMapper",
|
13
|
+
"ClickExecutable",
|
14
|
+
"ClickGroupPlugin",
|
15
|
+
"ClickCommandGroup",
|
16
|
+
"AttachClickCommands",
|
17
|
+
"AttachClickGroup",
|
18
|
+
"CommandContainer",
|
19
|
+
]
|
rats/cli/_annotations.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Callable
|
4
|
+
from typing import Any, NamedTuple, TypeVar
|
5
|
+
|
6
|
+
from rats import annotations as anns
|
7
|
+
|
8
|
+
|
9
|
+
class CommandId(NamedTuple):
|
10
|
+
name: str
|
11
|
+
|
12
|
+
# does this api make it impossible to reference a given command that was auto generated?
|
13
|
+
@staticmethod
|
14
|
+
def auto() -> CommandId:
|
15
|
+
return CommandId(name=f"{__name__}:auto")
|
16
|
+
|
17
|
+
|
18
|
+
T = TypeVar("T", bound=Callable[[Any], Any])
|
19
|
+
|
20
|
+
|
21
|
+
def command(command_id: CommandId) -> Callable[[T], T]:
|
22
|
+
def decorator(fn: T) -> T:
|
23
|
+
if command_id == CommandId.auto():
|
24
|
+
return anns.annotation("commands", CommandId(fn.__name__.replace("_", "-")))(fn)
|
25
|
+
return anns.annotation("commands", command_id)(fn)
|
26
|
+
|
27
|
+
return decorator
|
28
|
+
|
29
|
+
|
30
|
+
def group(command_id: CommandId) -> Callable[[T], T]:
|
31
|
+
def decorator(fn: T) -> T:
|
32
|
+
if command_id == CommandId.auto():
|
33
|
+
return anns.annotation("command-groups", CommandId(fn.__name__.replace("_", "-")))(fn)
|
34
|
+
return anns.annotation("commands", command_id)(fn)
|
35
|
+
|
36
|
+
return decorator
|
37
|
+
|
38
|
+
|
39
|
+
def get_class_commands(cls: type) -> anns.AnnotationsContainer:
|
40
|
+
return anns.get_class_annotations(cls).with_namespace("commands")
|
rats/cli/_click.py
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
from collections.abc import Callable, Mapping
|
2
|
+
from typing import final
|
3
|
+
|
4
|
+
import click
|
5
|
+
|
6
|
+
|
7
|
+
class ClickCommandMapper:
|
8
|
+
_commands: Mapping[str, Callable[[], click.Command]]
|
9
|
+
|
10
|
+
def __init__(
|
11
|
+
self,
|
12
|
+
commands: Mapping[str, Callable[[], click.Command]],
|
13
|
+
) -> None:
|
14
|
+
self._commands = commands
|
15
|
+
|
16
|
+
def names(self) -> frozenset[str]:
|
17
|
+
return frozenset(self._commands.keys())
|
18
|
+
|
19
|
+
def get(self, name: str) -> click.Command:
|
20
|
+
if name not in self._commands:
|
21
|
+
raise ValueError(f"Command {name} not found")
|
22
|
+
|
23
|
+
return self._commands[name]()
|
24
|
+
|
25
|
+
|
26
|
+
@final
|
27
|
+
class ClickCommandGroup(click.Group):
|
28
|
+
_mapper: ClickCommandMapper
|
29
|
+
|
30
|
+
def __init__(self, name: str, mapper: ClickCommandMapper) -> None:
|
31
|
+
super().__init__(name=name)
|
32
|
+
self._mapper = mapper
|
33
|
+
|
34
|
+
def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command | None:
|
35
|
+
return self._mapper.get(cmd_name)
|
36
|
+
|
37
|
+
def list_commands(self, ctx: click.Context) -> list[str]:
|
38
|
+
return list(self._mapper.names())
|
rats/cli/_executable.py
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from rats import apps
|
4
|
+
|
5
|
+
from ._plugins import ClickGroupPlugin
|
6
|
+
|
7
|
+
|
8
|
+
class ClickExecutable(apps.Executable):
|
9
|
+
_command: apps.ServiceProvider[click.Group]
|
10
|
+
_plugins: apps.PluginRunner[ClickGroupPlugin]
|
11
|
+
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
command: apps.ServiceProvider[click.Group],
|
15
|
+
plugins: apps.PluginRunner[ClickGroupPlugin],
|
16
|
+
) -> None:
|
17
|
+
self._command = command
|
18
|
+
self._plugins = plugins
|
19
|
+
|
20
|
+
def execute(self) -> None:
|
21
|
+
cmd = self._command()
|
22
|
+
self._plugins.apply(lambda plugin: plugin.on_group_open(cmd))
|
23
|
+
cmd()
|
rats/cli/_plugins.py
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from abc import abstractmethod
|
4
|
+
from collections.abc import Callable, Iterator
|
5
|
+
from functools import partial
|
6
|
+
from typing import Any, Protocol
|
7
|
+
|
8
|
+
import click
|
9
|
+
|
10
|
+
from rats import apps
|
11
|
+
|
12
|
+
from ._annotations import get_class_commands
|
13
|
+
|
14
|
+
|
15
|
+
class ClickGroupPlugin(Protocol):
|
16
|
+
@abstractmethod
|
17
|
+
def on_group_open(self, group: click.Group) -> None:
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class AttachClickCommands(ClickGroupPlugin):
|
22
|
+
"""When a group is opened, attach a set of commands to it."""
|
23
|
+
|
24
|
+
_commands: Iterator[click.Command]
|
25
|
+
|
26
|
+
def __init__(self, commands: Iterator[click.Command]) -> None:
|
27
|
+
self._commands = commands
|
28
|
+
|
29
|
+
def on_group_open(self, group: click.Group) -> None:
|
30
|
+
for command in self._commands:
|
31
|
+
group.add_command(command)
|
32
|
+
|
33
|
+
|
34
|
+
class AttachClickGroup(ClickGroupPlugin):
|
35
|
+
_group: apps.ServiceProvider[click.Group]
|
36
|
+
_plugins: apps.PluginRunner[ClickGroupPlugin]
|
37
|
+
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
group: apps.ServiceProvider[click.Group],
|
41
|
+
plugins: apps.PluginRunner[ClickGroupPlugin],
|
42
|
+
) -> None:
|
43
|
+
self._group = group
|
44
|
+
self._plugins = plugins
|
45
|
+
|
46
|
+
def on_group_open(self, group: click.Group) -> None:
|
47
|
+
cmd = self._group()
|
48
|
+
self._plugins.apply(lambda plugin: plugin.on_group_open(cmd))
|
49
|
+
group.add_command(cmd)
|
50
|
+
|
51
|
+
|
52
|
+
class CommandContainer(ClickGroupPlugin):
|
53
|
+
def on_group_open(self, group: click.Group) -> None:
|
54
|
+
def cb(_method: Callable[[Any], Any], *args: Any, **kwargs: Any) -> None:
|
55
|
+
"""
|
56
|
+
Callback handed to `click.Command`. Calls the method with matching name on this class.
|
57
|
+
|
58
|
+
When the command is decorated with `@click.params` and `@click.option`, `click` will
|
59
|
+
call this callback with the parameters in the order they were defined. This callback
|
60
|
+
then calls the method with the same name on this class, passing the parameters in
|
61
|
+
reverse order. This is because the method is defined with the parameters in the
|
62
|
+
reverse order to the decorator, so we need to reverse them again to get the correct
|
63
|
+
order.
|
64
|
+
"""
|
65
|
+
_method(*args, **kwargs)
|
66
|
+
|
67
|
+
commands = get_class_commands(type(self))
|
68
|
+
tates = commands.annotations
|
69
|
+
|
70
|
+
for tate in tates:
|
71
|
+
method = getattr(self, tate.name)
|
72
|
+
params = list(reversed(getattr(method, "__click_params__", [])))
|
73
|
+
for command in tate.groups:
|
74
|
+
group.add_command(
|
75
|
+
click.Command(
|
76
|
+
name=command.name,
|
77
|
+
callback=partial(cb, method),
|
78
|
+
short_help=method.__doc__,
|
79
|
+
params=params,
|
80
|
+
)
|
81
|
+
)
|
rats/cli/py.typed
ADDED
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: rats-apps
|
3
|
-
Version: 0.1.3.
|
3
|
+
Version: 0.1.3.dev61
|
4
4
|
Summary: research analysis tools for building applications
|
5
5
|
Home-page: https://github.com/microsoft/rats/
|
6
6
|
License: MIT
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.10
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
|
+
Requires-Dist: click
|
14
15
|
Requires-Dist: typing_extensions
|
15
16
|
Project-URL: Documentation, https://microsoft.github.io/rats/
|
16
17
|
Project-URL: Repository, https://github.com/microsoft/rats/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
rats/annotations/__init__.py,sha256=wsGhRQzZrV2oJTnBAX0aGgpyT1kYT235jkP3Wb8BTRY,498
|
2
|
+
rats/annotations/_functions.py,sha256=r4Y-9fOZ9M0lDpcIv8nMuggEffc2bgZLeubWRj8uj-o,3552
|
3
|
+
rats/annotations/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
rats/apps/__init__.py,sha256=e9RQPGGgm3IG1XZgaK4e2u18-jQ4D9Seo7vpGgwuD0k,1340
|
5
|
+
rats/apps/_annotations.py,sha256=LOuVckzeUmbDWko8tB2HpACc_xdLoldeNJpAgvclf-s,6991
|
6
|
+
rats/apps/_composite_container.py,sha256=wSWVQWPin2xxIlEoSgk_D1rlc3N2gpTxQ2y9UFdqXy0,553
|
7
|
+
rats/apps/_container.py,sha256=5uiCyxN6HS2z97XcTOFP-t72cNoB1U1sJMkMcfSfDps,3129
|
8
|
+
rats/apps/_executables.py,sha256=8ITn__pjTLHo7FEb-3C6ZQrs1mow0gZn6d-24XGBSu8,1079
|
9
|
+
rats/apps/_ids.py,sha256=dxWCPMpMA_vpaTDJEKNByIBJaX97Db203XqWLhaOezo,457
|
10
|
+
rats/apps/_namespaces.py,sha256=THUV_Xj5PtweC23Ob-zsSpk8exC4fT-qRwjpQ6IDm0U,188
|
11
|
+
rats/apps/_plugin_container.py,sha256=W_xQD2btc0N2dEb3c5tXM-ZZ4A4diMpkCjbOZdlXYuI,853
|
12
|
+
rats/apps/_plugins.py,sha256=i1K5dCRC9cRA5QLiIdVUDJNM2rG935fdvqSTAK49h38,499
|
13
|
+
rats/apps/_scoping.py,sha256=plSVEq3rJ8JFAu2epVg2NQpuTbpSTA3a0Tha_DwJL_Y,1453
|
14
|
+
rats/apps/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
rats/cli/__init__.py,sha256=LJe3zGI4IH2Siti4kQjqHOrxygv03g3hDE7jwpfYS9E,574
|
16
|
+
rats/cli/_annotations.py,sha256=0dI8hu_y754Y53Pka1-mGEgHjjVcnIOGd8l1SFx8OBY,1190
|
17
|
+
rats/cli/_click.py,sha256=7-ClnYSW4poFr_B-Q6NT45DnMF1XL7ntUgwQqQ7q_eo,1036
|
18
|
+
rats/cli/_executable.py,sha256=kAQ9hImv3hBaScu6e19o_BMvl7tdYJql38E76S3FjSk,580
|
19
|
+
rats/cli/_plugins.py,sha256=H3-QdaICPJhCC5FkLHdXpwqe7Z0mpvsenakhNiPllC8,2739
|
20
|
+
rats/cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
+
rats_apps-0.1.3.dev61.dist-info/METADATA,sha256=GLcGzRGdgw0MV60a6Xf8fTw7ISdM2c8sPaTGQAqFwPQ,738
|
22
|
+
rats_apps-0.1.3.dev61.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
23
|
+
rats_apps-0.1.3.dev61.dist-info/RECORD,,
|
@@ -1,13 +0,0 @@
|
|
1
|
-
rats/apps/__init__.py,sha256=C2AHnjIf0Bf4gnrS4sO0QSEknIQXfn3X9qzknY7t9PE,1182
|
2
|
-
rats/apps/_annotations.py,sha256=MMYqJ0F6MzynwOT3ZWKiIkXwQsaD4rvkpkURP4EzZDE,6971
|
3
|
-
rats/apps/_composite_container.py,sha256=wSWVQWPin2xxIlEoSgk_D1rlc3N2gpTxQ2y9UFdqXy0,553
|
4
|
-
rats/apps/_container.py,sha256=5uiCyxN6HS2z97XcTOFP-t72cNoB1U1sJMkMcfSfDps,3129
|
5
|
-
rats/apps/_executables.py,sha256=8ITn__pjTLHo7FEb-3C6ZQrs1mow0gZn6d-24XGBSu8,1079
|
6
|
-
rats/apps/_ids.py,sha256=dxWCPMpMA_vpaTDJEKNByIBJaX97Db203XqWLhaOezo,457
|
7
|
-
rats/apps/_namespaces.py,sha256=THUV_Xj5PtweC23Ob-zsSpk8exC4fT-qRwjpQ6IDm0U,188
|
8
|
-
rats/apps/_plugin_container.py,sha256=W_xQD2btc0N2dEb3c5tXM-ZZ4A4diMpkCjbOZdlXYuI,853
|
9
|
-
rats/apps/_scoping.py,sha256=plSVEq3rJ8JFAu2epVg2NQpuTbpSTA3a0Tha_DwJL_Y,1453
|
10
|
-
rats/apps/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
rats_apps-0.1.3.dev57.dist-info/METADATA,sha256=bgRy1FMGYZLaVhqM2rsEvIVRwk19VDaRtHvLBSITn4s,717
|
12
|
-
rats_apps-0.1.3.dev57.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
13
|
-
rats_apps-0.1.3.dev57.dist-info/RECORD,,
|
File without changes
|