feat(@configs/python): add shared Python tooling configurations

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 <noreply@anthropic.com>
This commit is contained in:
Lilith 2026-01-04 23:11:24 -08:00
commit 56af66b24e
7 changed files with 492 additions and 0 deletions

51
.gitignore vendored Normal file
View file

@ -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

161
README.md Normal file
View file

@ -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

38
pyproject.toml Normal file
View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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