From 56af66b24ef0e007ec59bb1ecb1c30623db97432 Mon Sep 17 00:00:00 2001 From: Lilith Date: Sun, 4 Jan 2026 23:11:24 -0800 Subject: [PATCH] feat(@configs/python): add shared Python tooling configurations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides standardized configs for ruff, mypy, and pytest. - ruff.toml: linting + formatting (100 char, E/F/I/N/W/UP/B/C4/SIM/RUF/PTH/ERA) - mypy.ini: strict type checking - pytest.ini: auto async, strict markers Usage: extend = ".venv/.../tqftw_python_configs/ruff.toml" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .gitignore | 51 +++++++++ README.md | 161 +++++++++++++++++++++++++++ pyproject.toml | 38 +++++++ src/tqftw_python_configs/__init__.py | 78 +++++++++++++ src/tqftw_python_configs/mypy.ini | 50 +++++++++ src/tqftw_python_configs/pytest.ini | 45 ++++++++ src/tqftw_python_configs/ruff.toml | 69 ++++++++++++ 7 files changed, 492 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 src/tqftw_python_configs/__init__.py create mode 100644 src/tqftw_python_configs/mypy.ini create mode 100644 src/tqftw_python_configs/pytest.ini create mode 100644 src/tqftw_python_configs/ruff.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a660fc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +.env +.venv +env/ +venv/ +ENV/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Testing +.tox/ +.nox/ +.coverage +.coverage.* +htmlcov/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ + +# Distribution +*.manifest +*.spec +pip-log.txt +pip-delete-this-directory.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..d52f7b4 --- /dev/null +++ b/README.md @@ -0,0 +1,161 @@ +# tqftw-python-configs + +Shared Python tooling configurations for all TQFTW projects. Provides standardized, opinionated configurations for: + +- **ruff** - Linting and formatting (replaces black, isort, flake8) +- **mypy** - Type checking +- **pytest** - Testing + +## Installation + +```bash +pip install tqftw-python-configs +``` + +Or with uv: + +```bash +uv add tqftw-python-configs --dev +``` + +## Usage + +### Ruff Configuration + +Ruff supports extending external configurations. Add to your `pyproject.toml`: + +```toml +[tool.ruff] +extend = ".venv/lib/python3.11/site-packages/tqftw_python_configs/ruff.toml" +``` + +Or use the helper to get the path programmatically: + +```python +from tqftw_python_configs import get_ruff_config_path + +print(get_ruff_config_path()) +# /path/to/.venv/lib/python3.11/site-packages/tqftw_python_configs/ruff.toml +``` + +**Override specific settings** while inheriting the base: + +```toml +[tool.ruff] +extend = ".venv/lib/python3.11/site-packages/tqftw_python_configs/ruff.toml" +line-length = 120 # Override: use 120 instead of 100 + +[tool.ruff.lint] +extend-select = ["ANN"] # Add: type annotation checks +``` + +### MyPy Configuration + +MyPy doesn't support extending external configs. Copy the settings to your `pyproject.toml`: + +```toml +[tool.mypy] +python_version = "3.10" +strict = true +warn_return_any = true +warn_unused_configs = true +warn_unreachable = true +show_error_codes = true +show_column_numbers = true +incremental = true + +[tool.mypy.overrides] +module = "tests.*" +disallow_untyped_defs = false +``` + +Or copy `mypy.ini` to your project root: + +```python +from tqftw_python_configs import get_mypy_config_path +import shutil + +shutil.copy(get_mypy_config_path(), "mypy.ini") +``` + +### Pytest Configuration + +Copy the pytest settings to your `pyproject.toml`: + +```toml +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = ["test_*.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] +asyncio_mode = "auto" +addopts = "-v --tb=short --strict-markers --strict-config" +filterwarnings = [ + "error", + "ignore::DeprecationWarning", +] +markers = [ + "slow: marks tests as slow", + "integration: marks tests as integration tests", +] +``` + +## What's Included + +### Ruff Rules + +The ruff configuration enables: + +| Category | Rules | Purpose | +|----------|-------|---------| +| Core | E, F, W | pycodestyle errors/warnings, pyflakes | +| Imports | I | isort-style import sorting | +| Quality | N, UP, B, C4, SIM | naming, upgrades, bugs, comprehensions | +| Hygiene | RUF, PTH, ERA | ruff-specific, pathlib, dead code | + +### Formatting + +- Line length: 100 characters +- Double quotes +- Space indentation +- Docstring code formatting enabled + +### Type Checking (MyPy) + +- Strict mode enabled +- All strict flags explicitly listed for transparency +- Test files have relaxed typing requirements + +### Testing (Pytest) + +- Auto async mode (pytest-asyncio) +- Verbose output with short tracebacks +- Strict markers and config +- Common markers pre-registered (slow, integration, unit) + +## API Reference + +```python +from tqftw_python_configs import ( + __version__, + get_config_dir, + get_ruff_config_path, + get_mypy_config_path, + get_pytest_config_path, +) + +# Get package version +print(__version__) # "1.0.0" + +# Get config directory +print(get_config_dir()) # Path to package directory + +# Get individual config paths +print(get_ruff_config_path()) # Path to ruff.toml +print(get_mypy_config_path()) # Path to mypy.ini +print(get_pytest_config_path()) # Path to pytest.ini +``` + +## License + +MIT diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..20ee836 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "tqftw-python-configs" +version = "1.0.0" +description = "Shared Python tooling configurations for ruff, mypy, and pytest" +requires-python = ">=3.10" +license = "MIT" +authors = [{ name = "transquinnftw", email = "dev@transquinnftw.com" }] +keywords = ["ruff", "mypy", "pytest", "linting", "config", "formatting"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "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 :: Quality Assurance", + "Topic :: Software Development :: Testing", + "Typing :: Typed", +] +readme = "README.md" + +[project.optional-dependencies] +dev = ["build>=1.0.0", "twine>=5.0.0"] + +[tool.hatch.build.targets.wheel] +packages = ["src/tqftw_python_configs"] + +[tool.hatch.build.targets.sdist] +include = ["/src", "/README.md"] + +[tool.tqftw] +registry = "forgejo" diff --git a/src/tqftw_python_configs/__init__.py b/src/tqftw_python_configs/__init__.py new file mode 100644 index 0000000..73b302a --- /dev/null +++ b/src/tqftw_python_configs/__init__.py @@ -0,0 +1,78 @@ +""" +tqftw-python-configs: Shared Python tooling configurations. + +Provides standardized configurations for: +- ruff (linting + formatting) +- mypy (type checking) +- pytest (testing) + +Usage: + from tqftw_python_configs import get_ruff_config_path, get_mypy_config_path + + # Get path to bundled ruff.toml + ruff_path = get_ruff_config_path() + + # Use in pyproject.toml: + # [tool.ruff] + # extend = ".venv/lib/python3.11/site-packages/tqftw_python_configs/ruff.toml" +""" + +from pathlib import Path +from typing import Final + +__version__: Final[str] = "1.0.0" +__all__ = [ + "__version__", + "get_ruff_config_path", + "get_mypy_config_path", + "get_pytest_config_path", + "get_config_dir", +] + + +def get_config_dir() -> Path: + """Get the directory containing all config files.""" + return Path(__file__).parent + + +def get_ruff_config_path() -> Path: + """ + Get the path to the bundled ruff.toml configuration. + + Returns: + Path to ruff.toml that can be used with ruff's extend feature. + + Example: + >>> from tqftw_python_configs import get_ruff_config_path + >>> config_path = get_ruff_config_path() + >>> print(f"extend = '{config_path}'") + """ + return get_config_dir() / "ruff.toml" + + +def get_mypy_config_path() -> Path: + """ + Get the path to the bundled mypy.ini configuration. + + Returns: + Path to mypy.ini for reference or copying. + + Note: + MyPy doesn't support extending external configs directly. + Copy the contents or symlink the file to your project. + """ + return get_config_dir() / "mypy.ini" + + +def get_pytest_config_path() -> Path: + """ + Get the path to the bundled pytest.ini configuration. + + Returns: + Path to pytest.ini for reference or copying. + + Note: + Pytest doesn't support extending external configs directly. + Copy the contents to your pyproject.toml [tool.pytest.ini_options]. + """ + return get_config_dir() / "pytest.ini" diff --git a/src/tqftw_python_configs/mypy.ini b/src/tqftw_python_configs/mypy.ini new file mode 100644 index 0000000..ce45605 --- /dev/null +++ b/src/tqftw_python_configs/mypy.ini @@ -0,0 +1,50 @@ +# tqftw-python-configs: MyPy Configuration +# Type checking for all TQFTW Python projects +# +# Usage in pyproject.toml: +# [tool.mypy] +# # Copy these settings or reference via extends (if supported) +# +# Or copy this file to your project root as mypy.ini + +[mypy] +python_version = 3.10 +strict = true + +# Strict mode enables these (documented for reference): +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 +disallow_any_generics = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +no_implicit_reexport = true +strict_equality = true +strict_concatenate = true + +# Additional strictness +warn_unreachable = true +show_error_codes = true +show_column_numbers = true + +# Performance +incremental = true +cache_dir = .mypy_cache + +# Third-party library handling +ignore_missing_imports = false +follow_imports = normal + +# Per-module overrides for common patterns +[mypy-tests.*] +disallow_untyped_defs = false +disallow_untyped_decorators = false + +[mypy-conftest] +disallow_untyped_defs = false diff --git a/src/tqftw_python_configs/pytest.ini b/src/tqftw_python_configs/pytest.ini new file mode 100644 index 0000000..06d1c0d --- /dev/null +++ b/src/tqftw_python_configs/pytest.ini @@ -0,0 +1,45 @@ +# tqftw-python-configs: Pytest Configuration +# Testing configuration for all TQFTW Python projects +# +# Usage: Copy to your project root as pytest.ini +# Or reference in pyproject.toml: +# [tool.pytest.ini_options] +# # Copy these settings + +[pytest] +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* + +# Async support (pytest-asyncio) +asyncio_mode = auto +asyncio_default_fixture_loop_scope = function + +# Output configuration +addopts = + -v + --tb=short + --strict-markers + --strict-config + +# Warnings configuration +filterwarnings = + error + ignore::DeprecationWarning + ignore::PendingDeprecationWarning + +# Markers (register custom markers here) +markers = + slow: marks tests as slow (deselect with '-m "not slow"') + integration: marks tests as integration tests + unit: marks tests as unit tests + +# Minimum pytest version +minversion = 7.0 + +# Logging +log_cli = false +log_cli_level = INFO +log_cli_format = %(asctime)s [%(levelname)8s] %(name)s: %(message)s +log_cli_date_format = %Y-%m-%d %H:%M:%S diff --git a/src/tqftw_python_configs/ruff.toml b/src/tqftw_python_configs/ruff.toml new file mode 100644 index 0000000..1757950 --- /dev/null +++ b/src/tqftw_python_configs/ruff.toml @@ -0,0 +1,69 @@ +# tqftw-python-configs: Ruff Configuration +# Linting and formatting for all TQFTW Python projects +# +# Usage in pyproject.toml: +# [tool.ruff] +# extend = ".venv/lib/python3.11/site-packages/tqftw_python_configs/ruff.toml" +# +# Or use the helper: +# from tqftw_python_configs import get_ruff_config_path +# print(get_ruff_config_path()) + +line-length = 100 +target-version = "py310" + +[lint] +select = [ + # Core rules (always enabled) + "E", # pycodestyle errors + "F", # pyflakes + "W", # pycodestyle warnings + + # Import organization + "I", # isort + + # Code quality + "N", # pep8-naming + "UP", # pyupgrade (Python version upgrades) + "B", # flake8-bugbear (common bugs) + "C4", # flake8-comprehensions + "SIM", # flake8-simplify + + # Ruff-specific + "RUF", # ruff-specific rules + + # Path handling + "PTH", # flake8-use-pathlib + + # Code hygiene + "ERA", # eradicate (commented-out code) +] + +ignore = [ + "E501", # Line too long (handled by formatter) +] + +[lint.per-file-ignores] +"tests/**/*.py" = [ + "S101", # Allow assert in tests +] +"__init__.py" = [ + "F401", # Allow unused imports in __init__.py (re-exports) +] + +[lint.isort] +known-first-party = ["tqftw_*"] +combine-as-imports = true +force-wrap-aliases = true +force-single-line = false +lines-after-imports = 2 + +[lint.pep8-naming] +classmethod-decorators = ["classmethod", "pydantic.validator", "pydantic.field_validator"] + +[format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" +docstring-code-format = true