Problem: - Ruff removed 'from app.core.database import Base' from models/database/base.py - Import appeared "unused" (F401) but was actually a critical re-export - Caused ImportError: cannot import name 'Base' at runtime - Re-export pattern: import in one file to export from package Solution: 1. Added F401 ignore for models/database/base.py in pyproject.toml 2. Created scripts/verify_critical_imports.py verification script 3. Integrated verification into make check and CI pipeline 4. Updated documentation with explanation New Verification Script: - Checks all critical re-export imports exist - Detects import variations (parentheses, 'as' clauses) - Handles SQLAlchemy declarative_base alternatives - Runs as part of make check automatically Protected Files: - models/database/base.py - Re-exports Base for all models - models/__init__.py - Exports Base for Alembic - models/database/__init__.py - Exports Base from package - All __init__.py files (already protected) Makefile Changes: - make verify-imports - Run import verification - make check - Now includes verify-imports - make ci - Includes verify-imports in pipeline Documentation Updated: - Code quality guide explains re-export protection - Pre-commit workflow includes verification - Examples of why re-exports matter This prevents future issues where linters remove seemingly "unused" imports that are actually critical for application structure. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
162 lines
4.2 KiB
TOML
162 lines
4.2 KiB
TOML
[build-system]
|
|
requires = ["setuptools>=45", "wheel"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "letzshop-product-import"
|
|
version = "0.1.0"
|
|
description = "Multi-tenant e-commerce marketplace platform"
|
|
requires-python = ">=3.11"
|
|
|
|
# =============================================================================
|
|
# RUFF - Modern All-in-One Linter & Formatter
|
|
# =============================================================================
|
|
[tool.ruff]
|
|
line-length = 88
|
|
target-version = "py311"
|
|
|
|
# Exclude directories
|
|
exclude = [
|
|
".git",
|
|
".venv",
|
|
"venv",
|
|
"__pycache__",
|
|
".mypy_cache",
|
|
".pytest_cache",
|
|
".ruff_cache",
|
|
"build",
|
|
"dist",
|
|
"alembic/versions",
|
|
]
|
|
|
|
[tool.ruff.lint]
|
|
# Enable comprehensive rule sets
|
|
select = [
|
|
"E", # pycodestyle errors
|
|
"W", # pycodestyle warnings
|
|
"F", # pyflakes
|
|
"I", # isort (import sorting)
|
|
"N", # pep8-naming
|
|
"UP", # pyupgrade (modern Python syntax)
|
|
"B", # flake8-bugbear (common bugs)
|
|
"C4", # flake8-comprehensions
|
|
"SIM", # flake8-simplify
|
|
"PIE", # flake8-pie
|
|
"RET", # flake8-return
|
|
"Q", # flake8-quotes
|
|
]
|
|
|
|
# Ignore specific rules
|
|
ignore = [
|
|
"E501", # line too long (handled by formatter)
|
|
"B008", # do not perform function calls in argument defaults (FastAPI Depends)
|
|
"RET504", # unnecessary variable assignment before return
|
|
"SIM102", # use a single if statement instead of nested if (sometimes less readable)
|
|
]
|
|
|
|
# Allow autofix for all rules
|
|
fixable = ["ALL"]
|
|
unfixable = []
|
|
|
|
# Per-file ignores
|
|
[tool.ruff.lint.per-file-ignores]
|
|
# Ignore import violations in __init__.py files (re-exports)
|
|
"__init__.py" = ["F401", "F403"]
|
|
# Base files that re-export (re-export Base from core.database)
|
|
"models/database/base.py" = ["F401"]
|
|
# Ignore specific rules in test files
|
|
"tests/**/*.py" = ["S101", "PLR2004"]
|
|
# Alembic migrations can have longer lines and specific patterns
|
|
"alembic/versions/*.py" = ["E501", "F401"]
|
|
|
|
# Import sorting configuration (replaces isort)
|
|
[tool.ruff.lint.isort]
|
|
known-first-party = ["app", "models", "middleware", "tasks", "storage", "scripts"]
|
|
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
|
|
split-on-trailing-comma = true
|
|
|
|
# Formatter configuration (replaces black)
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
skip-magic-trailing-comma = false
|
|
line-ending = "auto"
|
|
|
|
# =============================================================================
|
|
# MYPY - Static Type Checker
|
|
# =============================================================================
|
|
[tool.mypy]
|
|
python_version = "3.11"
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
disallow_untyped_defs = false
|
|
ignore_missing_imports = true
|
|
exclude = [
|
|
"^\\.venv/",
|
|
"^venv/",
|
|
"^build/",
|
|
"^dist/",
|
|
"^alembic/versions/",
|
|
]
|
|
|
|
# Per-module options
|
|
[[tool.mypy.overrides]]
|
|
module = "tests.*"
|
|
ignore_errors = true
|
|
|
|
[[tool.mypy.overrides]]
|
|
module = "alembic.*"
|
|
ignore_errors = true
|
|
|
|
# =============================================================================
|
|
# PYTEST - Testing
|
|
# =============================================================================
|
|
[tool.pytest.ini_options]
|
|
minversion = "7.0"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py", "*_test.py"]
|
|
python_classes = ["Test*"]
|
|
python_functions = ["test_*"]
|
|
addopts = [
|
|
"-v",
|
|
"--strict-markers",
|
|
"--strict-config",
|
|
"--color=yes",
|
|
]
|
|
markers = [
|
|
"unit: Unit tests",
|
|
"integration: Integration tests",
|
|
"slow: Slow running tests",
|
|
]
|
|
filterwarnings = [
|
|
"ignore::DeprecationWarning",
|
|
]
|
|
|
|
# =============================================================================
|
|
# COVERAGE
|
|
# =============================================================================
|
|
[tool.coverage.run]
|
|
source = ["app", "models", "middleware", "tasks", "storage"]
|
|
omit = [
|
|
"*/tests/*",
|
|
"*/__pycache__/*",
|
|
"*/venv/*",
|
|
"*/.venv/*",
|
|
"*/alembic/*",
|
|
"*/scripts/*",
|
|
]
|
|
|
|
[tool.coverage.report]
|
|
precision = 2
|
|
show_missing = true
|
|
skip_covered = false
|
|
exclude_lines = [
|
|
"pragma: no cover",
|
|
"def __repr__",
|
|
"raise AssertionError",
|
|
"raise NotImplementedError",
|
|
"if __name__ == .__main__.:",
|
|
"if TYPE_CHECKING:",
|
|
"if typing.TYPE_CHECKING:",
|
|
]
|