[project] name = "crabstero" dynamic = ["version"] description = "The simple nonversation Discord bot." requires-python = ">=3.14" license = "Apache-2.0" authors = [ { name = "Logan Fick" }, ] dependencies = [ "discord.py>=2.7.1", "aiosqlite>=0.22.1", "aiohttp>=3.14.1", "prometheus-client>=0.25.0", "uvloop>=0.22.1", ] [project.scripts] crabstero = "crabstero.cli:main" [project.urls] Repository = "https://git.logal.dev/LogalDeveloper/Crabstero" [dependency-groups] dev = [ "codespell>=2.4.2", "mypy>=2.1.0", "pip-audit>=2.10.1", "pytest>=9.1.0", "pytest-asyncio>=1.4.0", "pytest-cov>=7.1.0", "ruff>=0.15.18", "simcord==1.0.1", ] [tool.uv] extra-index-url = ["https://git.logal.dev/api/packages/LogalDeveloper/pypi/simple/"] publish-url = "https://git.logal.dev/api/packages/LogalDeveloper/pypi" [build-system] requires = ["hatchling>=1.30.1", "hatch-vcs>=0.5.0"] build-backend = "hatchling.build" [tool.hatch.version] source = "vcs" [tool.hatch.build.targets.wheel] packages = ["src/crabstero"] [tool.hatch.build.hooks.vcs] version-file = "src/crabstero/_version.py" [tool.mypy] python_version = "3.14" strict = true warn_unreachable = true explicit_package_bases = true mypy_path = "$MYPY_CONFIG_FILE_DIR/src" [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" asyncio_default_test_loop_scope = "function" testpaths = ["tests"] addopts = [ "--import-mode=importlib", "--strict-config", "--strict-markers", ] markers = [ "unit: fast, deterministic tests that do not cross real external boundaries", "integration: tests that exercise real local boundaries such as SQLite, sockets, CLI wiring, Discord simulation, or service lifecycle", ] xfail_strict = true [tool.ruff] target-version = "py314" extend-exclude = ["src/crabstero/_version.py"] # auto-generated by hatch-vcs [tool.ruff.lint] select = ["ALL"] ignore = [ "ANN401", # Any is valid at system boundaries; mypy strict handles real issues "C901", # McCabe complexity: noisy and not actionable "COM812", # handled by the formatter "D203", # incompatible with D211 (no blank line before class docstring) "D213", # incompatible with D212 (summary on first line) "EM", # exception message style: inline literals are fine "PLR0911", # too many return statements: flat early-returns are clear "PLR0912", # too many branches: inherent in parsers, validators, CLI "PLR0913", # too many arguments: API surfaces and constructors need them "PLR0915", # too many statements: inherent in parsers, validators, CLI "TRY003", # inline exception messages are fine (complements EM ignore) "TRY301", # raise inside try: guard clauses don't need helper functions ] [tool.ruff.lint.per-file-ignores] "src/crabstero/__init__.py" = ["E402"] # version fallback is resolved before public imports "tests/**" = [ "S101", # assert is standard for pytest "S311", # pseudo-random generators are fine in tests "SLF001", # tests legitimately access private members for verification "ARG001", # unused args are normal for fixtures and handler stubs "PLR2004", # magic values are clear in test assertions ] [tool.codespell] skip = "src/crabstero/_version.py,uv.lock" [tool.coverage.run] source = ["crabstero"] omit = [ "src/crabstero/_version.py", ] [tool.coverage.report] show_missing = true skip_empty = true fail_under = 95