feat(core): add core module with mixins, services, and background jobs
- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc. - Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin - Add Base ViewSets with bulk operations - Add BackgroundJob model for Celery task tracking - Add BaseAppCommand for management commands - Add permissions, pagination, filters, cache, logging - Migrate tests to factory_boy + faker - Add CHANGELOG.md - 297 tests passing
This commit is contained in:
351
pyproject.toml
351
pyproject.toml
@@ -45,6 +45,8 @@ dependencies = [
|
||||
"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]
|
||||
@@ -52,43 +54,39 @@ 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",
|
||||
|
||||
# Debugging (removed due to compatibility issues)
|
||||
# "ipdb==0.13.13",
|
||||
# "pdbpp==0.10.3",
|
||||
|
||||
|
||||
# Additional tools
|
||||
"watchdog==3.0.0",
|
||||
|
||||
|
||||
# Pre-commit hooks
|
||||
"pre-commit==3.6.0",
|
||||
]
|
||||
@@ -100,32 +98,101 @@ 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]
|
||||
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
||||
lint.select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"C", # mccabe
|
||||
"B", # flake8-bugbear
|
||||
"Q", # flake8-quotes
|
||||
"DJ", # flake8-django
|
||||
]
|
||||
line-length = 88
|
||||
target-version = "py311"
|
||||
|
||||
lint.extend-ignore = [
|
||||
"E501", # line too long, handled by formatter
|
||||
"DJ01", # Missing docstring (too strict for Django)
|
||||
]
|
||||
|
||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
||||
lint.fixable = ["ALL"]
|
||||
lint.unfixable = []
|
||||
|
||||
# Allow unused variables when underscore-prefixed.
|
||||
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
exclude = [
|
||||
".bzr",
|
||||
".direnv",
|
||||
@@ -152,11 +219,40 @@ exclude = [
|
||||
"*/__pycache__/*",
|
||||
]
|
||||
|
||||
# Same as Black.
|
||||
line-length = 88
|
||||
[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
|
||||
]
|
||||
|
||||
# Assume Python 3.11.
|
||||
target-version = "py311"
|
||||
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.
|
||||
@@ -165,10 +261,19 @@ 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"]
|
||||
"**/test_*" = ["C901"]
|
||||
"**/tests.py" = ["C901"]
|
||||
"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.
|
||||
@@ -183,6 +288,132 @@ 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",
|
||||
@@ -204,8 +435,38 @@ dev = [
|
||||
"flower==2.0.1",
|
||||
"click==8.1.7",
|
||||
"typer==0.9.0",
|
||||
"ipdb==0.13.13",
|
||||
"pdbpp==0.10.3",
|
||||
"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",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user