Набор простых и удобных утилит для Python, который избавляет от рутины при работе с конфигурацией и логированием в новых проектах.
Project description
chutils: Stop the Routine!
chutils is a set of simple utilities for Python designed to eliminate the repetitive setup of configuration, logging, and secrets in your projects.
Start a new project and focus on what matters, not the routine.
Full documentation is available on our website (currently in Russian).
The Problem
Every time you start a new project, you have to solve the same tasks:
- How to conveniently read settings from a configuration file?
- How to configure logging to write messages to both the console and a file with daily rotation?
- How to securely store API keys without hardcoding them in the code?
- How to make it all work "out of the box" without manually defining paths?
chutils offers ready-made solutions for all these problems.
Key Features
- ✨ Zero Configuration: The library automatically finds your project root and the
config.ymlorconfig.inifile. If the file is not found, safe defaults are used. - ⚙️ Flexible Configuration: Support for
YAMLandINIformats. Simple functions for retrieving typed data. - ✍️ Advanced Logger: The
setup_logger()function configures logging to the console and rotating files out of the box. It returns a custom logger with additional debug levels (devdebug,mediumdebug). - 🔒 Secure Secret Storage: The
secret_managermodule provides a simple interface for saving and retrieving secrets via the systemkeyring, with a fallback to.envfiles. - 🚀 Ready to Use: Just install and use.
Installation
poetry add chutils
Or using pip:
pip install chutils
For development, clone the repository and install in editable mode:
git clone https://github.com/Chu4hel/chutils.git
cd chutils
pip install -e .
Examples
In the /examples folder, you will find ready-to-run scripts demonstrating the library's key features.
Each example focuses on a specific task.
Quick Start
1. Working with Configuration
-
(Optional) Create a
config.ymlfile in your project root. If you skip this, the library will use defaults:# config.yml Database: host: localhost port: 5432 user: my_user
-
Get values in your code:
# main.py from chutils import get_config_value, get_config_int db_host = get_config_value("Database", "host", fallback="127.0.0.1") db_port = get_config_int("Database", "port", fallback=5433) print(f"Connecting to DB at: {db_host}:{db_port}") # Output: Connecting to DB at: localhost:5432
chutilswill automatically findconfig.ymland read the data.Overriding Configuration with Local Files (
config.local.yml)You can create a local configuration file (e.g.,
config.local.ymlorconfig.local.ini) next to your main file (config.ymlorconfig.ini). Values from the local file will override corresponding values from the main file. This is useful for:- Storing sensitive data that should not be committed to version control (add
config.local.ymlto.gitignore). - Overriding settings for local development without changing the main file.
Example: If
config.ymlcontains:# config.yml Database: host: production_db.com port: 5432 App: debug: false
And
config.local.ymlcontains:# config.local.yml Database: host: localhost App: debug: true developer_mode: true
Then
get_config()will return:Database: host: localhost # Overridden by local file port: 5432 # From main file App: debug: true # Overridden by local file developer_mode: true # Added from local file
Important: Ensure you add
config.local.yml(orconfig.local.ini) to your.gitignore. - Storing sensitive data that should not be committed to version control (add
2. Logging Setup
-
Add a
Loggingsection to yourconfig.yml(optional):# config.yml Logging: log_level: DEBUG log_file_name: my_app.log
-
Use the logger:
# main.py from chutils import setup_logger, ChutilsLogger # Configure logger. It automatically reads settings from config. logger: ChutilsLogger = setup_logger() logger.info("Application started.") logger.debug("This is a debug message.") # Output to console and writes to file logs/my_app.log
The
logsfolder will be created automatically.You can also specify the log filename directly when calling
setup_logger, overriding the config:# main.py from chutils import setup_logger, ChutilsLogger # Logger will write to custom.log, ignoring log_file_name from config.yml logger: ChutilsLogger = setup_logger(log_file_name="custom.log") logger.info("Message in a custom file.")
Creating Multiple Loggers
You can create different loggers for different parts of your application by passing a unique name to
setup_logger. This helps filter and separate logs.# main.py from chutils import setup_logger # Main app logger will write to main_app.log main_logger = setup_logger("main_app", log_file_name="main_app.log") # Logger for the database module will write to database.log db_logger = setup_logger("database", log_file_name="database.log") main_logger.info("Application started.") db_logger.debug("Initializing DB connection...")
See
/examples/05_different_log_levels.pyfor a detailed example.Configuring Multiple Loggers via File
You can centrally manage settings for different loggers using the
config_section_nameparameter.-
Add sections to
config.yml: The[Logging]section is used for defaults. Other sections can be used for specific loggers.# config.yml Logging: log_level: INFO rotation_type: time compress: true AuditLogger: log_level: DEBUG log_file_name: "audit.log"
-
Use
config_section_namein code:# main.py from chutils import setup_logger # This logger takes settings from [Logging] main_logger = setup_logger("main") main_logger.info("Message from main logger.") # This logger takes settings from [AuditLogger], overriding defaults audit_logger = setup_logger("audit", config_section_name="AuditLogger") audit_logger.debug("Detailed audit message.")
-
3. Secret Management
SecretManager looks for secrets in the following order:
- System Storage (
keyring): The most secure method. .envFile: If the secret is not found inkeyring, the manager looks in the.envfile in the project root.- Environment Variables: If not found there either, it checks OS environment variables.
Method 1: Keyring (Recommended)
-
Initialize
SecretManagerand save your secret. Do this once.# setup_secrets.py from chutils import SecretManager secrets = SecretManager("my_awesome_app") secrets.save_secret("DB_PASSWORD", "MySuperSecretDbPassword123!") print("DB password saved to system storage!")
-
Retrieve the secret in your main code without exposing it:
# main.py from chutils import SecretManager, get_config_value secrets = SecretManager("my_awesome_app") db_user = get_config_value("Database", "user") # Get password from secure storage db_password = secrets.get_secret("DB_PASSWORD") if db_password: print(f"Password retrieved for user {db_user}.") else: print("Password not found!")
Method 2: .env File (Useful for Docker and CI/CD)
-
Create a
.envfile in your project root:# .env DB_PASSWORD="AnotherSecretPassword" API_KEY="abcdef123456"
-
SecretManagerautomatically finds this file and reads variables if not found inkeyring.# main.py from chutils import SecretManager secrets = SecretManager("my_awesome_app") # This secret will be taken from .env if not in keyring api_key = secrets.get_secret("API_KEY") print(f"Found API key: {api_key}")
Comprehensive Example
This example shows how all chutils components work together.
-
config.yml:API: base_url: https://api.example.com Database: host: localhost port: 5432 user: my_user Logging: log_level: INFO
-
main.py:# main.py from chutils import get_config_value, setup_logger, SecretManager, ChutilsLogger # 1. Setup logger. It automatically reads settings from config. logger: ChutilsLogger = setup_logger() # 2. Initialize secret manager for our app. secrets = SecretManager("my_awesome_app") def setup_credentials(): """Function to save password initially if missing.""" db_user = get_config_value("Database", "user") password_key = f"{db_user}_password" if not secrets.get_secret(password_key): logger.info("DB password not found. Saving new one...") secrets.save_secret(password_key, "MySuperSecretDbPassword123!") logger.info("DB password saved to system storage.") def connect_to_db(): """Example DB connection using config and secrets.""" db_host = get_config_value("Database", "host") db_user = get_config_value("Database", "user") db_password = secrets.get_secret(f"{db_user}_password") if not db_password: logger.error("Failed to retrieve DB password!") return logger.info(f"Connecting to {db_host} as {db_user}...") # ... connection logic ... logger.info("Connected successfully!") def main(): logger.info("App started.") setup_credentials() connect_to_db() logger.info("App finished.") if __name__ == "__main__": main()
API
Configuration (chutils.config)
get_config_value(section, key, fallback=""): Get a value.get_config_int(section, key, fallback=0): Get an integer.get_config_boolean(section, key, fallback=False): Get a boolean.get_config_list(section, key, fallback=[]): Get a list.get_config_section(section): Get the entire section as a dictionary.save_config_value(section, key, value): Save a value. Works for.ymland.ini. Note: comments and formatting are lost when saving to.yml. They are preserved for.ini.
Logging (chutils.logger)
setup_logger(name='app_logger', log_level_str=''): Configures and returns aChutilsLoggerinstance.logger.mediumdebug("message"): Log with level 15.logger.devdebug("message"): Log with level 9.
Secret Management (chutils.secret_manager)
SecretManager(service_name, prefix="Chutils_"): Creates a manager isolated by service name.secrets.save_secret(key, value): Saves a secret.secrets.get_secret(key): Retrieves a secret.secrets.delete_secret(key): Deletes a secret.
Decorators (chutils.decorators)
log_function_details: Decorator for logging function call details (arguments, execution time, result).
Manual Initialization (chutils.init)
In 99% of cases, you will not need this. But if automation fails, you can manually specify the project path once at the very beginning:
import chutils
chutils.init(base_dir="/path/to/my/project/root")
Note on secret_manager (Keyring)
The SecretManager module uses the keyring library to securely store secrets in system storage.
- On Windows and macOS, this works "out of the box".
- Linux Requirements: Secure
keyringoperation on Linux requires an installed and configured backend (secret storage), such asGNOME Keyring(Seahorse) orKWallet. On servers or minimal builds, you may need to install this manually. See the officialkeyringdocumentation for details. - Mobile OS: This module is not intended for use on mobile operating systems (Android, iOS).
keyringwill likely not find system storage and may use an insecure method to store your secrets.
License
The project is distributed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chutils-2.4.0.tar.gz.
File metadata
- Download URL: chutils-2.4.0.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.5 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af78a160b2db76ba8222265ed9a17042800c290fe271af04eb90b9ddf1a7fcb3
|
|
| MD5 |
7d3af79237e896189d9772b75a847e51
|
|
| BLAKE2b-256 |
1972f8dbf5075b507450e01e3a0f87d76e2844f33f0b4860f5ecf81db0ac8e06
|
File details
Details for the file chutils-2.4.0-py3-none-any.whl.
File metadata
- Download URL: chutils-2.4.0-py3-none-any.whl
- Upload date:
- Size: 26.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.5 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8091c87440dc46a40eb3fb6aa04533017c1ade8c9c085c5033d1ed95e456fa60
|
|
| MD5 |
f71785f520bc53d7065c6ba98c085986
|
|
| BLAKE2b-256 |
66aa6088fc0a63afae996cacf00cc308e519beebfeac75fed12dc8a634f73526
|