pyprocessors-coreference 1.6.3__tar.gz → 1.6.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/.gitignore +3 -0
  2. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/PKG-INFO +1 -1
  3. pyprocessors_coreference-1.6.8/docs/sherpa/coreference.en.md +55 -0
  4. pyprocessors_coreference-1.6.8/docs/sherpa/coreference.fr.md +55 -0
  5. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/src/pyprocessors_coreference/__init__.py +1 -1
  6. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/.claude-plugin/plugin.json +2 -2
  7. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/HOWTO.md +1 -1
  8. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/README.md +4 -1
  9. pyprocessors_coreference-1.6.8/submodules/python-archetype/resources/help/help_examples.py +126 -0
  10. pyprocessors_coreference-1.6.8/submodules/python-archetype/resources/help/plugin-help.py +694 -0
  11. pyprocessors_coreference-1.6.8/submodules/python-archetype/resources/help/template.en.md +45 -0
  12. pyprocessors_coreference-1.6.8/submodules/python-archetype/resources/help/template.fr.md +45 -0
  13. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/skills/new-plugin/SKILL.md +13 -1
  14. pyprocessors_coreference-1.6.8/submodules/python-archetype/skills/new-plugin/references/converter.md +66 -0
  15. pyprocessors_coreference-1.6.8/submodules/python-archetype/skills/new-plugin/references/formatter.md +54 -0
  16. pyprocessors_coreference-1.6.8/submodules/python-archetype/skills/new-plugin/references/segmenter.md +55 -0
  17. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/skills/new-plugin/references/types.md +39 -14
  18. pyprocessors_coreference-1.6.8/submodules/python-archetype/skills/plugin-help/SKILL.md +182 -0
  19. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/vars/pythonPipeline.groovy +93 -6
  20. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/.claude/settings.json +0 -0
  21. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/.gitmodules +0 -0
  22. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/.python-version +0 -0
  23. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/README.md +0 -0
  24. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/docs/adr/0001-linking-candidats-entityfishing-decision-jev.md +0 -0
  25. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/pyproject.toml +0 -0
  26. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/src/pyprocessors_coreference/coreference.py +0 -0
  27. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/.claude-plugin/marketplace.json +0 -0
  28. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/resources/Stages.yml +0 -0
  29. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/skills/new-plugin/references/annotator.md +0 -0
  30. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/skills/new-plugin/references/importer.md +0 -0
  31. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/skills/new-plugin/references/processor.md +0 -0
  32. {pyprocessors_coreference-1.6.3 → pyprocessors_coreference-1.6.8}/submodules/python-archetype/tools/check-marketplace.py +0 -0
@@ -29,3 +29,6 @@ uv.lock
29
29
  # audit-report.md non suivi qui traine apres chaque 'task'. Meme correctif a y
30
30
  # porter -- c'est du ressort de check-plugin-drift.
31
31
  **/audit*.md
32
+
33
+ # Exemples des pages d aide Sherpa, enregistres par les tests
34
+ build/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyprocessors-coreference
3
- Version: 1.6.3
3
+ Version: 1.6.8
4
4
  Summary: Processor grouping the mentions of the same entity
5
5
  Project-URL: Homepage, https://bitbucket.org/kairntech/pyprocessors_coreference
6
6
  Author-email: Olivier Terrier <olivier.terrier@kairntech.com>
