[build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "pecflow-backend" version = "1.0.0" description = "PecFlow – Backend API per gestione PEC SaaS" requires-python = ">=3.12" dependencies = [ # Web framework "fastapi>=0.115.0", "uvicorn[standard]>=0.30.0", # Database "sqlalchemy>=2.0.36", "asyncpg>=0.29.0", # driver async PostgreSQL "psycopg2-binary>=2.9.9", # driver sync (Alembic) "alembic>=1.13.0", # Validazione e configurazione "pydantic>=2.9.0", "pydantic-settings>=2.5.0", "email-validator>=2.2.0", # Autenticazione e sicurezza "python-jose[cryptography]>=3.3.0", "bcrypt>=4.0.0", # password hashing (usato direttamente, senza passlib) "pyotp>=2.9.0", # TOTP 2FA "qrcode[pil]>=7.4.2", # generazione QR code TOTP "cryptography>=43.0.0", # AES-256-GCM cifratura credenziali # Rate limiting "slowapi>=0.1.9", # Job queue (client per enqueue job verso worker arq) "arq>=0.26.1", # SMTP async (per test connessione casella) "aiosmtplib>=3.0.0", # HTTP client "httpx>=0.27.0", # Storage MinIO/S3 "miniopy-async>=1.21.0", # IMAP async (per test connessione nel backend + mailbox service) "aioimaplib>=2.0.0", # Redis (async – per WebSocket pub/sub) "redis[asyncio]>=5.0.0", # WebSocket "websockets>=12.0", # Utilities "python-multipart>=0.0.9", # upload file "python-dotenv>=1.0.0", ] [project.optional-dependencies] dev = [ # Test "pytest>=8.3.0", "pytest-asyncio>=0.24.0", "pytest-cov>=5.0.0", "httpx>=0.27.0", # test client FastAPI "anyio>=4.6.0", "aiosqlite>=0.20.0", # driver SQLite async per i test di integrazione # Linting e formatting "ruff>=0.7.0", "mypy>=1.13.0", ] [tool.setuptools.packages.find] where = ["."] include = ["app*"] # ─── Ruff ───────────────────────────────────────────────────────────────────── [tool.ruff] target-version = "py312" line-length = 100 src = ["app", "tests"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade ] ignore = ["E501", "B008", "B904"] [tool.ruff.lint.isort] known-first-party = ["app"] # ─── MyPy ───────────────────────────────────────────────────────────────────── [tool.mypy] python_version = "3.12" strict = false ignore_missing_imports = true plugins = ["pydantic.mypy"] # ─── Pytest ─────────────────────────────────────────────────────────────────── [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] filterwarnings = [ "ignore::DeprecationWarning", "ignore::PendingDeprecationWarning", ] # ─── Coverage ───────────────────────────────────────────────────────────────── [tool.coverage.run] source = ["app"] omit = ["tests/*", "alembic/*"] [tool.coverage.report] show_missing = true fail_under = 70