rats-apps 0.11.0.dev20250521180658__py3-none-any.whl → 0.11.1__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.
@@ -53,11 +53,7 @@ This is the companion type to [rats.apps.ContainerPlugin][].
53
53
 
54
54
  ContainerPlugin = _ContainerPluginType | Callable[[Container], Container]
55
55
  """
56
- Main interface for a function that returns an [rats.apps.Container][] instance.
57
-
58
- Containers that implement this type—for example, by using the [rats.apps.PluginMixin][] mixin—can
59
- be used easily in functions that need to defer the construction of an application container. See
60
- [rats.apps.AppBundle][] for additional examples.
56
+ Factory function protocol that returns an [rats.apps.Container][] instance.
61
57
  """
62
58
 
63
59
 
@@ -155,7 +151,7 @@ class AppBundle(AppContainer):
155
151
  context: Container = EMPTY_CONTEXT,
156
152
  ):
157
153
  """
158
- Create an instance by providing the [rats.apps.AppPlugin] type and any additional context.
154
+ Create an instance by providing the [rats.apps.AppPlugin][] type and any additional context.
159
155
 
160
156
  Example:
161
157
  ```python
@@ -164,17 +160,22 @@ class AppBundle(AppContainer):
164
160
 
165
161
  class ExamplePlugin(apps.Container, apps.PluginMixin):
166
162
  @apps.service(apps.ServiceId[str]("some-value"))
167
- def _some_value() -> str:
163
+ def _some_value(self) -> str:
168
164
  return "hello, world!"
169
165
 
170
166
 
171
167
  class ExampleApplication(apps.AppContainer, apps.PluginMixin):
172
- def execute() -> None:
168
+ def execute(self) -> None:
173
169
  print(self._app.get(apps.ServiceId[str]("some-value")))
174
170
 
175
171
 
176
172
  if __name__ == "__main__":
177
- apps.run(apps.AppBundle(ExampleApplication, ExamplePlugin))
173
+ apps.run(
174
+ apps.AppBundle(
175
+ app_plugin=ExampleApplication,
176
+ container_plugin=ExamplePlugin,
177
+ )
178
+ )
178
179
  ```
179
180
 
180
181
  Args:
rats/apps/_container.py CHANGED
@@ -108,7 +108,6 @@ class Container(Protocol):
108
108
  """Retrieve a service group by its id."""
109
109
  if not self.has_namespace(ProviderNamespaces.GROUPS, group_id):
110
110
  # groups are expected to return iterable services
111
- # TODO: we need to clean up the meaning of groups and services somehow
112
111
  for i in self.get_namespaced_group(ProviderNamespaces.FALLBACK_GROUPS, group_id):
113
112
  yield from cast(Iterator[T_ServiceType], i)
114
113
 
@@ -151,7 +150,14 @@ def _get_cached_services_for_group(
151
150
 
152
151
  for provider in info_cache[(namespace, group_id)]:
153
152
  if provider not in provider_cache:
154
- provider_cache[provider] = getattr(c, provider.attr)()
153
+ if namespace in [
154
+ ProviderNamespaces.CONTAINERS,
155
+ ProviderNamespaces.SERVICES,
156
+ ProviderNamespaces.FALLBACK_SERVICES,
157
+ ]:
158
+ provider_cache[provider] = getattr(c, provider.attr)()
159
+ else:
160
+ provider_cache[provider] = list(getattr(c, provider.attr)())
155
161
 
156
162
  yield provider_cache[provider]
157
163
 
rats/cli/_container.py CHANGED
@@ -55,11 +55,11 @@ class Container(Protocol):
55
55
 
56
56
  commands = get_class_commands(type(self))
57
57
  tates = commands.annotations
58
+ logger.debug(f"[{type(self)}] commands: {tates}")
58
59
 
59
60
  for tate in tates:
60
61
  method = getattr(self, tate.name)
61
62
  params = list(reversed(getattr(method, "__click_params__", [])))
62
- logger.debug(tate.namespace)
63
63
  for command in tate.groups:
64
64
  if tate.namespace == "commands":
65
65
  group.add_command(
rats/logs/__init__.py CHANGED
@@ -7,16 +7,62 @@ handle configuring the python logging libraries, with a few configuration option
7
7
  !!! warning
8
8
  We expose the logging functionality through a [rats.apps.AppContainer][] in order to leverage
9
9
  the built in plugin system to give users the ability to adjust the default settings, but this
10
- entire application should be lightweight and should not contain very complex logic, avoiding
11
- logic that is very time consuming or has a chance of failing with confusing errors.
10
+ application should be lightweight and should not contain very complex logic, avoiding logic
11
+ that is very time consuming or has a chance of failing with confusing errors.
12
+
13
+ ## Verbosity Env Variables
14
+
15
+ To help develop modules, logging output can be configured with the `DEBUG_LOGS_*`, `QUIET_LOGS_*`,
16
+ and `LEVEL_LOGS_*` environment variables. The suffix of the environment variables match the module
17
+ name wanting to be configured.
18
+
19
+ ### Module Loggers
20
+
21
+ Environment variables named `DEBUG_LOGS_*` cause logs from the given module to be shown; the
22
+ `QUIET_LOGS_*` environment variables silence logs emitted by the module; and `LEVEL_LOGS_*` allows
23
+ a specific [logging-level](https://docs.python.org/3/library/logging.html#logging-levels) to be
24
+ used.
25
+
26
+ ```
27
+ $ rats-ci fix
28
+ All checks passed!
29
+ 63 files left unchanged
30
+ ran 2 fix commands
31
+ ```
32
+
33
+ ```bash
34
+ # Enable DEBUG level logs for the `rats.*` modules
35
+ export DEBUG_LOGS_RATS="1"
36
+ # Enable WARNING level logs for the `rats.projects.*` modules
37
+ export LEVEL_LOGS_RATS_PROJECTS="WARNING"
38
+ # Disable logs for `rats.cli.*` modules
39
+ export QUIET_LOGS_RATS_CLI="1"
40
+ ```
41
+ ```
42
+ $ rats-ci fix
43
+ 2025-05-27 00:49:45 DEBUG [rats.logs._app:96]: done configuring logging
44
+ All checks passed!
45
+ 63 files left unchanged
46
+ ran 2 fix commands
47
+ ```
48
+
49
+ ### Root Logger
50
+
51
+ The root logger can be configured with the `DEBUG_LOGS`, `QUIET_LOGS`, and `LEVEL_LOGS` environment
52
+ variables.
53
+
54
+ ```bash
55
+ # Enable WARNING level logs for all logs
56
+ export LEVEL_LOGS="WARNING"
57
+ ```
12
58
 
13
- If the logging options made available through this module are far from what is desired, instead
14
- of adding flags and options to this module, we recommend configuring logging in your own code.
15
59
  """
