Skip to main content

Automathèque

Code de base pour automatheque.

Installation

mais il est peu probable que vous ayez besoin de l'installer, c'est avant tout une dépendance.

pip install automatheque

Dépendances

  • voir pyproject.toml

Install en mode dev

pip install -e .[dev,docs] ou monas install depuis la racine.

Usage : Utilitaire pour script

from automatheque.script import script  # alias court de script_automatheque


@script(__doc__, __version__)
def main(_script):
    print(_script.config)


if __name__ == "__main__":
    main()

L'API a été promue de automatheque.util.script vers automatheque.script (#41). L'ancien chemin reste importable (shim) mais émet un DeprecationWarning : migrez vers from automatheque.script import script.

Le décorateur câble automatiquement, si le script les déclare dans son usage : --dry-run (via _script.dry_run), la verbosité -v/-q (niveau de log), une sortie propre sur Ctrl-C (code 130), et la durée d'exécution.

Sous-commandes (via commandopt)

On déclare des fonctions-commandes avec @commande([...]) (alias de commandopt.commandopt) et on aiguille avec _script.execute_commande(). Les options internes d'automatheque (--config, --dry-run, -v/-q) sont exclues de la sélection, mais restent transmises à la commande.

"""Mon script

Usage:
  mon_script.py (--ajouter | --supprimer) [--config=<f>] [-v]
"""

from automatheque.script import script, commande


@commande(["--ajouter"])
def ajouter(arguments): ...


@commande(["--supprimer"])
def supprimer(arguments): ...


@script(__doc__, __version__)
def main(_script):
    return _script.execute_commande()


if __name__ == "__main__":
    main()

Gestion des secrets