@@ -0,0 +1,55 @@
1
+ # coreference Processor (`coreference`)
2
+
3
+ <!-- To write: what the plugin does, in one sentence, with a concrete example in quotes. -->
4
+
5
+ ## When to use it
6
+
7
+ <!-- To write: two or three situations, in the words of a Sherpa user (project, corpus, search), not in the words of the code. -->
8
+
9
+ ## When not to use it
10
+
11
+ <!-- To write: what the plugin does not do although one might expect it to, and which other plugin does. -->
12
+
13
+ ## Prerequisites
14
+
15
+ <!-- To write: what the plugin expects as input (document language, sentence segmentation, annotations from another plugin…), required or recommended, and why. -->
16
+
17
+ <!-- generated:languages -->
18
+
19
+ **Supported languages:** the plugin declares no language restriction.
20
+
21
+ <!-- /generated:languages -->
22
+
23
+ ## What it produces
24
+
25
+ <!-- To write: what the plugin adds to or changes in the document (annotations and their labels, terms, categories, metadata, text…). Also say what it removes or replaces. -->
26
+
27
+ ## Parameters
28
+
29
+ <!-- The table is generated by 'task py:help': displayed name and default come from the code.
30
+ The "Effect" column is yours: it starts from the code's description and is kept from one
31
+ generation to the next. A computed default (None in the code) is written by hand. -->
32
+
33
+ <!-- generated:parameters -->
34
+
35
+ | Parameter | Default | Effect |
36
+ |---|---|---|
37
+ | **Labels** (`labels`) | — | Labels of the mentions to group. If empty, the mentions of every label are grouped.<br/> Mentions are only grouped with mentions of the same label, except person labels, which all form one family. |
38
+ | **Person Labels** (`person_labels`) | — | Labels of person names. They form one family (person and afpperson mentions are grouped together), and a partial name ("Macron") joins the full name it ends ("Emmanuel Macron").<br/> If empty, every label whose name contains "person" (person, afpperson...). |
39
+ | **Honorifics** (`honorifics`) *(advanced)* | `["M.", "MM.", "Mme", "Mmes", "Mlle", "Mlles", "Me", "Dr", "Dr.", "Pr", "Pr.", "Mr", "Mr.", "Mrs", "Mrs.", "Ms", "Ms.", "Miss", "Sir", "Dame", "Lord", "Lady"]` | Honorifics ignored in front of a person name when comparing names (M., Mme, Dr...) |
40
+
41
+ <!-- /generated:parameters -->
42
+
43
+ ## How it works
44
+
45
+ <!-- Optional: what one needs to understand about the processing to tune the parameters. Remove the section if it adds nothing. -->
46
+
47
+ ## Examples
48
+
49
+ <!-- To write: before/after cases, each recorded by a test with the help_example("<name>", ...) fixture,
50
+ then cited by an empty generated:example:<name> block, which 'task py:help' fills (exact form in the plugin-help skill).
51
+ One example per parameter that changes the result. The caption around the block is yours. -->
52
+
53
+ ## Known limitations
54
+
55
+ <!-- To write: the cases where the result is surprising, each with a short example. -->
@@ -0,0 +1,55 @@
1
+ # Processeur coreference (`coreference`)
2
+
3
+ <!-- À écrire : ce que fait le plugin, en une phrase, avec un exemple concret entre guillemets. -->
4
+
5
+ ## Quand l'utiliser
6
+
7
+ <!-- À écrire : deux ou trois situations, dans les mots de l'utilisateur de Sherpa (projet, corpus, recherche), pas dans ceux du code. -->
8
+
9
+ ## Quand ne pas l'utiliser
10
+
11
+ <!-- À écrire : ce que le plugin ne fait pas et qu'on pourrait attendre de lui, et quel autre plugin le fait. -->
12
+
13
+ ## Prérequis
14
+
15
+ <!-- À écrire : ce que le plugin attend en entrée (langue du document, découpage en phrases, annotations d'un autre plugin…), obligatoire ou recommandé, et pourquoi. -->
16
+
17
+ <!-- generated:languages -->
18
+
19
+ **Langues prises en charge :** le plugin ne déclare aucune restriction de langue.
20
+
21
+ <!-- /generated:languages -->
22
+
23
+ ## Ce qu'il produit
24
+
25
+ <!-- À écrire : ce que le plugin ajoute ou change dans le document (annotations et leurs labels, termes, catégories, métadonnées, texte…). Dire aussi ce qu'il retire ou remplace. -->
26
+
27
+ ## Paramètres
28
+
29
+ <!-- Le tableau est généré par 'task py:help' : nom affiché et valeur par défaut viennent du code.
30
+ La colonne « Effet » est à vous : elle part de la description du code et se conserve d'une
31
+ génération à l'autre. Une valeur par défaut calculée (None dans le code) s'écrit à la main. -->
32
+
33
+ <!-- generated:parameters -->
34
+
35
+ | Paramètre | Valeur par défaut | Effet |
36
+ |---|---|---|
37
+ | **Labels** (`labels`) | — | Labels of the mentions to group. If empty, the mentions of every label are grouped.<br/> Mentions are only grouped with mentions of the same label, except person labels, which all form one family. |
38
+ | **Person Labels** (`person_labels`) | — | Labels of person names. They form one family (person and afpperson mentions are grouped together), and a partial name ("Macron") joins the full name it ends ("Emmanuel Macron").<br/> If empty, every label whose name contains "person" (person, afpperson...). |
39
+ | **Honorifics** (`honorifics`) *(avancé)* | `["M.", "MM.", "Mme", "Mmes", "Mlle", "Mlles", "Me", "Dr", "Dr.", "Pr", "Pr.", "Mr", "Mr.", "Mrs", "Mrs.", "Ms", "Ms.", "Miss", "Sir", "Dame", "Lord", "Lady"]` | Honorifics ignored in front of a person name when comparing names (M., Mme, Dr...) |
40
+
41
+ <!-- /generated:parameters -->
42
+
43
+ ## Fonctionnement
44
+
45
+ <!-- Facultatif : ce qu'il faut comprendre du traitement pour bien régler les paramètres. Supprimer la section si elle n'apporte rien. -->
46
+
47
+ ## Exemples
48
+
49
+ <!-- À écrire : des cas avant/après, chacun enregistré par un test avec la fixture help_example("<nom>", ...),
50
+ puis cité par un bloc generated:example:<nom> vide, que 'task py:help' remplit (la forme exacte est dans le skill plugin-help).
51
+ Un exemple par paramètre qui change le résultat. La légende autour du bloc est à vous. -->
52
+
53
+ ## Limites à connaître
54
+
55
+ <!-- À écrire : les cas où le résultat surprend, chacun avec un exemple court. -->
@@ -1,3 +1,3 @@
1
1
  """Processor grouping the mentions of the same entity"""
2
2
 
3
- __version__ = "1.6.3"
3
+ __version__ = "1.6.8"
@@ -2,8 +2,8 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "python-archetype",
4
4
  "displayName": "Kairntech python-archetype",
5
- "version": "1.1.0",
6
- "description": "Cree et entretient les depots Python de Kairntech qui consomment python-archetype : creation d'un plugin a partir de sa graine, et mesure de la derive d'un depot par rapport a elle.",
5
+ "version": "1.3.2",
6
+ "description": "Cree et entretient les depots Python de Kairntech qui consomment python-archetype : creation d'un plugin a partir de sa graine, page d'aide Sherpa d'un plugin, et mesure de la derive d'un depot par rapport a elle.",
7
7
  "author": {
8
8
  "name": "Kairntech",
9
9
  "email": "olivier.terrier@kairntech.com"
@@ -12,7 +12,7 @@ pas dériver de lui.
12
12
  |---------|------|
13
13
  | `.claude-plugin/marketplace.json` | Le catalogue : nom `kairntech-python`, la liste des plugins offerts. |
14
14
  | `.claude-plugin/plugin.json` | Le plugin `python-archetype` : identité, version, et `"skills": "./skills/"`. |
15
- | `skills/<nom>/SKILL.md` | Un skill. Aujourd'hui `new-plugin`. |
15
+ | `skills/<nom>/SKILL.md` | Un skill. Aujourd'hui `new-plugin` et `plugin-help`. |
16
16
 
17
17
  L'entrée du catalogue porte `"source": "."` — **le plugin est la racine du dépôt**,
18
18
  pas un sous-répertoire. Il n'y a donc qu'une chose à cloner, et le skill voit
@@ -10,7 +10,8 @@ Rien ici ne connaît un projet en particulier.
10
10
 
11
11
  | Fichier | Rôle |
12
12
  |---------|------|
13
- | `resources/Taskfile.yml` | Les tasks : `sync`, `lock-check`, `lint`, `format`, `test`, `test-marker`, `sbom`, `check-vulnerabilities`, `check-updates`, `build`, `publish`. |
13
+ | `resources/Taskfile.yml` | Les tasks : `sync`, `lock-check`, `lint`, `format`, `test`, `test-marker`, `sbom`, `check-vulnerabilities`, `check-updates`, `build`, `publish`, `help`, `help-check`. |
14
+ | `resources/help/` | Les pages d'aide Sherpa d'un plugin : `plugin-help.py`, que lancent `help` et `help-check`, les modèles `template.fr.md` / `template.en.md`, et la fixture pytest `help_examples.py`, qui enregistre les exemples pendant les tests. |
14
15
  | `resources/Stages.yml` | Le lanceur de pipeline : `default`, `up-to`, `jenkins`, `stages`. Générique — il ne connaît que la liste `STAGES`. |
15
16
 
16
17
  Ils sont séparés parce qu'ils s'incluent différemment : les tasks sous un
@@ -67,6 +68,8 @@ dont Jenkins a besoin puisqu'il injecte ses propres étapes entre les stages.
67
68
  | `PYTEST_ARGS` | — | |
68
69
  | `LOCK_VERSIONED` | `true` | Sur `false`, `sync` résout à neuf (`--upgrade`) : un `uv.lock` non versionné qui traîne sur un poste est périmé, et `uv sync` s'en servirait en silence — on testerait et auditerait des versions que la CI ne voit jamais. |
69
70
  | `AUDIT_ARGS` | — | Options pip-audit. **Pas `--strict`** : il rend fatal « dépendance absente de PyPI », ce qu'un workspace produit toujours. |
71
+ | `HELP_DIR` | `docs/sherpa` | Où `help` écrit les pages d'aide Sherpa, une par entry-point et par langue (`<entry-point>.<langue>.md`). |
72
+ | `HELP_LANGS` | `fr en` | Langues des pages d'aide ; il faut un `resources/help/template.<langue>.md` par langue. |
70
73
  | `STAGES` | `sync lock-check lint test build publish` | |
71
74
  | `TEST_STAGE` | `test` | Le stage que `task -- --skip-tests` saute. |
72
75
  | `NON_BLOCKING_STAGES` | — | Stages dont l'échec est signalé sans interrompre ; le run sort quand même en non-zéro. À garder vide. |
@@ -0,0 +1,126 @@
1
+ """Fixture pytest 'help_example' : enregistre un exemple de page d'aide pendant un test.
2
+
3
+ Un exemple de page d'aide montre une sortie du plugin. Écrite à la main, elle est
4
+ déduite ou recopiée, et devient fausse sans que rien ne le signale au premier
5
+ changement de comportement. Enregistrée par un test, elle a forcément été produite
6
+ par le plugin, et 'task py:help-check' échoue dès que la page ne la montre plus.
7
+
8
+ Le test appelle la fixture explicitement, après avoir lancé le plugin, et garde ses
9
+ assertions — l'exemple ne remplace pas la vérification :
10
+
11
+ def test_propagate_false(help_example):
12
+ ...
13
+ docs = annotator.annotate([doc], parameters)
14
+ help_example("propagate-false", inputs=[doc], parameters=parameters, outputs=docs)
15
+ assert ...
16
+
17
+ L'exemple est écrit dans 'build/help-examples/<nom>.json', à la racine du dépôt :
18
+ recalculé à chaque 'py:test', il n'est pas versionné. La page le cite par un bloc
19
+ '<!-- generated:example:<nom> -->', que 'task py:help' remplit.
20
+
21
+ Le dépôt du plugin rend la fixture visible depuis 'tests/conftest.py' :
22
+
23
+ sys.path.insert(0, str(Path(__file__).parents[1] / "submodules/python-archetype/resources/help"))
24
+ from help_examples import help_example # noqa: E402, F401
25
+ """
26
+
27
+ import json
28
+ from pathlib import Path
29
+
30
+ import pytest
31
+
32
+ EXAMPLES_DIR = Path("build") / "help-examples"
33
+
34
+
35
+ # Au-delà, un contenu n'est pas recopié : une page n'en montre de toute façon qu'un extrait.
36
+ MAX_CONTENT = 100_000
37
+
38
+
39
+ def _content(data: bytes) -> dict:
40
+ """Le contenu d'un fichier ou d'une réponse : son texte s'il en est un, sa taille sinon."""
41
+ content = {"size": len(data)}
42
+ try:
43
+ text = data.decode("utf-8")
44
+ except UnicodeDecodeError:
45
+ return content
46
+ content["text"] = text[:MAX_CONTENT]
47
+ if len(text) > MAX_CONTENT:
48
+ content["truncated"] = True
49
+ return content
50
+
51
+
52
+ def _upload(upload) -> dict:
53
+ # Le fichier a déjà été lu par le plugin : on le relit depuis le début, puis on rend
54
+ # la position. Un fichier déjà fermé (le 'with open' du test est sorti) ne se relit
55
+ # plus : appeler help_example DANS le bloc 'with'.
56
+ plain = {"kind": "file", "filename": upload.filename, "content_type": upload.content_type}
57
+ try:
58
+ position = upload.file.tell()
59
+ upload.file.seek(0)
60
+ plain.update(_content(upload.file.read()))
61
+ upload.file.seek(position)
62
+ except (ValueError, OSError):
63
+ pass
64
+ return plain
65
+
66
+
67
+ def _response(response) -> dict:
68
+ plain = {"kind": "response", "status_code": response.status_code, "media_type": response.media_type}
69
+ disposition = response.headers.get("content-disposition")
70
+ if disposition:
71
+ plain["content_disposition"] = disposition
72
+ body = getattr(response, "body", None)
73
+ if isinstance(body, bytes):
74
+ plain.update(_content(body))
75
+ return plain
76
+
77
+
78
+ def _plain(value):
79
+ # Les modèles pydantic en JSON, sans les champs vides : la page ne montre pas l'absence.
80
+ if hasattr(value, "model_dump"):
81
+ # warnings=False : un plugin qui met des dicts là où le schéma attend des modèles
82
+ # (des phrases, par exemple) ferait crouler la sortie du test sous les avertissements.
83
+ return value.model_dump(mode="json", exclude_none=True, warnings=False)
84
+ # L'entrée d'un convertisseur (starlette UploadFile) et celle d'un importeur (un chemin).
85
+ if hasattr(value, "filename") and hasattr(value, "file"):
86
+ return _upload(value)
87
+ if isinstance(value, Path):
88
+ return {"kind": "file", "filename": value.name, **_content(value.read_bytes())}
89
+ # La sortie d'un formateur (starlette Response).
90
+ if hasattr(value, "status_code") and hasattr(value, "media_type"):
91
+ return _response(value)
92
+ if isinstance(value, bytes):
93
+ return _content(value)
94
+ if isinstance(value, (list, tuple)):
95
+ return [_plain(item) for item in value]
96
+ if isinstance(value, dict):
97
+ return {key: _plain(item) for key, item in value.items()}
98
+ return value
99
+
100
+
101
+ @pytest.fixture
102
+ def help_example(request):
103
+ directory = request.config.rootpath / EXAMPLES_DIR
104
+
105
+ def record(name: str, *, inputs, parameters, outputs) -> None:
106
+ # Seuls les paramètres qui s'écartent du défaut : ce sont eux que l'exemple illustre.
107
+ # D'où le modèle et non son dict : un importeur reçoit 'options.model_dump()', mais
108
+ # c'est 'options' qu'il faut passer ici, sans quoi tout paraît modifié.
109
+ if isinstance(parameters, dict):
110
+ raise TypeError(f"help_example({name!r}) : passer le modèle de paramètres, pas son dict")
111
+ params = parameters.model_dump(mode="json", exclude_defaults=True) if parameters is not None else {}
112
+ # Un générateur (la sortie d'un importeur) ne se lit qu'une fois : au test d'en faire
113
+ # une liste, qu'il vérifie et qu'il passe ici.
114
+ if not isinstance(outputs, (list, tuple)) and hasattr(outputs, "__next__"):
115
+ raise TypeError(f"help_example({name!r}) : passer une liste, pas un générateur")
116
+ example = {
117
+ "test": request.node.nodeid,
118
+ "parameters": params,
119
+ "inputs": _plain(inputs),
120
+ "outputs": _plain(outputs),
121
+ }
122
+ directory.mkdir(parents=True, exist_ok=True)
123
+ path = directory / f"{name}.json"
124
+ path.write_text(json.dumps(example, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8")
125
+
126
+ return record