mirror of
https://git.zavage.net/Zavage-Software/smileyface.git
synced 2026-06-25 18:12:48 -06:00
Merge branch 'python-version-support'
Add Python 3.8-3.13 multi-version support: pytest smoke-test suite, uv+nox version matrix, importlib_resources backport for 3.8, declared the previously-undeclared selenium dependency, Gitea Actions CI matrix, and supporting docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
a2d4b334d7
21
.gitea/workflows/test.yml
Normal file
21
.gitea/workflows/test.yml
Normal file
@ -0,0 +1,21 @@
|
||||
name: tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Run smoke tests
|
||||
run: uv run --python ${{ matrix.python-version }} --with . --with pytest pytest -v
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ idea
|
||||
.env
|
||||
.claude/settings.local.json
|
||||
.claude/worktrees/
|
||||
uv.lock
|
||||
|
||||
10
CLAUDE.md
10
CLAUDE.md
@ -24,13 +24,19 @@ flake8 smileyface/
|
||||
|
||||
# Run pre-commit hooks manually
|
||||
pre-commit run --all-files
|
||||
|
||||
# Run the smoke-test suite on the current interpreter
|
||||
uv run --with . --with pytest pytest -v
|
||||
|
||||
# Run the full Python version matrix (3.8-3.13)
|
||||
uv run --with nox nox -s tests
|
||||
```
|
||||
|
||||
There is no test suite.
|
||||
Smoke tests live in `tests/` (import, CLI `--help`, and settings checks) and run across the supported Python 3.8-3.13 matrix via `nox`.
|
||||
|
||||
## Code Style
|
||||
|
||||
- **Black** formatter: 120 char line length, target Python 3.13
|
||||
- **Black** formatter: 120 char line length, targets Python 3.8–3.13
|
||||
- **isort**: profile black, multi_line_output=3, trailing commas, force_grid_wrap=3
|
||||
- **flake8**: 120 char max, ignores E121/E123/E126/E226/E24/E704/W605
|
||||
|
||||
|
||||
10
README.md
10
README.md
@ -15,6 +15,16 @@ Activate your desired python environment, then:
|
||||
|
||||
poetry install
|
||||
|
||||
Supported Python Versions
|
||||
==========================
|
||||
SmileyFace is tested against CPython 3.8 – 3.13. The supported range is
|
||||
enforced by a smoke-test matrix.
|
||||
|
||||
To run the matrix locally (requires [uv](https://docs.astral.sh/uv/)):
|
||||
|
||||
uv python install 3.8 3.9 3.10 3.11 3.12 3.13
|
||||
uv run --with nox nox -s tests
|
||||
|
||||
Usage
|
||||
======
|
||||
|
||||
|
||||
15
noxfile.py
Normal file
15
noxfile.py
Normal file
@ -0,0 +1,15 @@
|
||||
import nox
|
||||
|
||||
nox.options.default_venv_backend = "uv"
|
||||
nox.options.reuse_existing_virtualenvs = False
|
||||
|
||||
# Newest first. 3.8 is a stretch goal (see the importlib_resources backport).
|
||||
PYTHON_VERSIONS = ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8"]
|
||||
|
||||
|
||||
@nox.session(python=PYTHON_VERSIONS)
|
||||
def tests(session):
|
||||
"""Install the project + pytest and run the smoke suite on each interpreter."""
|
||||
session.install(".")
|
||||
session.install("pytest")
|
||||
session.run("pytest", "-v")
|
||||
1397
poetry.lock
generated
1397
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,14 @@ homepage = "https://zavage-software.com/portfolio/smileyface"
|
||||
repository = "https://git-mirror.zavage.net/zavage-software/smileyface"
|
||||
documentation = "https://git-mirror.zavage.net/zavage-software/smileyface"
|
||||
keywords = ["cas"]
|
||||
classifiers = [
|
||||
"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",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
|
||||
packages = [{ include = "smileyface" }]
|
||||
include = [
|
||||
@ -21,17 +29,21 @@ include = [
|
||||
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.13"
|
||||
python = ">=3.8,<4.0"
|
||||
pydantic-settings = ">=2.0"
|
||||
click = ">=8.0"
|
||||
platformdirs = ">=3.0"
|
||||
sqlparse = "*"
|
||||
selenium = ">=4.0"
|
||||
importlib-resources = { version = ">=5.0", python = "<3.9" }
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "*"
|
||||
pre-commit = "*"
|
||||
isort = "*"
|
||||
flake8 = "*"
|
||||
pytest = "*"
|
||||
nox = "*"
|
||||
#Sphinx = "^5.3.0"
|
||||
#sphinx-rtd-theme = "^1.3.0"
|
||||
|
||||
@ -41,7 +53,7 @@ build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
target-version = ['py313']
|
||||
target-version = ['py38', 'py39', 'py310', 'py311', 'py312', 'py313']
|
||||
|
||||
[tool.isort]
|
||||
multi_line_output = 3
|
||||
@ -49,3 +61,7 @@ combine_as_imports = true
|
||||
include_trailing_comma = true
|
||||
force_grid_wrap = 3
|
||||
ensure_newline_before_comments = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "-ra"
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import datetime
|
||||
import os
|
||||
|
||||
from importlib.resources import files
|
||||
try:
|
||||
from importlib.resources import files # Python 3.9+
|
||||
except ImportError: # Python 3.8
|
||||
from importlib_resources import files
|
||||
|
||||
import sqlparse
|
||||
|
||||
|
||||
24
tests/test_cli.py
Normal file
24
tests/test_cli.py
Normal file
@ -0,0 +1,24 @@
|
||||
from click.testing import CliRunner
|
||||
|
||||
from smileyface.cli import cli
|
||||
|
||||
|
||||
def test_root_help():
|
||||
result = CliRunner().invoke(cli, ["--help"])
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "SmileyFace" in result.output
|
||||
|
||||
|
||||
def test_every_command_help():
|
||||
runner = CliRunner()
|
||||
for name in cli.commands:
|
||||
result = runner.invoke(cli, [name, "--help"])
|
||||
assert result.exit_code == 0, f"`{name} --help` failed:\n{result.output}"
|
||||
|
||||
|
||||
def test_scrape_subcommands_help():
|
||||
runner = CliRunner()
|
||||
scrape_group = cli.commands["scrape"]
|
||||
for name in scrape_group.commands:
|
||||
result = runner.invoke(cli, ["scrape", name, "--help"])
|
||||
assert result.exit_code == 0, f"`scrape {name} --help` failed:\n{result.output}"
|
||||
34
tests/test_imports.py
Normal file
34
tests/test_imports.py
Normal file
@ -0,0 +1,34 @@
|
||||
import importlib
|
||||
import pkgutil
|
||||
|
||||
import smileyface
|
||||
|
||||
|
||||
def test_top_level_package_imports():
|
||||
importlib.import_module("smileyface")
|
||||
|
||||
|
||||
def test_all_submodules_import():
|
||||
errors = []
|
||||
|
||||
def _on_walk_error(name):
|
||||
errors.append(f"{name}: failed during package walk")
|
||||
|
||||
module_names = [
|
||||
info.name
|
||||
for info in pkgutil.walk_packages(
|
||||
smileyface.__path__,
|
||||
prefix="smileyface.",
|
||||
onerror=_on_walk_error,
|
||||
)
|
||||
]
|
||||
|
||||
assert module_names, "walk_packages found no submodules - check smileyface.__path__"
|
||||
|
||||
for name in module_names:
|
||||
try:
|
||||
importlib.import_module(name)
|
||||
except Exception as exc: # noqa: BLE001 - we want every failure, not the first
|
||||
errors.append(f"{name}: {exc!r}")
|
||||
|
||||
assert not errors, "Modules failed to import:\n" + "\n".join(errors)
|
||||
16
tests/test_settings.py
Normal file
16
tests/test_settings.py
Normal file
@ -0,0 +1,16 @@
|
||||
from smileyface.settings import AppSettings
|
||||
|
||||
|
||||
def test_defaults():
|
||||
settings = AppSettings(_env_file=None)
|
||||
assert settings.sqlite_filename == "smiles.db"
|
||||
assert settings.skip_validate is False
|
||||
assert settings.project_dir == ""
|
||||
|
||||
|
||||
def test_env_overrides(monkeypatch):
|
||||
monkeypatch.setenv("SMILEYFACE_PROJECT_DIR", "/srv/ut4")
|
||||
monkeypatch.setenv("SMILEYFACE_SKIP_VALIDATE", "true")
|
||||
settings = AppSettings(_env_file=None)
|
||||
assert settings.project_dir == "/srv/ut4"
|
||||
assert settings.skip_validate is True
|
||||
Loading…
Reference in New Issue
Block a user