02.01 — Identité technique d’Ocarina#
pyproject.toml#
[project]
name = "ocarina"
version = "1.1.10"
description = "Websites test framework for Igor"
requires-python = ">=3.14"
authors = [{ name="Igor Casanova", email="[REDACTED]" }]
license = "MIT"
license-files = ["LICEN[CS]E*"]
readme = "README.md"
dependencies = ["python-docx>=1.2.0"]version = "1.1.10": le projet est en stable 1.x, pas en pré-version.requires-python = ">=3.14": le typage générique PEP 695 est utilisé partout.dependencies = ["python-docx>=1.2.0"]: une seule dépendance d’exécution. Tout le reste est dansdev.license = "MIT".description = "Websites test framework for Igor": pas « for everyone », pas « for humans », explicitement « for Igor ». Cohérent avec../01-philosophy/05-political-stance.md: « C’est ma voiture. »
Dépendances dev#
[dependency-groups]
dev = [
"ruff>=0.15.0",
"mypy>=1.17.0",
"mypy-extensions>=1.1.0",
"typing-extensions>=4.14.0",
"pytest>=9.0.0",
"pytest-cov>=7.0.0",
"hypothesis>=6.151.0",
"pytest-mypy-plugins>=3.1.0",
"allure-pytest>=2.15.3",
"allure-python-commons>=2.15.3",
"pre-commit>=4.5.1",
"syrupy>=5.1.0",
"selenium>=4.40.0",
"playwright>=1.60.0",
"twine>=6.2.0",
"build>=1.4.2",
"prysk>=0.20.0",
]| Outil | Rôle dans Ocarina |
|---|---|
ruff | Linter + formatter (remplace flake8 + isort + black). select = ["ALL"]. |
mypy (+ extensions) | Type-checker. strict = true (cf. mypy.ini). |
pytest | Runner des tests unitaires (le framework est lui-même testé). |
pytest-cov | Couverture de tests (du framework lui-même). Configurée dans pyproject.toml#tool.coverage. |
hypothesis | Property-based testing (PBT) → test_invariants_properties.py. |
pytest-mypy-plugins | Tests statiques de typage (vérifie les erreurs mypy attendues et tests d’inférence de types avec reveal_type). |
allure-pytest / allure-python-commons | Rapport Allure (déployé sur GH Pages). |
pre-commit | Hooks Git locaux (ruff-format). |
syrupy | Snapshot testing (sortie de pretty_print_results, results_to_json). |
selenium | Présent en dev parce qu’Ocarina ne dépend pas de Selenium pour fonctionner, livre juste un adapter Selenium pour être immédiatement opérationnel. |
playwright | Même logique : un second adapter livré (depuis la 1.1.3). Ocarina pilote désormais Selenium et Playwright out of the box, derrière les mêmes ports. |
twine / build | Publication PyPI. |
prysk | Tests CLI au format cram (.t). Successeur de cram. |
mypy.ini#
[mypy]
python_version = 3.14
strict = true
# * ... Allow missing annotations (type inference is cool)
disallow_incomplete_defs = false
# * ... Allow missing annotations (type inference is cool)
disallow_untyped_defs = falsestrict = true: active--warn-redundant-casts,--warn-unused-ignores,--no-implicit-optional,--check-untyped-defs, etc.- Deux exceptions :
disallow_incomplete_defsetdisallow_untyped_defsdésactivés, car l’auteur estime que l’inférence de type de mypy est suffisante quand on n’a pas besoin d’expliciter. Toutes les annotations explicites sont là où elles comptent.
pyproject.toml#tool.ruff#
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"ANN002", "ANN003", "ANN201",
"TRY003",
"C901",
"D203", # conflit avec D211
"D213", # conflit avec D212
"COM812", # conflit avec le formatter ruff (auto-fix)
]
[tool.ruff]
exclude = ["**/.venv/**", "**/bin/**", "**/__init__.py", "**/__bypass_linter__"]select = ["ALL"]: toutes les règles de ruff sont activées (~800).- Ignore list courte : six règles seulement, toutes justifiées.
B008NE doit JAMAIS être ignoré («# "B008", # * ... NEVER ignore this rule without knowing very well what you are doing: https://docs.astral.sh/ruff/rules/function-call-in-default-argument/»). C’est une note pour ne pas répéter une erreur passée.- **
**/**bypass_linter**** : convention de répertoire pour héberger du code explicitement non-linté (utile pour des modules expérimentaux internes).
pyproject.toml#tool.pytest.ini_options#
testpaths = ["tests"]
python_files = ["test_*.py"]
norecursedirs = [".*", "__pycache__"]
log_cli = true
log_cli_level = "DEBUG"
log_cli_format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
addopts = """
--cov=src
--cov-branch
--cov-report=term-missing
--cov-report=html
--cov-report=xml:coverage.xml
"""| Réglage | Effet |
|---|---|
log_cli = true | Tous les logs des tests apparaissent en CLI (utile pour les scénarios qui passent par ILogger). |
--cov=src + --cov-branch | Couverture par branche, pas seulement par ligne. |
--cov-report=html + xml | Trois sorties : terminal, HTML local, XML pour ingestion CI. |
pyproject.toml#tool.coverage#
Voir le détail ici : ../04-internal-tests/07-coverage-policy.md. En bref : tout ce qui est shape (custom_types, ports, errors), ce qui requiert un navigateur réel (adapters Selenium), et ce qui est traversé par les cram tests (cli/store, cli/builder), est explicitement omis. Pour ne pas fausser les métriques.
Makefile#
| Recette | Effet |
|---|---|
make install | Crée .venv si absent, pip install -e . --group dev, pre-commit install. Cross-OS (Windows / autres). |
make install-on-ci | Variante CI : pip install -r requirements-dev.txt puis pip install -e . --no-deps. |
make test | make cram-test puis pytest --alluredir=allure-results -vv --hypothesis-show-statistics. |
make cram-test | prysk tests/cram/ (sur Windows : ne fait rien). |
make check-coding-style | mypy + ruff |
make mypy-check | mypy src/ tests/ |
make ruff-check | ruff check . |
make ruff-format | ruff format . |
make generate-allure | allure generate allure-results -o allure-report |
make serve-allure | Ouvre le rapport Allure dans le navigateur. |
make serve-htmlcov | Idem pour htmlcov/ |
make test-ui | make test + make generate-allure + make serve-htmlcov + make serve-allure |
make update-snapshots | pytest --snapshot-update |
make clean / make clean-allure | Cleanup cross-OS. |
allurerc.mjs (taxonomie Allure)#
Depuis la migration vers Allure 3, la taxonomie des failures réside dans allurerc.mjs (le fichier categories.json dédié a disparu). Les catégories sont inchangées :
categories: {
rules: [
{ name: "Test defects", matchers: { statuses: ["broken"] } },
{
name: "Invariant violations",
matchers: { statuses: ["failed"], message: /.*InvariantViolationError.*/ },
},
{
name: "Assertion errors",
matchers: { statuses: ["failed"], message: /.*AssertionError.*/ },
},
{ name: "Skipped", matchers: { statuses: ["skipped"] } },
],
}Quatre catégories, dont par exemple Invariant violations : échecs des tests impliquant validate(...).execute().raise_if_invalid(). Voir ../../04-internal-tests/08-allure-history.md pour la config complète.
.pre-commit-config.yaml#
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.11
hooks:
- id: ruff-formatMinimal : juste ruff-format en pre-commit. Les autres outils (ruff check, mypy) sont en CI uniquement, choix qui réduit la friction locale (= éviter de « casser les couilles » des développeurs).
URLs#
[project.urls]
Documentation = "https://mojo-molotov.github.io/ocarina-holy-book"
Homepage = "https://github.com/mojo-molotov/ocarina"
Issues = "https://github.com/mojo-molotov/ocarina/issues"L’URL Documentation pointe vers le Holy Book. Voir ../09-holy-book/
Build backend#
[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"hatchling : choix moderne (PEP 517/518), léger, sans config ad hoc.