Создавал ли собственные библиотеки или пакеты на Python?

Ответ

Да, создавал. Один из последних пакетов — это внутренняя утилита для конфигурации микросервисов. Она автоматически загружала настройки из Consul, валидировала их по Pydantic-схемам и предоставляла готовый объект конфига с кэшированием.

Структура пакета internal_config:

internal_config/
├── pyproject.toml          # Современная конфигурация с setuptools
├── src/
│   └── internal_config/
│       ├── __init__.py
│       ├── loader.py       # Логика загрузки из Consul/Vault
│       ├── validator.py    # Валидация через Pydantic
│       └── exceptions.py
└── tests/

Ключевые шаги и best practices, которые я применял:

  1. pyproject.toml вместо setup.py: Использовал современный стандарт для указания зависимостей, entry points и метаданных.
  2. Структура src/: Это предотвращает случайный импорт из неинсталлированной версии кода.
  3. Типизация и документация: Полностью типизировал публичные функции и использовал docstring в формате Google. Добавил README.md с примерами использования.
  4. Тестирование и публикация: Настроил pytest с покрытием, а публикацию в приватный Artifactory выполнял через twine.

Пример фрагмента кода из __init__.py:

from .loader import ConfigLoader
from .validator import AppConfig
from typing import Optional
import cachetools

class ConfigurationManager:
    _cache = cachetools.TTLCache(maxsize=10, ttl=300)

    def __init__(self, service_name: str):
        self.service_name = service_name

    def get_config(self) -> AppConfig:
        """Возвращает валидированную конфигурацию для сервиса."""
        if self.service_name not in self._cache:
            loader = ConfigLoader(self.service_name)
            raw_config = loader.fetch()
            self._cache[self.service_name] = AppConfig(**raw_config)
        return self._cache[self.service_name]

Пакет используется в более чем 10 сервисах нашей команды, что упростило управление настройками и их валидацию на этапе запуска.

Ответ 18+ 🔞

А, ну это я помню, ёпта! Создавал, блядь, конечно. Последняя моя поделка — это внутренняя утилитка для конфигурации микросервисов. Представляешь, эта штука сама лезет в Consul, вытаскивает настройки, прогоняет их через Pydantic-схемы, как через мясорубку, и выдаёт тебе готовый, валидный объект конфига, да ещё и закэшированный. Удобно, сука, до безобразия!

Вот как эта мартышлюшка internal_config устроена:

internal_config/
├── pyproject.toml          # Всё по-взрослому, на setuptools
├── src/
│   └── internal_config/
│       ├── __init__.py
│       ├── loader.py       # Тут логика, как из Consul/Vault всё сосать
│       ├── validator.py    # А тут Pydantic всё проверяет
│       └── exceptions.py
└── tests/                  # Без этого никак, а то доверия — ноль ебать

Что я там накрутил, какие best practices соблюдал:

  1. pyproject.toml вместо старого setup.py: Ёперный театр, 21 век на дворе, пора уже на современные стандарты переходить. Там и зависимости, и entry points, и всё прочее.
  2. Структура src/: Обязательная штука, чувак. Чтобы случайно не импортировать код, который ещё не установлен. Иначе потом волнение ебать — «оно у меня на машине работало!».
  3. Типизация и документы: Все публичные функции затипизировал, docstring накидал. README.md с примерами, чтобы даже самый упоротый коллега разобрался. Иначе потом подозрение ебать чувствую — кто и как это использует.
  4. Тесты и публикация: pytest с покрытием настроил, а в приватный Artifactory через twine заливал. Без этого — пидарас шерстяной, а не разработчик.

Смотри, кусочек кода из __init__.py для наглядности:

from .loader import ConfigLoader
from .validator import AppConfig
from typing import Optional
import cachetools

class ConfigurationManager:
    _cache = cachetools.TTLCache(maxsize=10, ttl=300)

    def __init__(self, service_name: str):
        self.service_name = service_name

    def get_config(self) -> AppConfig:
        """Возвращает валидированную конфигурацию для сервиса."""
        if self.service_name not in self._cache:
            loader = ConfigLoader(self.service_name)
            raw_config = loader.fetch()
            self._cache[self.service_name] = AppConfig(**raw_config)
        return self._cache[self.service_name]

В общем, эта хитрая жопа теперь в десяти с лишним сервисах нашей команды болтается. Управлять настройками стало в разы проще, а валидация на старте сразу отсекает всякий пиздец из-за опечаток в конфигах. Красота, блядь!