Un mot de passe ou un jeton ne doit jamais fuiter dans les logs ou une traceback, et sa source ne devrait pas être figée dans le code (parfois une variable d'environnement, parfois la config, parfois un trousseau système…). Le module automatheque.secret répond aux deux besoins.

Secret : une valeur qui ne fuite pas

Secret enveloppe une valeur sensible : son repr, son str, un f-string et le logging affichent tous ***. La valeur réelle n'est accessible qu'au point d'usage, via .reveler().

from automatheque.secret import Secret

mdp = Secret("s3cr3t")
print(mdp)  # ***
print(f"mdp={mdp}")  # mdp=***
logging.info("mdp=%s", mdp)  # …mdp=***  (pas de fuite dans les logs)

connexion.login("moi", mdp.reveler())  # .reveler() UNIQUEMENT ici

recup_secret : d'où vient le secret ?

recup_secret(cle, config=, resolveurs=) cherche la valeur auprès de plusieurs sources essayées dans l'ordre (premier gagnant) et renvoie un Secret (ou None si introuvable). Par défaut : la variable d'environnement puis, si on lui passe une config, la configuration.

from automatheque.secret import recup_secret

# factrice.smtp.mdp  →  variable FACTRICE_SMTP_MDP,
#                       sinon [factrice.smtp] mdp = … dans la config
mdp = recup_secret("factrice.smtp.mdp", config=_script.config)
if mdp is not None:
    serveur.login(user, mdp.reveler())

Les sources sont des greffons

Chaque source est un greffon (cf. automatheque.greffon) rendant la capacité ResoudreSecret — on ajoute donc une nouvelle source comme n'importe quel greffon. Fournis d'origine :

Greffon Source
GreffonSecretEnv variable d'env (factrice.smtp.mdp → FACTRICE_SMTP_MDP)
GreffonSecretConfig configuration (section.option)
GreffonSecretKeyring trousseau système (dépendance optionnelle keyring)
GreffonSecretCommande sortie d'une commande externe (p. ex. pass show {cle})

Pour un ordre ou des sources personnalisés, on passe resolveurs= (liste ordonnée de greffons) — ici on interroge d'abord le trousseau, puis une commande :

from automatheque.secret import (
    recup_secret,
    GreffonSecretKeyring,
    GreffonSecretCommande,
)

mdp = recup_secret(
    "factrice.smtp.mdp",
    resolveurs=[
        GreffonSecretKeyring(service="mon-appli"),
        GreffonSecretCommande(gabarit="pass show {cle}"),
    ],
)

Caviardage des logs (défense en profondeur)

La configuration de log par défaut (configure_logging_defaut(), appelée par un script @script_automatheque) installe un filtre de caviardage : si la valeur d'un Secret vivant apparaît dans un message de log, elle est remplacée par ***.

mdp = recup_secret("factrice.smtp.mdp", config=_script.config)
logging.getLogger(__name__).info("connexion mdp=%s", mdp.reveler())
# → journalisé : « connexion mdp=*** »  (même la valeur révélée est rattrapée)

La première ligne de défense reste de ne jamais logger un secret en clair (Secret est déjà caviardé par str/repr) ; le filtre rattrape les fuites indirectes. Si tu configures le logging toi-même (dictConfig maison), pose le filtre sur tes handlers avec installe_caviardage() :

from automatheque.log import installe_caviardage

installe_caviardage()  # racine par défaut (couvre les loggers enfants)

Configuration : sections typées et validées

_script.config (ou charge_configuration()) renvoie un ConfigParser brut : tout y est chaîne, rien n'est validé, et une clé absente ou mal typée n'explose que tard, au point d'accès. Pour valider tôt — et récupérer des valeurs déjà typées — décris une section comme une classe attrs et peuple-la avec charge_section :

import attr
from automatheque.configuration import charge_section, booleen, liste


@attr.s
class ConfigSmtp:
    hote = attr.ib(validator=attr.validators.instance_of(str))
    port = attr.ib(default=465, converter=int)
    tls = attr.ib(default=True, converter=booleen)
    relais = attr.ib(factory=list, converter=liste)


smtp = charge_section(ConfigSmtp, _script.config, "smtp")
smtp.port  # 587 : un int, pas "587"
smtp.tls  # True : un bool

pour la section :

[smtp]
hote   = smtp.exemple.org
port   = 587
tls    = yes
relais = a.exemple.org, b.exemple.org

Les converter/validator des attr.ib font la conversion (chaîne → int, booleen, liste…) et le contrôle. L'erreur est précoce et nommée :

  • section absente, option inconnue (une faute de frappe est rattrapée), clé requise manquante, ou valeur refusée par un converter/validator → ConfigurationInvalide (qui hérite de ValueError), avec le nom de la section et de la clé fautive.
  • charge_section(..., strict=False) ignore les options inconnues, quand une même section sert à plusieurs consommateurs.

Deux converteurs sont fournis, puisqu'un .ini ne rend que des chaînes :

Converteur .ini → reconnaît
booleen bool yes/no, true/false, on/off, oui/non, vrai/faux
liste list[str] valeurs séparées par des virgules (éléments vides ignorés)

Valider la configuration d'un greffon

Un greffon peut exiger une configuration (config_requise = True). Plutôt que de se fier au contrôle générique « une config existe-t-elle ? » (Greffon.actif), décris la config attendue par une classe et valide-la avec charge_section au moment de monter le greffon : on sait alors tôt, et précisément, si la config requise est réellement présente et bien typée.

C'est le rôle naturel d'un Monteur — il lit la configuration et s'en sert pour instancier le greffon :

import attr
from automatheque.configuration import charge_configuration, charge_section
from automatheque.conception.structures import Monteur
from automatheque.greffon import Greffon


@attr.s
class ConfigMeteo:
    """Config attendue par le greffon météo (section [meteo])."""

    cle_api = attr.ib(validator=attr.validators.instance_of(str))
    hote = attr.ib(default="api.exemple.org", converter=str)


@attr.s(eq=False)
class GreffonMeteo(Greffon):
    config_requise = attr.ib(default=True, init=False, kw_only=True)
    reglages = attr.ib(default=None, kw_only=True)  # ConfigMeteo validée


class MonteurMeteo(Monteur):
    """Lit la config et ne monte le greffon que si sa section est valide."""

    def construit(self, *, identifiant=None, **kwargs):
        # charge_section lève ConfigurationInvalide — tôt, nommée — si la
        # section [meteo] est absente, incomplète ou mal typée.
        reglages = charge_section(ConfigMeteo, charge_configuration(), "meteo")
        return GreffonMeteo(identifiant=identifiant, reglages=reglages, **kwargs)

Le paquet déclare le monteur en point d'entrée (auto-découverte, cf. decouvre_monteurs) :

[project.entry-points."automatheque.greffons"]
meteo = "mon_paquet.meteo:MonteurMeteo"

Ainsi config_requise cesse d'être un simple booléen « il y a une config » : la présence réelle des clés dont ce greffon a besoin est prouvée à l'instanciation, et une config manquante ou fautive échoue avec un message qui nomme la section et la clé.

Configuration du logging

Automathèque ne configure rien à l'import (une bibliothèque ne doit pas toucher au logging global). C'est l'application qui configure : un script décoré par @script_automatheque appelle configure_logging_defaut() (sortie console) puis applique la section [log] de sa configuration.

Un script étant une application, sa configuration de log vise la racine : logging.getLogger(__name__) dans le script et les loggers des dépendances en héritent.

Forme simple (inline dans le .ini)

Dans le config.ini du script (~/.config/<mon_script>/config.ini) :

[log]
niveau = INFO
fichier = mon_script.log          ; optionnel (sinon console)
format  = %%(asctime)s [%%(levelname)s] %%(name)s: %%(message)s
; niveaux par logger (nom seul = niveau global) :
names   = automatheque:WARNING, mon_script:DEBUG, requests:ERROR

Dans un .ini, les % se doublent en %% (convention ConfigParser) ; un % non échappé lève une erreur explicite.

Un seul handler/destination est partagé ; names n'ajuste que des niveaux.

Forme complète (dictConfig externe)

Pour router des loggers vers des destinations différentes (erreurs du script dans un fichier, automatheque ailleurs…), pointer vers un dictConfig complet (JSON ou YAML, détecté au contenu) :

[log]
fichier_config = log.yaml

Voir l'exemple canonique log.yaml.dist.

Release files for automatheque 0.24.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for automatheque 0.24.0
File Size Uploaded
automatheque-0.24.0.tar.gz 87.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for automatheque 0.24.0
File Interpreter ABI Platform
automatheque-0.24.0-py3-none-any.whl Python 3 none any Details

Total release size: 171.3 kB

Release files / automatheque-0.24.0.tar.gz

Download URL automatheque-0.24.0.tar.gz
Size 87.3 kB
Tags Source
SHA-256 checksum
How to use checksums
63e88068d914513407966f88b2ff6b36a75814f76c923721092ac5ea122f8571
BLAKE2b-256 checksum
How to use checksums
c2f70d31533e50c59ca35ff19ddf2944e39c5c98e14214be44d9c00c3a73bf12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.

Transparency log

Release files / automatheque-0.24.0-py3-none-any.whl

Download URL automatheque-0.24.0-py3-none-any.whl
Size 84.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
704d1cfcfccb93ce0cf831ef3b32a24f0ca30a78eb56ba7ca74c11bd764557e9
BLAKE2b-256 checksum
How to use checksums
d7d2b92659921010040665de4558f67eafdde9e2ea492cf676fd674201f98ccb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.

Transparency log

Release history Release notifications | RSS feed

0.25.0

2 release files

This release

0.24.0 This release

2 release files

0.19.0

2 release files

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.14.2

2 release files

0.14.0

2 release files

0.13.1

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.9.9

2 release files

0.9.8

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.4

2 release files

0.9.3

2 release files

0.9.2

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.10

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page