16
60
 
17
61
  from ._app import AppConfigs, ConfigureApplication
62
+ from ._showwarning import showwarning
18
63
 
19
64
  __all__ = [
20
65
  "AppConfigs",
21
66
  "ConfigureApplication",
67
+ "showwarning",
22
68
  ]
rats/logs/_app.py CHANGED
@@ -1,10 +1,13 @@
1
1
  import logging.config
2
+ import os
2
3
  import warnings
3
4
  from collections.abc import Iterator
4
5
  from typing import Any
5
6
 
6
7
  from rats import apps
7
8
 
9
+ from ._showwarning import showwarning
10
+
8
11
  logger = logging.getLogger(__name__)
9
12
  LoggerConfigEntry = tuple[str, dict[str, Any]]
10
13
 
@@ -61,12 +64,12 @@ class ConfigureApplication(apps.AppContainer, apps.PluginMixin):
61
64
  "colored": {
62
65
  "()": "colorlog.ColoredFormatter",
63
66
  "format": (
64
- "%(log_color)s%(asctime)s %(levelname)-8s [%(name)s][%(lineno)d]: "
67
+ "%(log_color)s%(asctime)s %(levelname)-8s [%(name)s:%(lineno)d]: "
65
68
  "%(message)s%(reset)s"
66
69
  ),
67
70
  "datefmt": "%Y-%m-%d %H:%M:%S",
68
71
  "log_colors": {
69
- "DEBUG": "white",
72
+ "DEBUG": "cyan",
70
73
  "INFO": "green",
71
74
  "WARNING": "yellow",
72
75
  "ERROR": "red,",
@@ -88,9 +91,65 @@ class ConfigureApplication(apps.AppContainer, apps.PluginMixin):
88
91
  # enable deprecation warnings by default
89
92
  logging.captureWarnings(True)
90
93
  warnings.simplefilter("default", DeprecationWarning)
94
+ # our modified `showwarning` method logs warnings with the module logger that emitted it
95
+ warnings.showwarning = showwarning
91
96
  logger.debug("done configuring logging")
92
97
 
93
98
  @apps.fallback_group(AppConfigs.LOGGERS)
94
99
  def _default_loggers(self) -> Iterator[LoggerConfigEntry]:
95
- yield "", {"level": "INFO", "handlers": ["console"]}
96
- yield "azure", {"level": "WARNING", "handlers": ["console"]}
100
+ logger_mapping = {
101
+ "": "INFO",
102
+ "azure": "WARNING",
103
+ "py.warnings": "CRITICAL",
104
+ }
105
+ searched_prefixes = [
106
+ "DEBUG_LOGS",
107
+ "QUIET_LOGS",
108
+ "LEVEL_LOGS",
109
+ ]
110
+ for name in os.environ.keys():
111
+ env_prefix = name[0:10]
112
+ if env_prefix not in searched_prefixes:
113
+ # this isn't a logging config env
114
+ continue
115
+
116
+ # our above prefixes are conveniently all 10 characters
117
+ # everything after the prefix is the logger name, skip the underscore after the prefix
118
+ logger_name = name.lower()[11:].replace("_", ".")
119
+ if logger_name not in logger_mapping:
120
+ # the default here is ignored
121
+ logger_mapping[logger_name] = "INFO"
122
+
123
+ for name, default in logger_mapping.items():
124
+ yield self._build_logger_entry(name, default)
125
+
126
+ def _build_logger_entry(self, name: str, default: str = "INFO") -> LoggerConfigEntry:
127
+ # https://docs.python.org/3/library/logging.html#logging-levels
128
+ valid_levels = [
129
+ "NOTSET",
130
+ "DEBUG",
131
+ "INFO",
132
+ "WARNING",
133
+ "ERROR",
134
+ "CRITICAL",
135
+ ]
136
+ suffix = f"_{'_'.join(name.split('.')).upper()}" if name != "" else ""
137
+
138
+ debug_env_name = f"DEBUG_LOGS{suffix}"
139
+ quiet_env_name = f"QUIET_LOGS{suffix}"
140
+ level_env_name = f"LEVEL_LOGS{suffix}"
141
+ if os.environ.get(level_env_name):
142
+ # user specified exactly what log level is wanted for this module
143
+ lvl = os.environ[level_env_name].upper()
144
+ if lvl not in valid_levels:
145
+ raise ValueError(f"invalid log level specified: {level_env_name}={lvl}")
146
+ return name, {"level": lvl, "handlers": ["console"], "propagate": False}
147
+ elif os.environ.get(debug_env_name):
148
+ # show as many logs as possible
149
+ return name, {"level": "DEBUG", "handlers": ["console"], "propagate": False}
150
+ elif os.environ.get(quiet_env_name):
151
+ # only show critical logs when QUIET_LOGS is enabled
152
+ return name, {"level": "CRITICAL", "handlers": ["console"], "propagate": False}
153
+ else:
154
+ # set default logging to INFO
155
+ return name, {"level": default, "handlers": ["console"], "propagate": False}
@@ -0,0 +1,51 @@
1
+ import logging
2
+ import sys
3
+ import warnings
4
+ from pathlib import Path
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ def showwarning(
10
+ message: Warning | str,
11
+ category: type[Warning],
12
+ filename: str,
13
+ lineno: int,
14
+ file: str | None = None,
15
+ line: str | None = None,
16
+ ) -> None:
17
+ """
18
+ Handler that logs warnings using the module logger from the module that emitted the warning.
19
+
20
+ ```python
21
+ import warnings
22
+ from rats.logs import showwarning
23
+
24
+ warnings.showwarning = showwarning
25
+ warnings.warn("This is a custom warning", UserWarning)
26
+ ```
27
+
28
+ Args:
29
+ message: The warning message instance or string.
30
+ category: The category of the warning (e.g., [DeprecationWarning][], [UserWarning][]).
31
+ filename: The path to the file where the warning originated.
32
+ lineno: The line number in the file where the warning originated.
33
+ file: Ignored. Included for compatibility with the standard warnings.showwarning signature.
34
+ line: The line of source code to be included in the warning message, if available.
35
+ """
36
+ if file is not None:
37
+ raise ValueError(file)
38
+
39
+ formatted_message = warnings.formatwarning(message, category, filename, lineno, line)
40
+
41
+ for _module_name, module in sys.modules.items():
42
+ module_path = getattr(module, "__file__", None)
43
+ if module_path and Path(filename).is_file() and Path(module_path).samefile(filename):
44
+ module_name = _module_name
45
+ break
46
+ else:
47
+ # unsure what module to use, but we can default to "py.warnings" like the original handler
48
+ module_name = "py.warnings"
49
+
50
+ source_logger = logging.getLogger(module_name)
51
+ source_logger.warning(formatted_message)
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.3
2
+ Name: rats-apps
3
+ Version: 0.11.1
4
+ Summary: research analysis tools for building applications
5
+ License: MIT
6
+ Keywords: pipelines,machine learning,research
7
+ Author: Elon Portugaly
8
+ Author-email: elonp@microsoft.com
9
+ Requires-Python: >=3.10,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: click
17
+ Requires-Dist: colorlog
18
+ Requires-Dist: dataclass-wizard
19
+ Requires-Dist: pyyaml
20
+ Requires-Dist: typing-extensions
21
+ Project-URL: Documentation, https://microsoft.github.io/rats
22
+ Project-URL: Repository, https://github.com/microsoft/rats
23
+ Description-Content-Type: text/markdown
24
+
25
+ ---
26
+ title: introduction
27
+ ---
28
+
29
+ The `rats-apps` package helps create applications; a small set of modules that eliminate the most
30
+ common boilerplate code when creating applications of any kind. We do this mainly by providing a
31
+ set of libraries to define service containers, and using the service containers to hide the
32
+ complexity of creating services–like authentication, storage, or database clients–from other parts
33
+ of the system, allowing developers to focus on the business logic of the application. Often referred
34
+ to as [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection), we use our
35
+ service containers to separate the concerns of constructing objects and using them.
36
+
37
+ ## Installation
38
+
39
+ Use `pip` or your favorite packaging tool to install the package from PyPI.
40
+
41
+ ```bash
42
+ pip install rats-apps
43
+ ```
44
+
45
+ ## What is an application?
46
+
47
+ Let's start with a standard python script, and slowly migrate it to be a rats application in order
48
+ to explain a few main details. Creating a `__main__.py` file in a package makes it executable.
49
+ After the common python boilerplate code is added, this is typically what we find in the wild:
50
+
51
+ === ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
52
+ ```python
53
+ def main() -> None:
54
+ print("hello, world")
55
+
56
+
57
+ if __name__ == "__main__":
58
+ main()
59
+ ```
60
+
61
+ === ":material-console: ~/code"
62
+ ```bash
63
+ python -m foo
64
+ ```
65
+
66
+ Using this pattern, we can define our application with a small modification, turning our `main()`
67
+ function into a runnable rats application, and then running it:
68
+
69
+ === ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
70
+ ```python
71
+ from rats import apps
72
+
73
+
74
+ def main() -> None:
75
+ print("hello, world")
76
+
77
+
78
+ if __name__ == "__main__":
79
+ apps.run(apps.App(main))
80
+ ```
81
+
82
+ !!! info
83
+ The [rats.apps.App][] class is used to quickly turn a script entry point–`Callable[[], None]`
84
+ –into an object with an `execute()` method, defined by our [rats.apps.Executable][]
85
+ interface.
86
+
87
+ ## Application Containers & Plugins
88
+
89
+ We can start to leverage [rats.apps][] to make our application easy to extend. Let's replace our use
90
+ of the [rats.apps.App][] wrapper and move our `main()` function into a class. Using the
91
+ [rats.apps.AppContainer][] and [rats.apps.PluginMixin][] classes, we finish adapting our example
92
+ to be a rats application.
93
+
94
+ === ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
95
+
96
+ ```python
97
+ from rats import apps
98
+
99
+
100
+ class Application(apps.AppContainer, apps.PluginMixin):
101
+ def execute() -> None:
102
+ print("hello, world")
103
+
104
+
105
+ if __name__ == "__main__":
106
+ apps.run_plugin(Application)
107
+ ```
108
+
109
+ !!! info
110
+ If you're making these changes to an existing code base, you should be able to run things to
111
+ validate that everything still works as it did before. Your `main()` function is now in
112
+ the `execute()` method of your new `Application` class, but none of the behavior of your
113
+ application should have been affected.
114
+
115
+ Now that we have a fully defined rats application; we can use [rats.apps.Container][] instances to
116
+ make services available to our application while remaining decoupled from the details of how these
117
+ services are initialized. A common use case for this is to give our team access to the azure
118
+ storage clients without needing to specify the authentication details; allowing us to ensure our
119
+ application is functional in many compute environments.
120
+
121
+ === ":material-language-python: ~/code/src/foo/\_\_init\_\_.py"
122
+
123
+ ```python
124
+ from ._plugin import PluginContainer
125
+
126
+ __all__ = ["PluginContainer"]
127
+ ```
128
+
129
+ === ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
130
+
131
+ ```python
132
+ from rats import apps
133
+ import foo
134
+
135
+
136
+ class Application(apps.AppContainer, apps.PluginMixin):
137
+
138
+ def execute() -> None:
139
+ blob_client = self._app.get(foo.BLOB_SERVICE_ID)
140
+ print(f"hello, world. loaded blob client: {blob_client}")
141
+
142
+ @apps.container()
143
+ def _plugins(self) -> apps.Container:
144
+ return foo.PluginContainer(self._app)
145
+
146
+
147
+ if __name__ == "__main__":
148
+ apps.run_plugin(Application)
149
+ ```
150
+
151
+ === ":material-language-python: ~/code/src/foo/_plugin.py"
152
+
153
+ ```python
154
+ from rats import apps
155
+ from azure.storage.blob import BlobServiceClient
156
+
157
+ BLOB_SERVICE_ID = apps.ServiceId[BlobServiceClient]("blob-client")
158
+
159
+
160
+ class PluginContainer(apps.Container, apps.PluginMixin):
161
+
162
+ @apps.service(BLOB_SERVICE_ID)
163
+ def _blob_client(self) -> BlobServiceClient:
164
+ credential = DefaultAzureCredential()
165
+ return BlobServiceClient(
166
+ account_url=f"https://example.blob.core.windows.net/",
167
+ credential=credential,
168
+ )
169
+ ```
170
+
171
+ !!! success
172
+ Following these patterns, we can make services available to others with plugin containers; and
173
+ we can combine these containers to create applications. The [rats.apps][] module has additional
174
+ libraries to help define different types of applications, designed to help your solutions
175
+ evolve as ideas mature. Our first runnable example was a single instance of the
176
+ [rats.apps.AppContainer][] interface with an `execute()` method; but a larger project might
177
+ have a few modules providing different aspects of the application's needs by sharing a set of
178
+ service ids and a plugin container.
179
+
180
+ ## Installable Plugins
181
+
182
+ We use the standard [Entry Points](https://packaging.python.org/en/latest/specifications/entry-points/)
183
+ mechanism to allow authors to make their application extensible. These plugins are instances of
184
+ [rats.apps.Container][] and loaded into applications like our previous examples.
185
+
186
+ === ":material-file-settings: ~/code/pyproject.toml"
187
+ ```toml
188
+ [tool.poetry.plugins."foo.plugins"]
189
+ "foo" = "foo:PluginContainer"
190
+ ```
191
+
192
+ === ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
193
+ ```python
194
+ from rats import apps
195
+ import foo
196
+
197
+
198
+ class Application(apps.AppContainer, apps.PluginMixin):
199
+
200
+ def execute() -> None:
201
+ blob_client = self._app.get(foo.BLOB_SERVICE_ID)
202
+ print(f"hello, world. loaded blob client: {blob_client}")
203
+
204
+ @apps.container()
205
+ def _plugins(self) -> apps.Container:
206
+ return apps.PythonEntryPointContainer("foo.plugins")
207
+
208
+
209
+ if __name__ == "__main__":
210
+ apps.run_plugin(Application)
211
+ ```
212
+
213
+ !!! success
214
+ We used [rats.app] to define an application, and used a service provided by a plugin container
215
+ that is loaded through a python entry point. You can create a script entry in your
216
+ `pyproject.toml` file to expose your application through a terminal command:
217
+
218
+ === ":material-language-python: ~/code/src/foo/\_\_init\_\_.py"
219
+ ```python
220
+ from ._app import Application, main
221
+ from ._plugin import PluginContainer
222
+
223
+
224
+ __all__ = [
225
+ "Application",
226
+ "main",
227
+ "PluginContainer",
228
+ ]
229
+ ```
230
+ === ":material-file-settings: ~/code/pyproject.toml"
231
+ ```toml
232
+ [tool.poetry.plugins."foo.plugins"]
233
+ "foo" = "foo:PluginContainer"
234
+
235
+ [tool.poetry.scripts]
236
+ foo = "foo:main"
237
+ ```
238
+
@@ -9,9 +9,9 @@ rats/app_context/_context.py,sha256=S7D8NLefZJI4MDEpYKdenfNsemus4bUlQCG-gd3U3g8,
9
9
  rats/app_context/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  rats/apps/__init__.py,sha256=6B5qQvzx1xlRrNRY4QJi6GEywuQ1MoW454kC4nO2Yqg,2084
11
11
  rats/apps/_annotations.py,sha256=6M_M7K8haNVda0Tx02EpFf3s9EjnWYacNMjTIkNEdRU,4617
12
- rats/apps/_app_containers.py,sha256=Wen5nMJdhOVa6mGHeEm7paXo1RXsNrgNRUbS0SWd9X0,7026
12
+ rats/apps/_app_containers.py,sha256=1rtq92rOGvCbroQmDgOM24jxxcNNFQHy65fBLO5LIXo,6920
13
13
  rats/apps/_composite_container.py,sha256=FdpmH_xIly6LxNZrA_nZCznukptjVLXttXTMtf_tnv8,695
14
- rats/apps/_container.py,sha256=sYISCG-qVzl-bsBwX_CAWEP9gtXCnG-Jls3l8IKb4DQ,7208
14
+ rats/apps/_container.py,sha256=N8qR0oBLi03xZvPfc8SxaSci0oVYfX_rftzfaBkTSfQ,7415
15
15
  rats/apps/_executables.py,sha256=hXExNmAnuPU1KJXihNw1jEDAQpMlQ9E9_aPV8tpGbOY,1347
16
16
  rats/apps/_ids.py,sha256=T8Onrj79t8NPfBMQBk0xI6fIWDKF0m2JfFNrdtXAbWg,353
17
17
  rats/apps/_mains.py,sha256=2Q97mNk1cBzYROc_pJcm57EEeHmwRbXOWpfYXH37qcA,995
@@ -26,12 +26,13 @@ rats/cli/__main__.py,sha256=WeldAKjA3Kmz9ZRnZVd3G8Ud66Y_gSRDLIPNE1JyhV0,1418
26
26
  rats/cli/_annotations.py,sha256=-B2Y1bYjPbeTNTBMZzMdAU92qu9AyutKHN_NdFy-xhA,2964
27
27
  rats/cli/_click_app.py,sha256=Jvs6OqNC4Yoe6kbc2tCzjzUieNFa1n_zwXPsdo971Wc,1450
28
28
  rats/cli/_command.py,sha256=kyU3UqqF9aiTTaFvlQFBKDLXvArQS1QgjoQqlMbKzok,597
29
- rats/cli/_container.py,sha256=FIQBqi9PTNpE2P52qkfGET51BczdD-JvcWXLTjCNPDI,3512
29
+ rats/cli/_container.py,sha256=BoZLOu-eT4SzweNwMepWHd4PyxQAg--_p-rM7XkQNAA,3529
30
30
  rats/cli/_functions.py,sha256=BNmgWVquQUEqJAYsed_l8vLnlLP7u3XC1TDyEFI1AiU,1552
31
31
  rats/cli/_plugin.py,sha256=o-pmEqU6mVH3QoRfRBrbG-XRTWCzt6pLKtSV3-5VSx0,1144
32
32
  rats/cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- rats/logs/__init__.py,sha256=dSO-V2eu2W7w4w7oRau-UOfXXIkyZ2bHB6-kaasbeFM,970
34
- rats/logs/_app.py,sha256=SoTxk6g84tygOP_346NwXPcG1o6KZLd7lIgayq5vMdc,3239
33
+ rats/logs/__init__.py,sha256=_ZdkBmvW1yr5UOIB_m4OldNsUxK6NTDunNW4mvgQmpI,2115
34
+ rats/logs/_app.py,sha256=EVjSjSaxJIL5LMJZf4yo9EpUBkkavaVXyg42cDsUt3I,5702
35
+ rats/logs/_showwarning.py,sha256=g5Gq0I7GoHgABI4eCobq6xd4NaKuLGJFyK-SCvegDHA,1726
35
36
  rats/logs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
37
  rats/runtime/__init__.py,sha256=f9aEnynHuePP9OP5XCtB-6nCBvNWWlQQLTzuxFEueoQ,2150
37
38
  rats/runtime/__main__.py,sha256=y01yOymsL075poX95pc02sJR1HD0pDNFRZdpOdi0R6Y,79
@@ -54,7 +55,7 @@ rats_e2e/runtime/_data.py,sha256=3d1F_JO2gEOPUjBp_KYMP3TefyneiG_ktlJjdIIYUy8,125
54
55
  rats_e2e/runtime/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
56
  rats_resources/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
57
  rats_resources/runtime/example-context.yaml,sha256=eiLsNFquFfkIpUhxUCQLzLigH21QF2F00fzA_e_aOKk,215
57
- rats_apps-0.11.0.dev20250521180658.dist-info/METADATA,sha256=dcJpnIbCfQHHsWtD0bjxHQ26671OecfVVNeISRUoJYg,889
58
- rats_apps-0.11.0.dev20250521180658.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
59
- rats_apps-0.11.0.dev20250521180658.dist-info/entry_points.txt,sha256=Gf6bPwxIVjWd3Xx71upZo7eDJA5cujniLew6fxJMgA4,117
60
- rats_apps-0.11.0.dev20250521180658.dist-info/RECORD,,
58
+ rats_apps-0.11.1.dist-info/METADATA,sha256=zUanJsEqbI1Z4kibOwJKNmGs5aYYoTe0Bame-D7CIag,8274
59
+ rats_apps-0.11.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
60
+ rats_apps-0.11.1.dist-info/entry_points.txt,sha256=Gf6bPwxIVjWd3Xx71upZo7eDJA5cujniLew6fxJMgA4,117
61
+ rats_apps-0.11.1.dist-info/RECORD,,
@@ -1,27 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: rats-apps
3
- Version: 0.11.0.dev20250521180658
4
- Summary: research analysis tools for building applications
5
- License: MIT
6
- Keywords: pipelines,machine learning,research
7
- Author: Elon Portugaly
8
- Author-email: elonp@microsoft.com
9
- Requires-Python: >=3.10,<4.0
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Requires-Dist: click
17
- Requires-Dist: colorlog
18
- Requires-Dist: dataclass-wizard
19
- Requires-Dist: pyyaml
20
- Requires-Dist: typing-extensions
21
- Project-URL: Documentation, https://microsoft.github.io/rats
22
- Project-URL: Repository, https://github.com/microsoft/rats
23
- Description-Content-Type: text/markdown
24
-
25
- # rats-apps
26
- ...
27
-