rats-apps 0.11.1.dev20250527164358__py3-none-any.whl → 0.11.1.dev20250527164753__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/cli/_container.py +1 -1
- rats/logs/__init__.py +50 -4
- rats/logs/_app.py +63 -4
- rats/logs/_showwarning.py +51 -0
- {rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/METADATA +1 -1
- {rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/RECORD +8 -7
- {rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/WHEEL +0 -0
- {rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/entry_points.txt +0 -0
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
|
-
|
11
|
-
|
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
|
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": "
|
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
|
-
|
96
|
-
|
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)
|
{rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/RECORD
RENAMED
@@ -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=
|
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=
|
34
|
-
rats/logs/_app.py,sha256=
|
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.1.
|
58
|
-
rats_apps-0.11.1.
|
59
|
-
rats_apps-0.11.1.
|
60
|
-
rats_apps-0.11.1.
|
58
|
+
rats_apps-0.11.1.dev20250527164753.dist-info/METADATA,sha256=kgJQUzcaMgofZndS9ETn14z0uY0ZE50-Y1Yh8pqVqYA,889
|
59
|
+
rats_apps-0.11.1.dev20250527164753.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
60
|
+
rats_apps-0.11.1.dev20250527164753.dist-info/entry_points.txt,sha256=Gf6bPwxIVjWd3Xx71upZo7eDJA5cujniLew6fxJMgA4,117
|
61
|
+
rats_apps-0.11.1.dev20250527164753.dist-info/RECORD,,
|
{rats_apps-0.11.1.dev20250527164358.dist-info → rats_apps-0.11.1.dev20250527164753.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|