Отлично. На счет ошибок:
23:1: E265 block comment should start with ’# ’
24:33: E262 inline comment should start with ’# ’
— Не знаю как исправить. Что-то странное. Думаю нужно пересмотреть количество коментов. Постарайся их минимизировать. Если правильно именовать и структурировать, коменты не понадобятся.
На счет radon — очень хорошо.
Насчет
F 77:0 main — C
— если еще не разобралась с цикломатической сложностью, дело в количестве условных блоков. Нужно стараться разбить main() на набор более мелких функций.
Привет, твое сообщение пришло. Отправил тебе свой контакт в телеграмме, пиши туда.
Мой профиль в менторботе — t.me/...ot?start=mentor-157648379
Ничего не получил. Похоже нужно репортить на ДОУ баг :)
Ты не получала личного сообщения? Продублирую здесь:
1) Перенеси код из if __name__ == ’__main__’ в функцию main().
2) Убери print() из исключений. Параметры в них тоже лишние.
3) Прогони свой скрипт через утилиту pypi.org/project/flake8 с плагином pypi.org/...roject/flake8-docstrings. Это позволит привести код в соответствие со стандартами PEP8 и PEP257.
4) Прогони свой код через утилиту pypi.org/project/radon. Рефактори пока не получится добиться индекса A для всех функций.
Заинтересовался идеей и пошёл почитать код на гитхабе. Могу дать пару советов, пиши в личку.
Да. Вот как выглядит контейнер побольше:
"""Containers module.""" import logging.config import sqlite3 import boto3 from dependency_injector import containers, providers from . import services class Container(containers.DeclarativeContainer): config = providers.Configuration() configure_logging = providers.Callable( logging.config.fileConfig, fname='logging.ini', ) # Gateways database_client = providers.Singleton( sqlite3.connect, config.database.dsn, ) s3_client = providers.Singleton( boto3.client, service_name='s3', aws_access_key_id=config.aws.access_key_id, aws_secret_access_key=config.aws.secret_access_key, ) # Services user_service = providers.Factory( services.UserService, db=database_client, ) auth_service = providers.Factory( services.AuthService, db=database_client, token_ttl=config.auth.token_ttl.as_int(), ) photo_service = providers.Factory( services.PhotoService, db=database_client, s3=s3_client, )
Factory провайдер photo_service зависит от от Singleton-провайдеров s3_client и database_client и т. д.
При вызове провайдер photo_service будет всегда создавать новый объект, а в качестве зависимостей будут передаваться единожды созданные объекты провайдеров database_client и s3_client.
Если под управлением ресурсами имеется ввиду время жизни объектов, то да — за счет разных провайдеров:
Про провайдеры можно почитать тут.
Про другие фичи можно почитать тут.
Коллаборацию сложно делать без архитектуры, техлида, код ревью, процессов, системы контроля версий и таск менеджера.
В Python есть typing. Он используется в примерах в посте.
Переходы по Ctrl + клик работают во всех примерах в этом посте.
Это достигается за счет
Service.__init__(self, api_client: ApiClient)
можно нажать на ApiClient и перейти к его определению.Вот как раз гибкость и понятность кода обычно противоположны. И любые абстракции очень тяжело разруливать.
В PEP20 есть такой принцип «Complex is better than complicated». Вот пример иллюстрации: pbs.twimg.com/...media/Bky1fNJCQAAztUg.png
Бывают простые (1), сложные (2) и сложные и запутанные проекты (3). Принцип dependency injection помогает перейти от сложного и запутанного проекта (3) к просто сложному (2).
Когда у вас будет контейнер со всеми компонентами и их зависимости по проекту нужно будет гораздо реже передвигаться поиском.
на серйознішу мову
Python — несерьезный язык?
На счет контрибьюторов.
Создатель pinject не занимается своим фреймворком с 14 года. Я занимаюсь Dependency Injector постоянно. Не всегда много контрибьюторов == хорошая поддержка. Наличие лидера в опенсорс проекте — решающий фактор.
Я поддерживаю Dependency Injector самостоятельно. Непофикшенных багов в нем нет. Простые баги фикшу за часы. Фичи занимают дни или недели. Спорные фичи могут занять несколько месяцев так как функционал добавляю аккуратно. Если сомневаюсь в необходимости или потенциальной опасности фичи, даю автору временное решение и оставляю ее «на подумать» перед добавлением в фреймворк.
Если хотите присоединиться, пишите в личку. Помощи буду рад.
Приятно, когда твой фреймворк сравнивают с Ansible. Это первый раз, спасибо :)
Количество даунлоадов ни о чем
«ни о чем» — неконструктивный аргумент. Dependency Injector скачивают в 10 раз больше, чем pinject.
Работаю над обновлением доки сейчас. Примерами тоже займусь. Про композит не понял. Если что пишите в личку, соберём что-то вместе.
Я переписывал Dependency Injector на Cython по двум причинам:
Как бонус удалось получить неплохой прирост производительности.
Проблем при переписывании было немало. После тоже. Второй бы раз хорошо подумал над этим шагом.
Да, есть такой. Переходите на Dependency Injector, он лучше чем pinject.
Dependency Injector отличается от pinject такими вещами:
Да, нужно было это описать. Я уже пошел и поменял README. Пост трогать уже не буду для исторической сохранности :) Еще раз спасибо за вопросы
Классные вопросы, спасибо. Отвечаю:
1. Все зливати в один конфіг не завжди зручно.
Да, правда. Dependency Injector поддерживает работу с несколькими контейнерами. Есть 2 варианта:
Навіщо цілий фреймворк для такої речі.
Когда применяешь dependency injection код сборки объектов становится вот таким:
service = Service(ApiClient(config['api_key'], config['timeout']))
Такой код со временем дублируется и менять структуру становится тяжелее. Dependency Injector помогает описать сборку в одном месте и убрать дублирование:
service = container.service()
Еще Dependency Injector дает бонус в виде переопределения любого провайдера с помощью метода .override()
:
from unittest import mock with container.api_client.override(mock.Mock()): service = container.service() assert isinstance(service.api_client, mock.Mock)
Это помогает при тестировании. Можно применять для настройки проекта для работы в разных окружениях: подставить стабы для API на дев и стейдж.
Архітектура підбирається під конкретний проект індивідуально і має, як правило, свої особливості.
Dependency Injector не привязывает к определенной архитектуре. Он помогает собирать код, который написан по принципу dependency injection. Его можно применять для построения проекта с нуля и для части проекта. Такое обычно происходит при пошаговом рефакторинге.
Нет. Проект с закрытым исходным кодом. Планируем сделать технический пост. В нём расскажем как все устроено.
Такая проблема есть. Кроме **kwargs есть еще C extensions, для которых совсем ничего не работает. Решить эту проблему можно на уровне библиотеки написав вот такой тайпинг стаб: github.com/...cy_injector/providers.pyi
IDE и mypy смотрят на стаб для автокомплита и проверок. Стаб лежит рядом с основным модулем и не участвует в выполнении. Проблема в том, что такие стабы писать и поддерживать дорого. Для опенсорс библиотеки цена оправдана, а для коммерческого приложения может быть дорого.