chutils 2.6.0a0__tar.gz → 2.7.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.
- chutils-2.7.0/PKG-INFO +393 -0
- chutils-2.6.0a0/PKG-INFO → chutils-2.7.0/README.md +175 -26
- chutils-2.7.0/pyproject.toml +91 -0
- chutils-2.7.0/src/chutils/__init__.py +184 -0
- chutils-2.7.0/src/chutils/__init__.pyi +226 -0
- chutils-2.7.0/src/chutils/cache/__init__.py +5 -0
- chutils-2.7.0/src/chutils/cache/base.py +85 -0
- chutils-2.7.0/src/chutils/cache/decorator.py +93 -0
- chutils-2.7.0/src/chutils/cache/in_memory.py +70 -0
- chutils-2.7.0/src/chutils/cache/utils.py +51 -0
- chutils-2.7.0/src/chutils/cli.py +57 -0
- chutils-2.7.0/src/chutils/cli_booster.py +151 -0
- chutils-2.7.0/src/chutils/cli_utils.py +95 -0
- chutils-2.7.0/src/chutils/commands/__init__.py +29 -0
- chutils-2.7.0/src/chutils/commands/base.py +39 -0
- chutils-2.7.0/src/chutils/commands/config.py +123 -0
- chutils-2.7.0/src/chutils/commands/dev.py +162 -0
- chutils-2.7.0/src/chutils/commands/init.py +135 -0
- chutils-2.7.0/src/chutils/commands/paths.py +78 -0
- chutils-2.7.0/src/chutils/commands/secrets.py +81 -0
- chutils-2.7.0/src/chutils/commands/template.py +92 -0
- chutils-2.7.0/src/chutils/commands/utils.py +24 -0
- chutils-2.7.0/src/chutils/commands/validate.py +76 -0
- chutils-2.7.0/src/chutils/config/GEMINI.md +23 -0
- chutils-2.7.0/src/chutils/config/__init__.py +222 -0
- chutils-2.7.0/src/chutils/config/core.py +273 -0
- chutils-2.7.0/src/chutils/config/diagnostics.py +128 -0
- chutils-2.7.0/src/chutils/config/generator.py +134 -0
- chutils-2.7.0/src/chutils/config/getters.py +280 -0
- chutils-2.7.0/src/chutils/config/manager.py +435 -0
- chutils-2.7.0/src/chutils/config/providers.py +459 -0
- chutils-2.7.0/src/chutils/config/schema.py +114 -0
- chutils-2.7.0/src/chutils/config/utils.py +139 -0
- chutils-2.7.0/src/chutils/config/watcher.py +141 -0
- chutils-2.7.0/src/chutils/context.py +73 -0
- {chutils-2.6.0a0 → chutils-2.7.0}/src/chutils/decorators.py +71 -5
- chutils-2.7.0/src/chutils/dev/__init__.py +3 -0
- chutils-2.7.0/src/chutils/dev/ast_indexer.py +279 -0
- chutils-2.7.0/src/chutils/dev/models.py +64 -0
- chutils-2.7.0/src/chutils/exceptions.py +86 -0
- chutils-2.7.0/src/chutils/features.py +187 -0
- chutils-2.7.0/src/chutils/fs.py +130 -0
- chutils-2.7.0/src/chutils/lifecycle.py +199 -0
- chutils-2.7.0/src/chutils/logger/GEMINI.md +21 -0
- chutils-2.7.0/src/chutils/logger/__init__.py +38 -0
- chutils-2.7.0/src/chutils/logger/core.py +539 -0
- chutils-2.7.0/src/chutils/logger/formatters.py +45 -0
- chutils-2.7.0/src/chutils/logger/handlers.py +124 -0
- chutils-2.7.0/src/chutils/logger/masking.py +102 -0
- chutils-2.7.0/src/chutils/secret_manager/GEMINI.md +20 -0
- chutils-2.7.0/src/chutils/secret_manager/__init__.py +10 -0
- chutils-2.7.0/src/chutils/secret_manager/core.py +189 -0
- chutils-2.7.0/src/chutils/secret_manager/providers.py +249 -0
- chutils-2.7.0/src/chutils/testing/__init__.py +11 -0
- chutils-2.7.0/src/chutils/testing/fixtures.py +205 -0
- chutils-2.7.0/src/chutils/time.py +202 -0
- chutils-2.7.0/src/chutils/tracing.py +187 -0
- chutils-2.6.0a0/README.md +0 -168
- chutils-2.6.0a0/pyproject.toml +0 -62
- chutils-2.6.0a0/src/chutils/__init__.py +0 -114
- chutils-2.6.0a0/src/chutils/config.py +0 -751
- chutils-2.6.0a0/src/chutils/logger.py +0 -620
- chutils-2.6.0a0/src/chutils/secret_manager.py +0 -328
- {chutils-2.6.0a0 → chutils-2.7.0}/LICENSE +0 -0
chutils-2.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chutils
|
|
3
|
+
Version: 2.7.0
|
|
4
|
+
Summary: Набор простых и удобных утилит для Python, который избавляет от рутины при работе с конфигурацией и логированием в новых проектах.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Author: Chu4hel
|
|
8
|
+
Author-email: sergeiivanov636@gmail.com
|
|
9
|
+
Requires-Python: >=3.9, !=3.9.0, !=3.9.1
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Provides-Extra: date
|
|
17
|
+
Provides-Extra: full
|
|
18
|
+
Provides-Extra: json
|
|
19
|
+
Provides-Extra: otel
|
|
20
|
+
Provides-Extra: pydantic
|
|
21
|
+
Provides-Extra: rich
|
|
22
|
+
Provides-Extra: secrets
|
|
23
|
+
Provides-Extra: testing
|
|
24
|
+
Provides-Extra: watch
|
|
25
|
+
Requires-Dist: keyring (>=25.7.0)
|
|
26
|
+
Requires-Dist: keyring (>=25.7.0) ; extra == "full"
|
|
27
|
+
Requires-Dist: keyring (>=25.7.0) ; extra == "secrets"
|
|
28
|
+
Requires-Dist: opentelemetry-api (>=1.41.1) ; extra == "full"
|
|
29
|
+
Requires-Dist: opentelemetry-api (>=1.41.1) ; extra == "otel"
|
|
30
|
+
Requires-Dist: opentelemetry-exporter-otlp (>=1.41.1) ; extra == "full"
|
|
31
|
+
Requires-Dist: opentelemetry-exporter-otlp (>=1.41.1) ; extra == "otel"
|
|
32
|
+
Requires-Dist: opentelemetry-sdk (>=1.41.1) ; extra == "full"
|
|
33
|
+
Requires-Dist: opentelemetry-sdk (>=1.41.1) ; extra == "otel"
|
|
34
|
+
Requires-Dist: pydantic (>=2.13.4) ; extra == "full"
|
|
35
|
+
Requires-Dist: pydantic (>=2.13.4,<3.0.0) ; extra == "pydantic"
|
|
36
|
+
Requires-Dist: pytest (>=8.0.0) ; (python_full_version < "3.10.0") and (extra == "full")
|
|
37
|
+
Requires-Dist: pytest (>=8.0.0) ; (python_full_version < "3.10.0") and (extra == "testing")
|
|
38
|
+
Requires-Dist: pytest (>=9.0.3) ; (python_full_version >= "3.10.0") and (extra == "full")
|
|
39
|
+
Requires-Dist: pytest (>=9.0.3) ; (python_full_version >= "3.10.0") and (extra == "testing")
|
|
40
|
+
Requires-Dist: python-dateutil (>=2.9.0) ; extra == "date"
|
|
41
|
+
Requires-Dist: python-dateutil (>=2.9.0) ; extra == "full"
|
|
42
|
+
Requires-Dist: python-dotenv (>=1.2.1) ; python_full_version < "3.10.0"
|
|
43
|
+
Requires-Dist: python-dotenv (>=1.2.2) ; python_full_version >= "3.10.0"
|
|
44
|
+
Requires-Dist: python-json-logger (>=3.2.1) ; extra == "full"
|
|
45
|
+
Requires-Dist: python-json-logger (>=3.2.1) ; extra == "json"
|
|
46
|
+
Requires-Dist: pyyaml (>=6.0.3)
|
|
47
|
+
Requires-Dist: rich (>=15.0.0) ; extra == "full"
|
|
48
|
+
Requires-Dist: rich (>=15.0.0) ; extra == "rich"
|
|
49
|
+
Requires-Dist: watchdog (>=6.0.0) ; extra == "full"
|
|
50
|
+
Requires-Dist: watchdog (>=6.0.0) ; extra == "watch"
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
[Русская версия](docs/README_RU.md)
|
|
54
|
+
|
|
55
|
+
# chutils: Stop the Routine!
|
|
56
|
+
|
|
57
|
+
[](https://opensource.org/licenses/MIT)
|
|
58
|
+
[](https://www.python.org/downloads/)
|
|
59
|
+
[](https://badge.fury.io/py/chutils)
|
|
60
|
+
[](https://Chu4hel.github.io/chutils/)
|
|
61
|
+
|
|
62
|
+
**chutils** is a set of simple utilities for Python designed to eliminate the repetitive setup of configuration,
|
|
63
|
+
logging, and secrets in your projects.
|
|
64
|
+
|
|
65
|
+
Start a new project and focus on what matters, not the routine.
|
|
66
|
+
|
|
67
|
+
Full documentation is available on [our website](https://Chu4hel.github.io/chutils/) (currently in Russian).
|
|
68
|
+
|
|
69
|
+
## The Problem
|
|
70
|
+
|
|
71
|
+
Every time you start a new project, you have to solve the same tasks:
|
|
72
|
+
|
|
73
|
+
- How to conveniently read settings from a configuration file?
|
|
74
|
+
- How to configure logging to write messages to both the console and a file with daily rotation?
|
|
75
|
+
- How to securely store API keys without hardcoding them in the code?
|
|
76
|
+
- How to make it all work "out of the box" without manually defining paths?
|
|
77
|
+
|
|
78
|
+
**chutils** offers ready-made solutions for all these problems.
|
|
79
|
+
|
|
80
|
+
## Key Features
|
|
81
|
+
|
|
82
|
+
- **✨ Zero Configuration:** The library **automatically** finds your project root and the `config.yml` or `config.ini`
|
|
83
|
+
file. It uses **lazy initialization** — no heavy operations until you actually need them.
|
|
84
|
+
- **⚙️ Flexible Configuration:** Support for `YAML` and `INI` formats. Simple functions for retrieving typed data.
|
|
85
|
+
- **✍️ Advanced Logger:** The `setup_logger()` function configures logging to the console and rotating files out of the
|
|
86
|
+
box. It returns a custom logger with additional debug levels (`devdebug`, `mediumdebug`).
|
|
87
|
+
- **🔒 Secure Secret Storage:** The `secret_manager` module provides a simple interface for saving and retrieving secrets
|
|
88
|
+
via the system `keyring`, with a fallback to `.env` files.
|
|
89
|
+
- **🚀 CLI Booster:** Turn any function into a CLI tool in seconds using the `@cli_command` decorator with automatic type
|
|
90
|
+
mapping and docstring parsing.
|
|
91
|
+
- **⏰ Painless Datetime:** Always-aware UTC time utilities, smart parsing, and human-readable time intervals.
|
|
92
|
+
- **📡 Distributed Tracing:** Seamless OpenTelemetry integration with `@trace` decorator and automatic log correlation.
|
|
93
|
+
- **🔍 Config Diagnostics:** Interactive trace of configuration sources and priorities via `config debug` command.
|
|
94
|
+
- **🌐 Remote Configuration:** Load settings from HTTP/HTTPS endpoints with background polling and fallback support.
|
|
95
|
+
- **🔄 Hot-Reload:** Support for automatic configuration reloading on file changes without restart (requires
|
|
96
|
+
`pip install chutils[watch]`).
|
|
97
|
+
- **⚡ Async Ready:** Most core functions have asynchronous versions (prefixed with `a`) for non-blocking execution.
|
|
98
|
+
- **🚀 Ready to Use:** Just install and use.
|
|
99
|
+
|
|
100
|
+
## Command Line Interface (CLI)
|
|
101
|
+
|
|
102
|
+
The library provides a `chutils` console command for convenient secret management without writing code.
|
|
103
|
+
|
|
104
|
+
### Secret Management
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Save a secret to the system storage (keyring)
|
|
108
|
+
chutils secrets set MY_API_KEY "super-secret-value"
|
|
109
|
+
|
|
110
|
+
# Delete a secret
|
|
111
|
+
chutils secrets delete MY_API_KEY
|
|
112
|
+
|
|
113
|
+
# Explicitly specify service name
|
|
114
|
+
chutils secrets set DB_PASSWORD "12345" --service my_custom_app
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Installation
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
poetry add chutils
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or using pip:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
pip install chutils
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Examples
|
|
130
|
+
|
|
131
|
+
In the [`/examples`](./examples/) folder, you will find ready-to-run scripts demonstrating the library's key features.
|
|
132
|
+
Each example focuses on a specific task.
|
|
133
|
+
|
|
134
|
+
## Quick Start
|
|
135
|
+
|
|
136
|
+
### 1. Working with Configuration
|
|
137
|
+
|
|
138
|
+
1. (Optional) Create a `config.yml` file in your project root:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
# config.yml
|
|
142
|
+
Database:
|
|
143
|
+
host: localhost
|
|
144
|
+
port: 5432
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. Get values in your code:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from chutils import get_config_value, get_config_int
|
|
151
|
+
|
|
152
|
+
db_host = get_config_value("Database", "host", fallback="127.0.0.1")
|
|
153
|
+
db_port = get_config_int("Database", "port", fallback=5432)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Validation via Pydantic (Optional)
|
|
157
|
+
|
|
158
|
+
For strict typing and validation, you can use Pydantic models (requires `pip install chutils[pydantic]`):
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from pydantic import BaseModel
|
|
162
|
+
from chutils import get_config
|
|
163
|
+
|
|
164
|
+
class AppConfig(BaseModel):
|
|
165
|
+
app_name: str
|
|
166
|
+
version: str
|
|
167
|
+
|
|
168
|
+
# Returns an instance of AppConfig
|
|
169
|
+
cfg = get_config(model=AppConfig)
|
|
170
|
+
print(cfg.app_name)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
You can also validate specific sections:
|
|
174
|
+
```python
|
|
175
|
+
from chutils import get_config_section
|
|
176
|
+
db_cfg = get_config_section("Database", model=MyDbModel)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Overriding Configuration with Local Files (`config.local.yml`)
|
|
180
|
+
|
|
181
|
+
You can create a `config.local.yml` next to your main file. Values from the local file will **override**
|
|
182
|
+
corresponding values from the main file. This is perfect for local development or storing sensitive data (ensure
|
|
183
|
+
`*.local.*` is in your `.gitignore`).
|
|
184
|
+
|
|
185
|
+
### 2. Hot-Reload
|
|
186
|
+
|
|
187
|
+
You can make your application react to configuration file changes in real-time.
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from chutils import start_config_watcher, on_config_change, get_config_value
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def reload_logic():
|
|
194
|
+
print("Configuration updated!")
|
|
195
|
+
# Update app state here
|
|
196
|
+
db_url = get_config_value("Database", "url")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# Register callback
|
|
200
|
+
on_config_change(reload_logic)
|
|
201
|
+
|
|
202
|
+
# Start watcher (requires watchdog package)
|
|
203
|
+
start_config_watcher()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
To use this feature, install `watchdog`:
|
|
207
|
+
`pip install chutils[watch]`
|
|
208
|
+
|
|
209
|
+
### 3. Logging Setup
|
|
210
|
+
|
|
211
|
+
1. Configure and use the logger:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from chutils import setup_logger, ChutilsLogger
|
|
215
|
+
|
|
216
|
+
# Automatically reads settings from [Logging] section in config.yml
|
|
217
|
+
logger: ChutilsLogger = setup_logger()
|
|
218
|
+
|
|
219
|
+
logger.info("Application started.")
|
|
220
|
+
logger.devdebug("Deep debug message (level 9).")
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Structured Logging (JSON)
|
|
224
|
+
|
|
225
|
+
If you need to output logs in JSON format for ELK, Splunk, or cloud logging (requires `pip install chutils[json]`):
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# Via code
|
|
229
|
+
logger = setup_logger(json_format=True)
|
|
230
|
+
|
|
231
|
+
# Or via config in the [Logging] section
|
|
232
|
+
# json_format: true
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Contextual Logging (ContextVar)
|
|
236
|
+
|
|
237
|
+
You can bind metadata to the current execution context (thread or coroutine), and it will be automatically
|
|
238
|
+
included in all log messages.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
from chutils import setup_logger, bind_context
|
|
242
|
+
|
|
243
|
+
logger = setup_logger()
|
|
244
|
+
|
|
245
|
+
# Bind request ID and user to the current context
|
|
246
|
+
bind_context(request_id="REQ-123", user="admin")
|
|
247
|
+
|
|
248
|
+
logger.info("Action performed")
|
|
249
|
+
# Text: ... [request_id=REQ-123 user=admin] Action performed
|
|
250
|
+
# JSON: {..., "message": "Action performed", "context": {"request_id": "REQ-123", "user": "admin"}}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Controlling Logging via Environment Variables
|
|
254
|
+
|
|
255
|
+
- `CH_LOG_JSON=true`: Forces JSON format.
|
|
256
|
+
- `CH_LOG_NO_TIME=true`: Removes the date/time from the log format (for clean Docker logs).
|
|
257
|
+
- `CH_LOG_NO_FILE=true`: Disables creating log files.
|
|
258
|
+
|
|
259
|
+
These variables have **highest priority** and override any code or config settings.
|
|
260
|
+
|
|
261
|
+
### 3. Secret Management
|
|
262
|
+
|
|
263
|
+
`SecretManager` looks for secrets in the following order: **Keyring > .env File > Environment Variables**.
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
from chutils import SecretManager
|
|
267
|
+
|
|
268
|
+
secrets = SecretManager("my_awesome_app")
|
|
269
|
+
|
|
270
|
+
# Save once
|
|
271
|
+
secrets.save_secret("API_KEY", "secret-value-123")
|
|
272
|
+
|
|
273
|
+
# Use everywhere
|
|
274
|
+
key = secrets.get_secret("API_KEY")
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### Disabling Keyring (Optional)
|
|
278
|
+
|
|
279
|
+
In environments like Docker or CI/CD where `keyring` is unavailable, you can suppress warnings and skip the check:
|
|
280
|
+
|
|
281
|
+
- Set `CH_DISABLE_KEYRING_WARNING=true` in environment.
|
|
282
|
+
- Or add `disable_keyring: true` under `secrets` section in `config.yml`.
|
|
283
|
+
|
|
284
|
+
## API Overview
|
|
285
|
+
|
|
286
|
+
### Configuration (`chutils.config`)
|
|
287
|
+
|
|
288
|
+
- `get_config_value(section, key, fallback)` / `aget_config()`
|
|
289
|
+
- `get_config_int`, `get_config_boolean`, `get_config_list`, `get_config_path`
|
|
290
|
+
- `save_config_value(section, key, value, notify=True)` / `asave_config_value()`
|
|
291
|
+
- Use `notify=False` to update the file without triggering Hot-Reload callbacks.
|
|
292
|
+
|
|
293
|
+
### Logging (`chutils.logger`)
|
|
294
|
+
|
|
295
|
+
- `setup_logger(name, log_level, log_file_name, rotation_type, compress, ...)`
|
|
296
|
+
- Levels: `logger.devdebug` (9), `logger.mediumdebug` (15), and all standard ones.
|
|
297
|
+
|
|
298
|
+
### Secret Management (`chutils.secret_manager`)
|
|
299
|
+
|
|
300
|
+
- `SecretManager(service_name, prefix)`
|
|
301
|
+
- `save_secret` / `asave_secret`
|
|
302
|
+
- `get_secret` / `aget_secret`
|
|
303
|
+
- `delete_secret` / `adelete_secret`
|
|
304
|
+
|
|
305
|
+
### Decorators (`chutils.decorators`)
|
|
306
|
+
|
|
307
|
+
- `@log_function_details`: Logs arguments, execution time, and result (uses `DEVDEBUG` level).
|
|
308
|
+
- `@timeout(seconds, fallback)`: Limits function execution time. Supports sync/async and optional fallback.
|
|
309
|
+
- `@retry`: Automatically retries a function if it fails. Supports sync/async, backoff, jitter, and exception filtering.
|
|
310
|
+
- `@cli_command`: Turns any function into a standalone CLI script with automatic argument parsing.
|
|
311
|
+
|
|
312
|
+
### Time & Dates (`chutils.time`)
|
|
313
|
+
|
|
314
|
+
- `utc_now()`: Returns a timezone-aware UTC datetime.
|
|
315
|
+
- `parse_datetime(value)`: Smart parsing of strings and timestamps into UTC.
|
|
316
|
+
- `humanize_timedelta(dt)`: Returns human-readable strings like "5 minutes ago" or "tomorrow".
|
|
317
|
+
|
|
318
|
+
### Example of @retry usage:
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
from chutils.decorators import retry
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@retry(retries=3, delay=1.0, backoff=2.0)
|
|
325
|
+
def fetch_data():
|
|
326
|
+
# Will be retried up to 3 times on any Exception
|
|
327
|
+
...
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Command Line Interface (CLI)
|
|
331
|
+
|
|
332
|
+
`chutils` includes a set of tools to speed up development and debugging.
|
|
333
|
+
|
|
334
|
+
### 1. Initialize Project
|
|
335
|
+
|
|
336
|
+
Quickly set up a new project with a default configuration and `.gitignore` rules:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Interactive mode
|
|
340
|
+
chutils init
|
|
341
|
+
|
|
342
|
+
# Non-interactive mode (default values)
|
|
343
|
+
chutils init -y
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 2. Validate Configuration
|
|
347
|
+
|
|
348
|
+
Check if your configuration files match your Pydantic models:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Automatically finds 'Settings' class in context.py or config.py
|
|
352
|
+
chutils validate
|
|
353
|
+
|
|
354
|
+
# Explicitly specify the model path
|
|
355
|
+
chutils validate --model src.settings:AppConfig
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### 3. Debug Search Paths
|
|
359
|
+
|
|
360
|
+
See exactly where `chutils` is looking for configuration files:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Human-readable output
|
|
364
|
+
chutils show-paths
|
|
365
|
+
|
|
366
|
+
# JSON output for automation
|
|
367
|
+
chutils show-paths --json
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 4. Manage Secrets
|
|
371
|
+
|
|
372
|
+
Manage your system keyring secrets directly from the terminal:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
# Set a secret
|
|
376
|
+
chutils secrets set API_KEY "your-secret-value" --service my_app
|
|
377
|
+
|
|
378
|
+
# Delete a secret
|
|
379
|
+
chutils secrets delete API_KEY --service my_app
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### 5. Debug Configuration
|
|
383
|
+
|
|
384
|
+
Trace exactly where each configuration value comes from:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
chutils config debug
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## License
|
|
391
|
+
|
|
392
|
+
The project is distributed under the MIT License.
|
|
393
|
+
|
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: chutils
|
|
3
|
-
Version: 2.6.0a0
|
|
4
|
-
Summary: Набор простых и удобных утилит для Python, который избавляет от рутины при работе с конфигурацией и логированием в новых проектах.
|
|
5
|
-
License: MIT
|
|
6
|
-
License-File: LICENSE
|
|
7
|
-
Author: Chu4hel
|
|
8
|
-
Author-email: sergeiivanov636@gmail.com
|
|
9
|
-
Requires-Python: >=3.9, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*, !=3.8.*
|
|
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
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
-
Requires-Dist: keyring (>=25.7.0,<26.0.0)
|
|
18
|
-
Requires-Dist: python-dotenv (==1.2.1) ; python_version < "3.10"
|
|
19
|
-
Requires-Dist: python-dotenv (>=1.2.2,<2.0.0) ; python_version >= "3.10"
|
|
20
|
-
Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
|
|
23
1
|
[Русская версия](docs/README_RU.md)
|
|
24
2
|
|
|
25
3
|
# chutils: Stop the Routine!
|
|
@@ -56,9 +34,34 @@ Every time you start a new project, you have to solve the same tasks:
|
|
|
56
34
|
box. It returns a custom logger with additional debug levels (`devdebug`, `mediumdebug`).
|
|
57
35
|
- **🔒 Secure Secret Storage:** The `secret_manager` module provides a simple interface for saving and retrieving secrets
|
|
58
36
|
via the system `keyring`, with a fallback to `.env` files.
|
|
37
|
+
- **🚀 CLI Booster:** Turn any function into a CLI tool in seconds using the `@cli_command` decorator with automatic type
|
|
38
|
+
mapping and docstring parsing.
|
|
39
|
+
- **⏰ Painless Datetime:** Always-aware UTC time utilities, smart parsing, and human-readable time intervals.
|
|
40
|
+
- **📡 Distributed Tracing:** Seamless OpenTelemetry integration with `@trace` decorator and automatic log correlation.
|
|
41
|
+
- **🔍 Config Diagnostics:** Interactive trace of configuration sources and priorities via `config debug` command.
|
|
42
|
+
- **🌐 Remote Configuration:** Load settings from HTTP/HTTPS endpoints with background polling and fallback support.
|
|
43
|
+
- **🔄 Hot-Reload:** Support for automatic configuration reloading on file changes without restart (requires
|
|
44
|
+
`pip install chutils[watch]`).
|
|
59
45
|
- **⚡ Async Ready:** Most core functions have asynchronous versions (prefixed with `a`) for non-blocking execution.
|
|
60
46
|
- **🚀 Ready to Use:** Just install and use.
|
|
61
47
|
|
|
48
|
+
## Command Line Interface (CLI)
|
|
49
|
+
|
|
50
|
+
The library provides a `chutils` console command for convenient secret management without writing code.
|
|
51
|
+
|
|
52
|
+
### Secret Management
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Save a secret to the system storage (keyring)
|
|
56
|
+
chutils secrets set MY_API_KEY "super-secret-value"
|
|
57
|
+
|
|
58
|
+
# Delete a secret
|
|
59
|
+
chutils secrets delete MY_API_KEY
|
|
60
|
+
|
|
61
|
+
# Explicitly specify service name
|
|
62
|
+
chutils secrets set DB_PASSWORD "12345" --service my_custom_app
|
|
63
|
+
```
|
|
64
|
+
|
|
62
65
|
## Installation
|
|
63
66
|
|
|
64
67
|
```bash
|
|
@@ -98,13 +101,60 @@ Each example focuses on a specific task.
|
|
|
98
101
|
db_port = get_config_int("Database", "port", fallback=5432)
|
|
99
102
|
```
|
|
100
103
|
|
|
104
|
+
#### Validation via Pydantic (Optional)
|
|
105
|
+
|
|
106
|
+
For strict typing and validation, you can use Pydantic models (requires `pip install chutils[pydantic]`):
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from pydantic import BaseModel
|
|
110
|
+
from chutils import get_config
|
|
111
|
+
|
|
112
|
+
class AppConfig(BaseModel):
|
|
113
|
+
app_name: str
|
|
114
|
+
version: str
|
|
115
|
+
|
|
116
|
+
# Returns an instance of AppConfig
|
|
117
|
+
cfg = get_config(model=AppConfig)
|
|
118
|
+
print(cfg.app_name)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
You can also validate specific sections:
|
|
122
|
+
```python
|
|
123
|
+
from chutils import get_config_section
|
|
124
|
+
db_cfg = get_config_section("Database", model=MyDbModel)
|
|
125
|
+
```
|
|
126
|
+
|
|
101
127
|
#### Overriding Configuration with Local Files (`config.local.yml`)
|
|
102
128
|
|
|
103
129
|
You can create a `config.local.yml` next to your main file. Values from the local file will **override**
|
|
104
130
|
corresponding values from the main file. This is perfect for local development or storing sensitive data (ensure
|
|
105
131
|
`*.local.*` is in your `.gitignore`).
|
|
106
132
|
|
|
107
|
-
### 2.
|
|
133
|
+
### 2. Hot-Reload
|
|
134
|
+
|
|
135
|
+
You can make your application react to configuration file changes in real-time.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from chutils import start_config_watcher, on_config_change, get_config_value
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def reload_logic():
|
|
142
|
+
print("Configuration updated!")
|
|
143
|
+
# Update app state here
|
|
144
|
+
db_url = get_config_value("Database", "url")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# Register callback
|
|
148
|
+
on_config_change(reload_logic)
|
|
149
|
+
|
|
150
|
+
# Start watcher (requires watchdog package)
|
|
151
|
+
start_config_watcher()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
To use this feature, install `watchdog`:
|
|
155
|
+
`pip install chutils[watch]`
|
|
156
|
+
|
|
157
|
+
### 3. Logging Setup
|
|
108
158
|
|
|
109
159
|
1. Configure and use the logger:
|
|
110
160
|
|
|
@@ -118,8 +168,39 @@ Each example focuses on a specific task.
|
|
|
118
168
|
logger.devdebug("Deep debug message (level 9).")
|
|
119
169
|
```
|
|
120
170
|
|
|
171
|
+
#### Structured Logging (JSON)
|
|
172
|
+
|
|
173
|
+
If you need to output logs in JSON format for ELK, Splunk, or cloud logging (requires `pip install chutils[json]`):
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
# Via code
|
|
177
|
+
logger = setup_logger(json_format=True)
|
|
178
|
+
|
|
179
|
+
# Or via config in the [Logging] section
|
|
180
|
+
# json_format: true
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Contextual Logging (ContextVar)
|
|
184
|
+
|
|
185
|
+
You can bind metadata to the current execution context (thread or coroutine), and it will be automatically
|
|
186
|
+
included in all log messages.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from chutils import setup_logger, bind_context
|
|
190
|
+
|
|
191
|
+
logger = setup_logger()
|
|
192
|
+
|
|
193
|
+
# Bind request ID and user to the current context
|
|
194
|
+
bind_context(request_id="REQ-123", user="admin")
|
|
195
|
+
|
|
196
|
+
logger.info("Action performed")
|
|
197
|
+
# Text: ... [request_id=REQ-123 user=admin] Action performed
|
|
198
|
+
# JSON: {..., "message": "Action performed", "context": {"request_id": "REQ-123", "user": "admin"}}
|
|
199
|
+
```
|
|
200
|
+
|
|
121
201
|
#### Controlling Logging via Environment Variables
|
|
122
202
|
|
|
203
|
+
- `CH_LOG_JSON=true`: Forces JSON format.
|
|
123
204
|
- `CH_LOG_NO_TIME=true`: Removes the date/time from the log format (for clean Docker logs).
|
|
124
205
|
- `CH_LOG_NO_FILE=true`: Disables creating log files.
|
|
125
206
|
|
|
@@ -154,7 +235,8 @@ In environments like Docker or CI/CD where `keyring` is unavailable, you can sup
|
|
|
154
235
|
|
|
155
236
|
- `get_config_value(section, key, fallback)` / `aget_config()`
|
|
156
237
|
- `get_config_int`, `get_config_boolean`, `get_config_list`, `get_config_path`
|
|
157
|
-
- `save_config_value(section, key, value)` / `asave_config_value()`
|
|
238
|
+
- `save_config_value(section, key, value, notify=True)` / `asave_config_value()`
|
|
239
|
+
- Use `notify=False` to update the file without triggering Hot-Reload callbacks.
|
|
158
240
|
|
|
159
241
|
### Logging (`chutils.logger`)
|
|
160
242
|
|
|
@@ -171,9 +253,17 @@ In environments like Docker or CI/CD where `keyring` is unavailable, you can sup
|
|
|
171
253
|
### Decorators (`chutils.decorators`)
|
|
172
254
|
|
|
173
255
|
- `@log_function_details`: Logs arguments, execution time, and result (uses `DEVDEBUG` level).
|
|
256
|
+
- `@timeout(seconds, fallback)`: Limits function execution time. Supports sync/async and optional fallback.
|
|
174
257
|
- `@retry`: Automatically retries a function if it fails. Supports sync/async, backoff, jitter, and exception filtering.
|
|
258
|
+
- `@cli_command`: Turns any function into a standalone CLI script with automatic argument parsing.
|
|
175
259
|
|
|
176
|
-
|
|
260
|
+
### Time & Dates (`chutils.time`)
|
|
261
|
+
|
|
262
|
+
- `utc_now()`: Returns a timezone-aware UTC datetime.
|
|
263
|
+
- `parse_datetime(value)`: Smart parsing of strings and timestamps into UTC.
|
|
264
|
+
- `humanize_timedelta(dt)`: Returns human-readable strings like "5 minutes ago" or "tomorrow".
|
|
265
|
+
|
|
266
|
+
### Example of @retry usage:
|
|
177
267
|
|
|
178
268
|
```python
|
|
179
269
|
from chutils.decorators import retry
|
|
@@ -185,7 +275,66 @@ def fetch_data():
|
|
|
185
275
|
...
|
|
186
276
|
```
|
|
187
277
|
|
|
278
|
+
## Command Line Interface (CLI)
|
|
279
|
+
|
|
280
|
+
`chutils` includes a set of tools to speed up development and debugging.
|
|
281
|
+
|
|
282
|
+
### 1. Initialize Project
|
|
283
|
+
|
|
284
|
+
Quickly set up a new project with a default configuration and `.gitignore` rules:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# Interactive mode
|
|
288
|
+
chutils init
|
|
289
|
+
|
|
290
|
+
# Non-interactive mode (default values)
|
|
291
|
+
chutils init -y
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 2. Validate Configuration
|
|
295
|
+
|
|
296
|
+
Check if your configuration files match your Pydantic models:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Automatically finds 'Settings' class in context.py or config.py
|
|
300
|
+
chutils validate
|
|
301
|
+
|
|
302
|
+
# Explicitly specify the model path
|
|
303
|
+
chutils validate --model src.settings:AppConfig
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 3. Debug Search Paths
|
|
307
|
+
|
|
308
|
+
See exactly where `chutils` is looking for configuration files:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# Human-readable output
|
|
312
|
+
chutils show-paths
|
|
313
|
+
|
|
314
|
+
# JSON output for automation
|
|
315
|
+
chutils show-paths --json
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 4. Manage Secrets
|
|
319
|
+
|
|
320
|
+
Manage your system keyring secrets directly from the terminal:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Set a secret
|
|
324
|
+
chutils secrets set API_KEY "your-secret-value" --service my_app
|
|
325
|
+
|
|
326
|
+
# Delete a secret
|
|
327
|
+
chutils secrets delete API_KEY --service my_app
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 5. Debug Configuration
|
|
331
|
+
|
|
332
|
+
Trace exactly where each configuration value comes from:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
chutils config debug
|
|
336
|
+
```
|
|
337
|
+
|
|
188
338
|
## License
|
|
189
339
|
|
|
190
340
|
The project is distributed under the MIT License.
|
|
191
|
-
|