[project] name = "mostovik-backend" version = "0.1.0" description = "Backend service for Mostovik project" authors = [ {name = "Your Name", email = "your.email@example.com"}, ] requires-python = ">=3.11" dependencies = [ # Django Framework "Django==3.2.25", "djangorestframework==3.14.0", # Database "psycopg2-binary==2.9.9", # Async tasks "celery==5.3.6", "redis==5.0.3", "django-celery-beat==2.6.0", "django-celery-results==2.5.1", # Caching "django-redis==5.4.0", # Data processing "pandas==2.0.3", "numpy==1.24.4", "requests==2.31.0", "beautifulsoup4==4.12.3", # Web scraping "scrapy==2.11.2", "selenium==4.17.2", # Validation and serialization "django-filter==23.5", "django-cors-headers==4.3.1", # Logging and monitoring "python-json-logger==2.0.7", # Utilities "python-dotenv==1.0.1", "python-dateutil==2.8.2", "pytz==2024.1", # Security "cryptography==42.0.5", "djangorestframework-simplejwt>=5.3.1", "drf-yasg>=1.21.10", "pillow>=12.1.0", "python-decouple>=3.8", "coreapi>=2.3.3", "django-rest-swagger>=2.2.0", "model-bakery>=1.17.0", "faker>=40.1.2", "factory-boy>=3.3.0", ] [project.optional-dependencies] dev = [ # WSGI server "gunicorn==21.2.0", "gevent==23.9.1", # Development "django-extensions==3.2.3", "werkzeug==3.0.1", "django-debug-toolbar==4.2.0", # Testing "pytest==7.4.4", "pytest-django==4.7.0", "pytest-cov==4.1.0", "factory-boy==3.3.0", "coverage==7.4.0", # Linters and formatters "flake8==6.1.0", "black==23.12.1", "isort==5.13.2", "ruff==0.1.14", # Documentation "sphinx==7.2.6", "sphinx-rtd-theme==2.0.0", # Monitoring "flower==2.0.1", # CLI tools "click==8.1.7", "typer==0.9.0", # Additional tools "watchdog==3.0.0", # Pre-commit hooks "pre-commit==3.6.0", ] [build-system] requires = ["setuptools>=45", "wheel"] build-backend = "setuptools.build_meta" [tool.setuptools] packages = ["src"] # ================================================================================== # PYTEST CONFIGURATION # ================================================================================== [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "config.settings.test" python_paths = ["src"] testpaths = ["tests"] addopts = [ "--verbose", "--tb=short", "--reuse-db", "--nomigrations", "--strict-markers", "--strict-config", "--color=yes", ] markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", "integration: marks tests as integration tests", "unit: marks tests as unit tests", "models: marks tests for models", "views: marks tests for views", "serializers: marks tests for serializers", "services: marks tests for services", "factories: marks tests for factories", ] filterwarnings = [ "ignore::django.utils.deprecation.RemovedInDjango40Warning", "ignore::django.utils.deprecation.RemovedInDjango41Warning", "ignore::DeprecationWarning", "ignore::PendingDeprecationWarning", ] norecursedirs = [ ".git", ".venv", "__pycache__", "*.egg-info", ".pytest_cache", "node_modules", "migrations", ] # ================================================================================== # COVERAGE CONFIGURATION # ================================================================================== [tool.coverage.run] source = ["src"] omit = [ "*/migrations/*", "*/tests/*", "*/venv/*", "*/virtualenv/*", "*/site-packages/*", "manage.py", "*/settings/*", "*/config/wsgi.py", "*/config/asgi.py", "*/__pycache__/*", ] branch = true relative_files = true [tool.coverage.report] exclude_lines = [ "pragma: no cover", "def __repr__", "if self.debug:", "if settings.DEBUG", "raise AssertionError", "raise NotImplementedError", "if 0:", "if __name__ == .__main__.:", "class .*\\bProtocol\\):", "@(abc\\.)?abstractmethod", ] show_missing = true skip_covered = false precision = 2 [tool.coverage.html] directory = "htmlcov" [tool.coverage.xml] output = "coverage.xml" # ================================================================================== # RUFF CONFIGURATION (Linting and Code Quality) # ================================================================================== [tool.ruff] line-length = 88 target-version = "py311" exclude = [ ".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".mypy_cache", ".nox", ".pants.d", ".pytype", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv", "*/migrations/*", "*/__pycache__/*", ] [tool.ruff.lint] # Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "C", # mccabe "B", # flake8-bugbear "Q", # flake8-quotes "DJ", # flake8-django "UP", # pyupgrade "S", # bandit security "T20", # flake8-print "SIM", # flake8-simplify ] extend-ignore = [ "E501", # line too long, handled by formatter "DJ01", # Missing docstring (too strict for Django) "DJ001", # null=True on string fields (architectural decision) "F403", # star imports (common in Django settings) "F405", # name may be undefined from star imports (Django settings) "E402", # module level import not at top (Django settings) "S101", # Use of assert (common in tests) "T201", # print statements (useful for debugging) ] # Allow autofix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] unfixable = [] # Allow unused variables when underscore-prefixed. dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" [tool.ruff.lint.mccabe] # Unlike Flake8, default to a complexity level of 10. max-complexity = 10 [tool.ruff.lint.per-file-ignores] # Ignore `E402` (import violations) in all `__init__.py` files "__init__.py" = ["E402"] # Ignore star imports and related errors in settings "src/config/settings/*" = ["F403", "F405", "E402"] # Ignore star imports in test runner files "check_tests.py" = ["F403"] "run_tests.py" = ["F403"] "run_tests_simple.py" = ["F403"] # Ignore complexity issues in tests "tests/*" = ["C901", "S101"] "**/test_*" = ["C901", "S101"] "**/tests.py" = ["C901", "S101"] # Ignore security warnings in test factories "tests/**/factories.py" = ["S311"] "**/factories.py" = ["S311"] [tool.ruff.format] # Like Black, use double quotes for strings. quote-style = "double" # Like Black, indent with spaces, rather than tabs. indent-style = "space" # Like Black, respect magic trailing commas. skip-magic-trailing-comma = false # Like Black, automatically detect the appropriate line ending. line-ending = "auto" # ================================================================================== # BLACK CONFIGURATION (Code Formatting) # ================================================================================== [tool.black] line-length = 88 target-version = ['py311'] include = '\.pyi?$' extend-exclude = ''' /( # directories \.eggs | \.git | \.hg | \.mypy_cache | \.tox | \.venv | _build | buck-out | build | dist | migrations )/ ''' # ================================================================================== # ISORT CONFIGURATION (Import Sorting) # ================================================================================== [tool.isort] profile = "black" multi_line_output = 3 line_length = 88 include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true ensure_newline_before_comments = true src_paths = ["src"] skip = ["migrations"] known_django = ["django"] known_third_party = [ "celery", "redis", "requests", "pandas", "numpy", "scrapy", "selenium", "beautifulsoup4", "rest_framework", "django_filters", "corsheaders", "drf_yasg", "model_bakery", "factory", "pytest", ] sections = [ "FUTURE", "STDLIB", "DJANGO", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER", ] # ================================================================================== # MYPY CONFIGURATION (Type Checking) # ================================================================================== [tool.mypy] python_version = "3.11" check_untyped_defs = true ignore_missing_imports = true warn_unused_ignores = true warn_redundant_casts = true warn_unused_configs = true warn_return_any = true warn_unreachable = true strict_optional = true no_implicit_reexport = true show_error_codes = true plugins = ["mypy_django_plugin.main"] [[tool.mypy.overrides]] module = "*.migrations.*" ignore_errors = true [[tool.mypy.overrides]] module = "tests.*" disallow_untyped_defs = false [tool.django-stubs] django_settings_module = "config.settings.development" # ================================================================================== # BANDIT CONFIGURATION (Security) # ================================================================================== [tool.bandit] exclude_dirs = ["tests", "migrations"] tests = ["B201", "B301"] skips = ["B101", "B601"] # ================================================================================== # PYLINT CONFIGURATION # ================================================================================== [tool.pylint.messages_control] disable = [ "C0114", # missing-module-docstring "C0115", # missing-class-docstring "C0116", # missing-function-docstring "R0903", # too-few-public-methods (Django models) "R0901", # too-many-ancestors (Django views) "W0613", # unused-argument (Django views) "C0103", # invalid-name (Django field names) ] [tool.pylint.format] max-line-length = 88 [tool.pylint.design] max-args = 10 max-locals = 25 max-returns = 10 max-branches = 20 # ================================================================================== # DEPENDENCY GROUPS (Alternative to optional-dependencies) # ================================================================================== [dependency-groups] dev = [ "gunicorn==21.2.0", "gevent==23.9.1", "django-extensions==3.2.3", "werkzeug==3.0.1", "django-debug-toolbar==4.2.0", "pytest==7.4.4", "pytest-django==4.7.0", "pytest-cov==4.1.0", "factory-boy==3.3.0", "coverage==7.4.0", "flake8==6.1.0", "black==23.12.1", "isort==5.13.2", "ruff==0.1.14", "sphinx==7.2.6", "sphinx-rtd-theme==2.0.0", "flower==2.0.1", "click==8.1.7", "typer==0.9.0", "watchdog==3.0.0", "pre-commit==3.6.0", "mypy==1.8.0", "django-stubs==4.2.7", "types-requests==2.31.0.20240125", "bandit==1.7.5", ] test = [ "pytest==7.4.4", "pytest-django==4.7.0", "pytest-cov==4.1.0", "pytest-xdist==3.5.0", "pytest-mock==3.12.0", "factory-boy==3.3.0", "model-bakery>=1.17.0", "coverage==7.4.0", ] docs = [ "sphinx==7.2.6", "sphinx-rtd-theme==2.0.0", "sphinx-autodoc-typehints==1.25.2", "myst-parser==2.0.0", ] lint = [ "ruff==0.1.14", "black==23.12.1", "isort==5.13.2", "mypy==1.8.0", "django-stubs==4.2.7", "bandit==1.7.5", "pre-commit==3.6.0", ]