[build-system] requires = ["setuptools>=68.0"] build-backend = "setuptools.build_meta" [project] name = "tatlock" version = "2.3.0" description = "OpenAI-compatible API with Ollama backend" requires-python = ">=3.12" dependencies = [ "fastapi>=0.123,<0.124", "uvicorn[standard]>=0.38,<0.39", "pydantic>=2.11,<2.13", "pydantic-settings>=2.12,<2.13", "pydantic-ai-slim[openai,anthropic]>=1.27,<1.28", "anthropic>=0.77,<1.0", "httpx>=0.28,<0.29", "sse-starlette>=3.0,<3.1", "python-dotenv>=1.2,<1.3", "starlette>=0.45,<0.46", "redis[hiredis]>=5.2,<6.0", "qdrant-client>=1.12,<2.0", "structlog>=24.1,<25.0", ] [project.optional-dependencies] dev = [ "pytest>=8.3,<8.4", "pytest-asyncio>=0.25,<0.26", "pytest-cov>=6.0,<6.1", "pytest-mock>=3.14,<3.15", "ruff>=0.8,<0.9", "mypy>=1.14,<1.15", "faker>=34.0,<35.0", "coverage[toml]>=7.7,<7.8", ] [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" cache_dir = ".cache/pytest" markers = [ "unit: Unit tests", "integration: Integration tests", "slow: Slow running tests", "contract: Wire-level contract tests against live service boundaries", ] addopts = [ "--verbose", "--strict-markers", "--tb=short", "--cov=src", "--cov-report=term-missing", "--cov-report=html:build/coverage/html", "--cov-report=xml:build/coverage/coverage.xml", "--cov-branch", ] filterwarnings = [ "ignore::DeprecationWarning", ] [tool.coverage.run] source = ["src"] branch = true data_file = "build/coverage/.coverage" omit = [ "*/tests/*", "*/__pycache__/*", "*/site-packages/*", "*/.venv/*", ] [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:", "@abstractmethod", ] [tool.coverage.html] directory = "build/coverage/html" [tool.coverage.xml] output = "build/coverage/coverage.xml" [tool.ruff] line-length = 100 target-version = "py312" cache-dir = ".cache/ruff" [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade ] ignore = [ "E501", # line too long (handled by formatter) "B008", # do not perform function calls in argument defaults "C901", # too complex ] [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] [tool.mypy] python_version = "3.12" cache_dir = ".cache/mypy" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true disallow_incomplete_defs = true check_untyped_defs = true no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true warn_no_return = true strict_equality = true [[tool.mypy.overrides]] module = ["sse_starlette.*", "pydantic_ai.*"] ignore_missing_imports = true