[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "injectq"
dynamic = ["version"]
description = "Modern Python dependency injection library combining simplicity, power, and performance"
readme = "README.md"
license = "MIT"
requires-python = ">=3.10"
authors = [
    { name = "InjectQ Contributors" },
]
keywords = [
    "dependency-injection",
    "di",
    "ioc",
    "inversion-of-control",
    "container",
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Software Development :: Libraries :: Python Modules",
    "Topic :: Software Development :: Libraries",
    "Typing :: Typed",
]
dependencies = [
    "typing-extensions>=4.0.0",
]

[project.optional-dependencies]
fastapi = ["fastapi>=0.68.0"]
fastmcp = ["fastmcp>=2.14.0"]
taskiq = ["taskiq>=0.9.0"]
testing = ["pytest>=6.0.0", "pytest-asyncio>=0.21.0", "pytest-benchmark>=4.0.0"]
dev = [
    "pytest>=6.0.0",
    "pytest-benchmark>=4.0.0",
    "pytest-asyncio>=0.21.0",
    "pytest-cov>=3.0.0",
    "mypy>=1.0.0",
    "black>=22.0.0",
    "flake8>=4.0.0",
    "isort>=5.0.0",
    "httpx>=0.28.1",
    "taskiq>=0.11.18",
    "fastapi>=0.68.0",
    "fastmcp>=2.14.0"
]

[project.urls]
Homepage = "https://github.com/Iamsdt/injectq"
Documentation = "https://github.com/Iamsdt/injectq"
Repository = "https://github.com/Iamsdt/injectq"
Issues = "https://github.com/Iamsdt/injectq/issues"

[tool.hatch.version]
path = "injectq/__init__.py"

[tool.hatch.build.targets.wheel]
packages = ["injectq"]

[tool.black]
line-length = 88
target-version = ['py38']
include = '\.pyi?$'
extend-exclude = '''
/(
  # directories
  \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | build
  | dist
)/
'''

[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88

[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
strict = true
show_error_codes = true

# Allow certain flexibilities for dependency injection patterns
[[tool.mypy.overrides]]
module = "injectq.decorators.*"
allow_untyped_decorators = true

[[tool.mypy.overrides]]
module = "injectq.utils.types"
allow_any_generics = true

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
asyncio_mode = "auto"
addopts = [
    "--strict-markers",
    "--strict-config",
    "--cov=injectq",
    "--cov-fail-under=73",
    "--cov-report=term-missing:skip-covered",
    "--cov-report=html",
    "--cov-report=xml",
]
markers = [
    "slow: marks tests as slow (deselect with '-m \"not slow\"')",
    "integration: marks tests as integration tests",
    "asyncio: marks tests as async",
]

[tool.coverage.run]
source = ["injectq"]
omit = [
    "*/tests/*",
    "*/test_*",
    "*/__pycache__/*",
]

[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",
]

[tool.ruff]
target-version = "py310"
line-length = 88
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",
]

[tool.ruff.lint]
# Enable comprehensive rule sets
select = [
    "E",   # pycodestyle errors
    "W",   # pycodestyle warnings
    "F",   # pyflakes
    "I",   # isort
    "N",   # pep8-naming
    "D",   # pydocstyle
    "UP",  # pyupgrade
    "YTT", # flake8-2020
    "ANN", # flake8-annotations
    "S",   # flake8-bandit
    "BLE", # flake8-blind-except
    "FBT", # flake8-boolean-trap
    "B",   # flake8-bugbear
    "A",   # flake8-builtins
    "COM", # flake8-commas
    "C4",  # flake8-comprehensions
    "DTZ", # flake8-datetimez
    "T10", # flake8-debugger
    "EM",  # flake8-errmsg
    "EXE", # flake8-executable
    "FA",  # flake8-future-annotations
    "ISC", # flake8-implicit-str-concat
    "ICN", # flake8-import-conventions
    "G",   # flake8-logging-format
    "INP", # flake8-no-pep420
    "PIE", # flake8-pie
    "T20", # flake8-print
    "PYI", # flake8-pyi
    "PT",  # flake8-pytest-style
    "Q",   # flake8-quotes
    "RSE", # flake8-raise
    "RET", # flake8-return
    "SLF", # flake8-self
    "SLOT", # flake8-slots
    "SIM", # flake8-simplify
    "TID", # flake8-tidy-imports
    "TCH", # flake8-type-checking
    "INT", # flake8-gettext
    "ARG", # flake8-unused-arguments
    "PTH", # flake8-use-pathlib
    "ERA", # eradicate
    "PD",  # pandas-vet
    "PGH", # pygrep-hooks
    "PL",  # pylint
    "TRY", # tryceratops
    "FLY", # flynt
    "NPY", # numpy
    "PERF", # perflint
    "FURB", # refurb
    "LOG", # flake8-logging
    "RUF", # ruff-specific rules
]

ignore = [
    "D100", # Missing docstring in public module
    "D101", # Missing docstring in public class
    "D102", # Missing docstring in public method
    "D103", # Missing docstring in public function
    "D104", # Missing docstring in public package
    "D105", # Missing docstring in magic method
    "D106", # Missing docstring in public nested class
    "D107", # Missing docstring in __init__
    "ANN101", # Missing type annotation for self
    "ANN102", # Missing type annotation for cls
    "FBT001", # Boolean-typed positional argument in function
    "FBT002", # Boolean-typed positional argument in method
    "S101", # Use of assert detected
    "PLR0913", # Too many arguments to function call
    "PLR2004", # Magic value used in comparison
    "COM812", # Missing trailing comma (conflicts with formatter)
    "ISC001", # Implicit string concatenation (conflicts with formatter)
    "ANN401", # Missing type annotation for function
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101", "PLR2004", "ANN001", "ANN201", "D"]
"examples/*" = ["T201", "ANN001", "ANN201", "D"]
"injectq/__init__.py" = ["F401"]  # Allow unused imports in __init__.py

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint.isort]
known-first-party = ["injectq"]
force-single-line = false
lines-after-imports = 2

[dependency-groups]
dev = [
    "mkdocs>=1.6.1",
    "mkdocs-autorefs>=1.4.3",
    "mkdocs-gen-files>=0.5.0",
    "mkdocs-literate-nav>=0.6.2",
    "mkdocs-material>=9.6.18",
    "mkdocs-material-extensions>=1.3.1",
    "mkdocstrings>=0.30.0",
    "mypy>=1.17.1",
    "pytest-asyncio>=1.1.0",
    "pytest-benchmark>=4.0.0",
    "pytest-cov>=6.2.1",
    "ruff>=0.12.11",
    "twine>=6.1.0",
]
