[project]
name = "cz-billing-generator"
dynamic = ["version"]
description = "CLI tool for generating and uploading synthetic billing data to CloudZero"
readme = "README.md"
requires-python = ">=3.10"
license = "LicenseRef-Proprietary"
authors = [
    { name = "CloudZero", email = "support@cloudzero.com" },
]
keywords = [
    "CloudZero",
    "czbg",
    "billing",
    "generator",
    "cli"
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Natural Language :: English",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Operating System :: MacOS",
    "Operating System :: Unix"
]

dependencies = [
    "typer>=0.9.0",
    "polars>=0.20.0",
    "pyyaml>=6.0.0",
    "rich>=14.0.0",
    "python-dotenv>=1.1.0",
    "boto3>=1.26.0",
    "requests>=2.32.0",
    "tenacity>=9.0.0",
    "psutil>=6.1.0",
    "numpy>=1.24.0",
    "python-dateutil>=2.8.0",
    "pytz>=2024.1",
]

[project.scripts]
czbg = "src.czbillgen:app"

[project.urls]
Homepage = "https://github.com/cloudzero/czbillgen"

[build-system]
requires = ["build", "setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["."]
include = ["src*"]
namespaces = true

[tool.setuptools.package-data]
"src" = ["config/*.yaml", "metadata/profiles/*.yaml"]

[tool.setuptools.dynamic]
version = {attr = "src.__version__"}

[tool.uv]
extra-index-url = ["https://pypi.cloudzero.com"]
dev-dependencies = [
    "build>=1.2.0",
    "wheel>=0.45.0",
    "pytest>=8.0.0",
    "ruff>=0.4.4",
    "notebook>=7.4.0",
    "ipykernel>=6.29.5",
    "pandas>=2.2.3",
    "pyarrow>=19.0.1",
    "matplotlib>=3.10.1",
    "seaborn>=0.13.2",
    "pytest-mock>=3.14.1",
    "pytest-xdist>=3.8.0",
]

[tool.pytest.ini_options]
# Test discovery and execution
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]

# Test execution options
addopts = [
    "-v",
    "--tb=short",
    "--strict-markers",
    "--strict-config",
    "--color=yes"
]

# Test markers for categorization
markers = [
    "unit: Unit tests (fast, isolated)",
    "integration: Integration tests (moderate speed, multiple components)", 
    "cli: CLI command tests (moderate speed, command-line interface)",
    "system: System tests (slow, full system)",
    "slow: Tests that take longer to run",
    "network: Tests that require network access",
    "fixtures: Tests that use test fixtures"
]

# Filter warnings
filterwarnings = [
    "error",
    "ignore::UserWarning",
    "ignore::DeprecationWarning",
    "ignore::PendingDeprecationWarning"
]

# Minimum version requirements
minversion = "6.0"

[tool.ruff]
# Same as Black.
line-length = 88
indent-width = 4

# Assume Python 3.10+.
target-version = "py310"

[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`)  codes by default.
select = ["E4", "E7", "E9", "F", "I", "N", "UP", "B", "C90", "PL"]
ignore = [
    "E501",  # Line length handled by formatter
    "UP007", # Don't convert Union[X, Y] to X | Y (Python 3.10 compatibility)
    "UP035", # Don't convert typing.List to list (Python 3.10 compatibility)
    "UP037", # Don't convert typing.Dict to dict (Python 3.10 compatibility)
]

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

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

[tool.ruff.lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10

[tool.ruff.lint.per-file-ignores]
# Tests can use magic values, assertions, and fixtures
"tests/**/*" = ["PLR2004", "S101", "ARG", "PLR0913"]

[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "double"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

[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
show_error_codes = true

# Per-module options
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
disallow_incomplete_defs = false

[[tool.mypy.overrides]]
module = [
    "polars.*",
    "typer.*",
    "rich.*",
    "yaml.*",
    "dotenv.*"
]
ignore_missing_imports = true
