[project]
name = "mypylogger"
version = "0.2.3"
description = "Zero-dependency JSON logging library with sensible defaults for Python applications"
readme = "README.md"
license = {text = "MIT"}
authors = [{name = "Stephen Abbot", email = "admin@bittikens.com"}]
maintainers = [{name = "Stephen Abbot", email = "admin@bittikens.com"}]
requires-python = ">=3.8"
keywords = [
    "logging",
    "json", 
    "structured-logging",
    "zero-dependency",
    "python-logging",
    "json-formatter",
    "application-logging",
    "development-tools"
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Intended Audience :: System Administrators",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Software Development :: Libraries :: Python Modules",
    "Topic :: System :: Logging",
    "Topic :: System :: Systems Administration",
    "Topic :: Software Development :: Debuggers",
    "Typing :: Typed",
]
dependencies = []

[project.urls]
Homepage = "https://github.com/stabbotco1/mypylogger"
Documentation = "https://stabbotco1.github.io/mypylogger"
Repository = "https://github.com/stabbotco1/mypylogger"
"Bug Tracker" = "https://github.com/stabbotco1/mypylogger/issues"
Changelog = "https://github.com/stabbotco1/mypylogger/blob/main/CHANGELOG.md"
"Source Code" = "https://github.com/stabbotco1/mypylogger"
"Download" = "https://pypi.org/project/mypylogger/"

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

[tool.hatch.build.targets.wheel]
packages = ["src/mypylogger"]

[dependency-groups]
dev = [
    "bandit>=1.7.10",
    "boto3>=1.37.38",
    "build>=1.0.0",
    "bump2version>=1.0.1",
    "codespell>=2.4.1",
    "deptry>=0.20.0",
    "interrogate>=1.7.0",
    "mypy>=1.14.1",
    "pip-audit>=2.7.3",
    "pytest>=8.3.5",
    "pytest-benchmark>=4.0.0",
    "pytest-cov>=5.0.0",
    "requests>=2.32.4",
    "ruff>=0.14.1",
    "safety>=3.6.2",
    "sphinx-lint>=1.0.0",
    "tomli>=2.0.0 ; python_full_version < '3.11'",
    "twine>=5.0.0",
]
security = [
    "pyyaml>=6.0.3",
]
docs = [
    "sphinx>=7.1.0",
    "sphinx-rtd-theme>=2.0.0",
    "sphinx-autodoc-typehints>=1.25.0",
]

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
    "--cov=mypylogger",
    "--cov-report=term-missing",
    "--cov-report=html:htmlcov",
    "--cov-fail-under=95",
    "--strict-markers",
    "--strict-config",
    "-v"
]
markers = [
    "unit: Unit tests",
    "integration: Integration tests",
    "slow: Slow running tests"
]
filterwarnings = [
    "error",
    "ignore::UserWarning",
    "ignore::DeprecationWarning"
]

[tool.coverage.run]
source = ["src"]
branch = true
omit = [
    "tests/*",
    "*/tests/*",
    "*/__pycache__/*",
    "*/site-packages/*"
]

[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__.:"
]
show_missing = true
skip_covered = false

[tool.mypy]
python_version = "3.9"
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
show_error_codes = true
show_error_context = true
pretty = true

# Paths and modules
mypy_path = "src"
packages = ["mypylogger"]
namespace_packages = true

# Import discovery
ignore_missing_imports = false
follow_imports = "normal"
follow_imports_for_stubs = true

# Platform configuration
platform = "linux"

# Error output
show_column_numbers = true
show_absolute_path = true
color_output = true
error_summary = true

# Strict mode components (enabled individually for clarity)
strict = true

[tool.ruff]
# Line length configuration
line-length = 100
target-version = "py38"

# Exclude files and directories
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",
    "htmlcov",
]

[tool.ruff.lint]
# Enable specific 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
    "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-specific rules
    "PERF", # Perflint
    "RUF", # Ruff-specific rules
]

# Ignore specific rules that may be too strict for this project
ignore = [
    "D100", # Missing docstring in public module
    "D104", # Missing docstring in public package
    "D203", # 1 blank line required before class docstring (conflicts with D211)
    "D213", # Multi-line docstring summary should start at the second line (conflicts with D212)
    "S101", # Use of assert detected (allow in tests)
    "PLR0913", # Too many arguments to function call
    "COM812", # Trailing comma missing (handled by formatter)
    "ISC001", # Implicitly concatenated string literals (handled by formatter)
    "T201", # Print statements (needed for error logging to stderr)
    "BLE001", # Broad exception catching (intentional for graceful degradation)
    "DTZ005", # datetime.now() without timezone (acceptable for log filenames)
    "TRY300", # Consider moving to else block (acceptable pattern)
    "S110", # try-except-pass (acceptable for error suppression)
    "SIM105", # Use contextlib.suppress (prefer explicit try-except)
    "SLF001", # Private member access (needed for sys._getframe)
]

# Allow fix for all fixable rules
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[tool.ruff.format]
# Use double quotes for strings
quote-style = "double"

# Indent with spaces, rather than tabs
indent-style = "space"

# Respect magic trailing commas
skip-magic-trailing-comma = false

# Automatically detect the appropriate line ending
line-ending = "auto"

[tool.ruff.lint.per-file-ignores]
# Tests can use magic values, assertions, print statements, and access private members
"tests/**/*" = ["PLR2004", "S101", "T201", "T203", "SLF001", "SIM117", "S603", "S607", "DTZ011", "PLC0415"]
# Documentation validation scripts need subprocess calls
"scripts/validate_documentation.py" = ["S603", "PERF203"]

[tool.ruff.lint.pydocstyle]
# Use Google-style docstrings
convention = "google"

[tool.ruff.lint.isort]
# Import sorting configuration
known-first-party = ["mypylogger"]
force-single-line = false
force-sort-within-sections = true

[tool.deptry]
# Configure deptry to understand our project structure
extend_exclude = [
    "docs/",
    "htmlcov/",
    ".venv/",
    "build/",
    "dist/",
    "scripts/",
    "infrastructure/",
    "debug_*.py",
]

# Ignore specific packages that are legitimately used from different dependency groups
[tool.deptry.per_rule_ignores]
# DEP004: imported but declared as dev dependency
# tomli is used in scripts (dev context) and is in dev group - this is correct
# yaml is used in security modules and is in security group - this is correct
# requests is used conditionally in monitoring (dev/testing context) and is in dev group - this is correct
DEP004 = ["tomli", "yaml", "requests"]
# DEP001: imported but missing from dependency definitions
# validate_security_yaml is a script module, not a package dependency
DEP001 = ["validate_security_yaml"]

[tool.bumpversion]
current_version = "0.2.2"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
search = "{current_version}"
replace = "{new_version}"
tag = true
sign_tags = false
tag_name = "v{new_version}"
tag_message = "Bump version: {current_version} → {new_version}"
allow_dirty = false
commit = true
message = "Bump version: {current_version} → {new_version}"

[[tool.bumpversion.files]]
filename = "pyproject.toml"
search = 'version = "{current_version}"'
replace = 'version = "{new_version}"'
