Skip to main content

Набор простых и удобных утилит для Python, который избавляет от рутины при работе с конфигурацией и логированием в новых проектах.

Project description

Русская версия

chutils: Stop the Routine!

License: MIT Python PyPI version Documentation

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.yml or config.ini file. If the file is not found, safe defaults are used.
  • ⚙️ Flexible Configuration: Support for YAML and INI formats. 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_manager module provides a simple interface for saving and retrieving secrets via the system keyring, with a fallback to .env files.
  • 🚀 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

  1. (Optional) Create a config.yml file in your project root. If you skip this, the library will use defaults:

    # config.yml
    Database:
      host: localhost
      port: 5432
      user: my_user
    
  2. 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
    

    chutils will automatically find config.yml and read the data.

    Overriding Configuration with Local Files (config.local.yml)

    You can create a local configuration file (e.g., config.local.yml or config.local.ini) next to your main file ( config.yml or config.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.yml to .gitignore).
    • Overriding settings for local development without changing the main file.

    Example: If config.yml contains:

    # config.yml
    Database:
      host: production_db.com
      port: 5432
    App:
      debug: false
    

    And config.local.yml contains:

    # 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 (or config.local.ini) to your .gitignore.

2. Logging Setup

  1. Add a Logging section to your config.yml (optional):

    # config.yml
    Logging:
      log_level: DEBUG
      log_file_name: my_app.log
    
  2. 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 logs folder 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.py for a detailed example.

    Configuring Multiple Loggers via File

    You can centrally manage settings for different loggers using the config_section_name parameter.

    1. 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"
      
    2. Use config_section_name in 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:

  1. System Storage (keyring): The most secure method.
  2. .env File: If the secret is not found in keyring, the manager looks in the .env file in the project root.
  3. Environment Variables: If not found there either, it checks OS environment variables.

Method 1: Keyring (Recommended)

  1. Initialize SecretManager and 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!")
    
  2. 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)

  1. Create a .env file in your project root:

    # .env
    DB_PASSWORD="AnotherSecretPassword"
    API_KEY="abcdef123456"
    
  2. SecretManager automatically finds this file and reads variables if not found in keyring.

    # 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.

  1. config.yml:

    API:
      base_url: https://api.example.com
    
    Database:
      host: localhost
      port: 5432
      user: my_user
    
    Logging:
      log_level: INFO
    
  2. 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 .yml and .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 a ChutilsLogger instance.
  • 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 keyring operation on Linux requires an installed and configured backend (secret storage), such as GNOME Keyring (Seahorse) or KWallet. On servers or minimal builds, you may need to install this manually. See the official keyring documentation for details.
  • Mobile OS: This module is not intended for use on mobile operating systems (Android, iOS). keyring will 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chutils-2.4.0.tar.gz (27.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chutils-2.4.0-py3-none-any.whl (26.8 kB view details)

Uploaded Python 3

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

Hashes for chutils-2.4.0.tar.gz
Algorithm Hash digest
SHA256 af78a160b2db76ba8222265ed9a17042800c290fe271af04eb90b9ddf1a7fcb3
MD5 7d3af79237e896189d9772b75a847e51
BLAKE2b-256 1972f8dbf5075b507450e01e3a0f87d76e2844f33f0b4860f5ecf81db0ac8e06

See more details on using hashes here.

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

Hashes for chutils-2.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8091c87440dc46a40eb3fb6aa04533017c1ade8c9c085c5033d1ed95e456fa60
MD5 f71785f520bc53d7065c6ba98c085986
BLAKE2b-256 66aa6088fc0a63afae996cacf00cc308e519beebfeac75fed12dc8a634f73526

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page