denckring 0.1.0__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.
- denckring-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +37 -0
- denckring-0.1.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
- denckring-0.1.0/.github/ISSUE_TEMPLATE/new_procedure.yml +49 -0
- denckring-0.1.0/.github/dependabot.yml +39 -0
- denckring-0.1.0/.github/pull_request_template.md +18 -0
- denckring-0.1.0/.github/workflows/ci.yml +293 -0
- denckring-0.1.0/.github/workflows/release.yml +175 -0
- denckring-0.1.0/.gitignore +39 -0
- denckring-0.1.0/.pre-commit-config.yaml +31 -0
- denckring-0.1.0/.python-version +1 -0
- denckring-0.1.0/CHANGELOG.md +1202 -0
- denckring-0.1.0/CITATION.cff +29 -0
- denckring-0.1.0/CODE_OF_CONDUCT.md +34 -0
- denckring-0.1.0/CONTRIBUTING.md +116 -0
- denckring-0.1.0/LICENSE +202 -0
- denckring-0.1.0/LICENSE-DATA +56 -0
- denckring-0.1.0/Makefile +151 -0
- denckring-0.1.0/NOTICE +16 -0
- denckring-0.1.0/PKG-INFO +335 -0
- denckring-0.1.0/README.md +291 -0
- denckring-0.1.0/SECURITY.md +30 -0
- denckring-0.1.0/docs/adr/0001-english-api-multilingual-content.md +22 -0
- denckring-0.1.0/docs/adr/0002-check-mandatory-apply-optional.md +28 -0
- denckring-0.1.0/docs/adr/0003-catalogue-yaml-not-sqlite.md +19 -0
- denckring-0.1.0/docs/adr/0004-language-packs-as-capabilities.md +24 -0
- denckring-0.1.0/docs/adr/0005-continuous-score.md +20 -0
- denckring-0.1.0/docs/adr/0006-dual-licence.md +25 -0
- denckring-0.1.0/docs/adr/0007-one-module-per-procedure.md +21 -0
- denckring-0.1.0/docs/adr/0008-catalogue-inside-package.md +19 -0
- denckring-0.1.0/docs/adr/0009-folding-is-a-parameter.md +30 -0
- denckring-0.1.0/docs/adr/0010-packs-via-entry-points.md +29 -0
- denckring-0.1.0/docs/adr/0011-checkability.md +44 -0
- denckring-0.1.0/docs/adr/0012-syllable-capabilities.md +35 -0
- denckring-0.1.0/docs/adr/0013-data-as-a-separate-distribution.md +32 -0
- denckring-0.1.0/docs/adr/0014-metre-as-satisfiability.md +40 -0
- denckring-0.1.0/docs/adr/0015-lexicon-capabilities.md +37 -0
- denckring-0.1.0/docs/adr/0016-one-pack-per-language.md +30 -0
- denckring-0.1.0/docs/adr/0017-devices-ship-with-their-procedures.md +43 -0
- denckring-0.1.0/docs/adr/0018-attestation.md +43 -0
- denckring-0.1.0/docs/adr/0019-figures.md +45 -0
- denckring-0.1.0/docs/adr/0020-corpora-are-not-shipped.md +39 -0
- denckring-0.1.0/docs/adr/0021-the-transferable-part.md +42 -0
- denckring-0.1.0/docs/adr/0022-german-moves-to-a-default.md +31 -0
- denckring-0.1.0/docs/adr/0023-the-german-lexicon.md +49 -0
- denckring-0.1.0/docs/adr/0024-apache-two-for-the-code.md +54 -0
- denckring-0.1.0/docs/adr/0025-the-apply-spine.md +115 -0
- denckring-0.1.0/docs/adr/0026-the-production-surface.md +144 -0
- denckring-0.1.0/docs/adr/0027-candidates-carry-their-scores.md +107 -0
- denckring-0.1.0/docs/adr/0028-the-graded-lexicon.md +154 -0
- denckring-0.1.0/docs/adr/0029-the-choices-the-catalogue-promised.md +213 -0
- denckring-0.1.0/docs/adr/0030-german-pronunciations.md +194 -0
- denckring-0.1.0/docs/adr/0031-devices-are-address-spaces.md +151 -0
- denckring-0.1.0/docs/adr/0032-the-french-lexicon.md +204 -0
- denckring-0.1.0/docs/adr/0033-the-layer-split.md +117 -0
- denckring-0.1.0/docs/adr/0034-french-prosody.md +221 -0
- denckring-0.1.0/docs/adr/0035-orthographic-and-phonetic-readings.md +298 -0
- denckring-0.1.0/docs/adr/0036-the-elision-seam.md +109 -0
- denckring-0.1.0/docs/adr/0037-the-calculator-word.md +128 -0
- denckring-0.1.0/docs/adr/0038-german-frequency.md +147 -0
- denckring-0.1.0/docs/api/errors.md +35 -0
- denckring-0.1.0/docs/api/functions.md +15 -0
- denckring-0.1.0/docs/api/index.md +78 -0
- denckring-0.1.0/docs/api/packs.md +23 -0
- denckring-0.1.0/docs/api/types.md +19 -0
- denckring-0.1.0/mkdocs.yml +134 -0
- denckring-0.1.0/pyproject.toml +170 -0
- denckring-0.1.0/scripts/build_docs.py +263 -0
- denckring-0.1.0/scripts/build_overview_gif.py +124 -0
- denckring-0.1.0/scripts/new_procedure.py +81 -0
- denckring-0.1.0/scripts/rings_from_text.py +82 -0
- denckring-0.1.0/scripts/templates/catalogue_row.yaml.tmpl +12 -0
- denckring-0.1.0/scripts/templates/golden.yaml.tmpl +13 -0
- denckring-0.1.0/scripts/templates/procedure.py.tmpl +25 -0
- denckring-0.1.0/scripts/templates/strategy.py.tmpl +12 -0
- denckring-0.1.0/scripts/templates/test.py.tmpl +9 -0
- denckring-0.1.0/skills/denckring/SKILL.md +65 -0
- denckring-0.1.0/src/denckring/__init__.py +65 -0
- denckring-0.1.0/src/denckring/cli.py +359 -0
- denckring-0.1.0/src/denckring/core/__init__.py +0 -0
- denckring-0.1.0/src/denckring/core/arca.py +94 -0
- denckring-0.1.0/src/denckring/core/base.py +447 -0
- denckring-0.1.0/src/denckring/core/calculator.py +78 -0
- denckring-0.1.0/src/denckring/core/catalogue.py +46 -0
- denckring-0.1.0/src/denckring/core/corpus.py +126 -0
- denckring-0.1.0/src/denckring/core/describe.py +250 -0
- denckring-0.1.0/src/denckring/core/device.py +670 -0
- denckring-0.1.0/src/denckring/core/errors.py +516 -0
- denckring-0.1.0/src/denckring/core/pasigraph.py +88 -0
- denckring-0.1.0/src/denckring/core/prosody.py +395 -0
- denckring-0.1.0/src/denckring/core/protocol.py +282 -0
- denckring-0.1.0/src/denckring/core/registry.py +55 -0
- denckring-0.1.0/src/denckring/core/source_compare.py +233 -0
- denckring-0.1.0/src/denckring/core/text.py +187 -0
- denckring-0.1.0/src/denckring/data/catalogue.yaml +3539 -0
- denckring-0.1.0/src/denckring/data/devices/harsdoerffer_1651.yaml +337 -0
- denckring-0.1.0/src/denckring/data/devices/poesieautomat_2000.yaml +602 -0
- denckring-0.1.0/src/denckring/data/figures/kircher_ars_magna.yaml +22 -0
- denckring-0.1.0/src/denckring/data/figures/llull_ternary.yaml +80 -0
- denckring-0.1.0/src/denckring/eval/__init__.py +0 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/abecedarian.yaml +32 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/acrostic.yaml +46 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/alcaic_stanza.yaml +46 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/alexandrine.yaml +37 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/alliterative_verse.yaml +41 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/alphabetical_sentence.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/anagram.yaml +60 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/anaphora.yaml +18 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/antigram.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/arca_musarithmica.yaml +61 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/assonance_constraint.yaml +41 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/ballade.yaml +169 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/beau_present.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/belle_absente.yaml +19 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/bivocalic.yaml +19 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/blank_verse.yaml +48 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/boustrophedon.yaml +53 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/buchstabwechsel.yaml +24 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/calculator_word.yaml +103 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/cent_mille_milliards.yaml +103 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/charade.yaml +36 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/chronogram.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/cinquain.yaml +56 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/clerihew.yaml +51 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/column_reading.yaml +45 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/consonantal_lipogram.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/curtal_sonnet.yaml +83 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/cut_up.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/dactylic_hexameter.yaml +29 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/definitional_expansion.yaml +51 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/definitional_literature.yaml +58 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/denckring.yaml +19 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/diastic.yaml +33 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/double_acrostic.yaml +17 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/double_dactyl.yaml +50 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/elegiac_couplet.yaml +32 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/englyn.yaml +69 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/eodermdrome.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/epistrophe.yaml +17 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/every_nth_word.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/fold_in.yaml +57 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/ghazal.yaml +59 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/haibun.yaml +48 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/haiku.yaml +46 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/haikuization.yaml +41 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/hemeling.yaml +86 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/hendecasyllable.yaml +31 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/heroic_couplet.yaml +40 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/heterogram.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/homoconsonantism.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/homoteleuton.yaml +27 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/homovocalism.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/iambic_pentameter.yaml +44 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/ideenwuerfeln.yaml +44 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/kangaroo_word.yaml +52 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/larding.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/letter_bank.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/limerick.yaml +56 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/lipogram.yaml +44 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/lipogrammatic_translation.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/liponym.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/llull_figure.yaml +28 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/mathews_algorithm.yaml +61 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/melting_text.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/mesostic.yaml +49 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/monoconsonantal.yaml +21 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/monosyllabic_prose.yaml +31 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/multiple_constraint.yaml +33 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/n_plus_7.yaml +69 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/ottava_rima.yaml +68 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/palindrome.yaml +31 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/pangram.yaml +30 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/pangrammatic_lipogram.yaml +27 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/pangrammatic_window.yaml +24 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/pantoum.yaml +29 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/paragram.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/pasigraphy.yaml +34 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/petrarchan_sonnet.yaml +72 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/poesie_automat.yaml +78 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/prisoners_constraint.yaml +31 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/proteus_verse.yaml +68 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/quenina.yaml +60 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/recombination.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/renga.yaml +55 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/reverse_snowball.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/rhyme_royal.yaml +49 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/rhyme_scheme.yaml +68 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/rondeau.yaml +106 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/s_plus_7.yaml +72 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/sapphic_stanza.yaml +45 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/sator_square.yaml +23 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/semordnilap.yaml +43 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/senryu.yaml +46 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/sentence_length_constraint.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/serial_lipogram.yaml +129 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/sestina.yaml +61 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/shakespearean_sonnet.yaml +72 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/single_sentence.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/slenderizing.yaml +51 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/snowball.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/snowball_sentence.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/sonnet.yaml +98 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/spenserian_stanza.yaml +74 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/spoonerism.yaml +43 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/supervocalic.yaml +29 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/syllable_count.yaml +49 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/tanka.yaml +52 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/tautogram.yaml +39 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/tautonym.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/telestich.yaml +35 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/terza_rima.yaml +62 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/text_folding.yaml +73 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/tmesis.yaml +43 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/transposal.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/triolet.yaml +71 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/trochaic_tetrameter.yaml +30 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/univocalic.yaml +33 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/univocalic_translation.yaml +25 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/villanelle.yaml +100 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/wechselsatz.yaml +13 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/word_ladder.yaml +57 -0
- denckring-0.1.0/src/denckring/eval/fixtures/golden/word_square.yaml +57 -0
- denckring-0.1.0/src/denckring/eval/harness.py +181 -0
- denckring-0.1.0/src/denckring/lang/__init__.py +92 -0
- denckring-0.1.0/src/denckring/lang/base.py +228 -0
- denckring-0.1.0/src/denckring/lang/de.py +80 -0
- denckring-0.1.0/src/denckring/lang/en.py +65 -0
- denckring-0.1.0/src/denckring/lang/fr.py +53 -0
- denckring-0.1.0/src/denckring/mcp/__init__.py +1 -0
- denckring-0.1.0/src/denckring/mcp/server.py +141 -0
- denckring-0.1.0/src/denckring/procedures/__init__.py +0 -0
- denckring-0.1.0/src/denckring/procedures/abecedarian.py +87 -0
- denckring-0.1.0/src/denckring/procedures/acrostic.py +87 -0
- denckring-0.1.0/src/denckring/procedures/alcaic_stanza.py +48 -0
- denckring-0.1.0/src/denckring/procedures/alexandrine.py +32 -0
- denckring-0.1.0/src/denckring/procedures/alliterative_verse.py +71 -0
- denckring-0.1.0/src/denckring/procedures/alphabetical_sentence.py +45 -0
- denckring-0.1.0/src/denckring/procedures/anagram.py +334 -0
- denckring-0.1.0/src/denckring/procedures/anaphora.py +46 -0
- denckring-0.1.0/src/denckring/procedures/antigram.py +53 -0
- denckring-0.1.0/src/denckring/procedures/arca_musarithmica.py +146 -0
- denckring-0.1.0/src/denckring/procedures/assonance_constraint.py +97 -0
- denckring-0.1.0/src/denckring/procedures/ballade.py +116 -0
- denckring-0.1.0/src/denckring/procedures/beau_present.py +58 -0
- denckring-0.1.0/src/denckring/procedures/belle_absente.py +94 -0
- denckring-0.1.0/src/denckring/procedures/bivocalic.py +78 -0
- denckring-0.1.0/src/denckring/procedures/blank_verse.py +59 -0
- denckring-0.1.0/src/denckring/procedures/boustrophedon.py +111 -0
- denckring-0.1.0/src/denckring/procedures/buchstabwechsel.py +121 -0
- denckring-0.1.0/src/denckring/procedures/calculator_word.py +266 -0
- denckring-0.1.0/src/denckring/procedures/cent_mille_milliards.py +135 -0
- denckring-0.1.0/src/denckring/procedures/charade.py +68 -0
- denckring-0.1.0/src/denckring/procedures/chronogram.py +62 -0
- denckring-0.1.0/src/denckring/procedures/cinquain.py +30 -0
- denckring-0.1.0/src/denckring/procedures/clerihew.py +43 -0
- denckring-0.1.0/src/denckring/procedures/column_reading.py +103 -0
- denckring-0.1.0/src/denckring/procedures/consonantal_lipogram.py +52 -0
- denckring-0.1.0/src/denckring/procedures/curtal_sonnet.py +40 -0
- denckring-0.1.0/src/denckring/procedures/cut_up.py +73 -0
- denckring-0.1.0/src/denckring/procedures/dactylic_hexameter.py +73 -0
- denckring-0.1.0/src/denckring/procedures/definitional_expansion.py +176 -0
- denckring-0.1.0/src/denckring/procedures/definitional_literature.py +194 -0
- denckring-0.1.0/src/denckring/procedures/denckring.py +167 -0
- denckring-0.1.0/src/denckring/procedures/diastic.py +129 -0
- denckring-0.1.0/src/denckring/procedures/double_acrostic.py +80 -0
- denckring-0.1.0/src/denckring/procedures/double_dactyl.py +77 -0
- denckring-0.1.0/src/denckring/procedures/elegiac_couplet.py +75 -0
- denckring-0.1.0/src/denckring/procedures/englyn.py +50 -0
- denckring-0.1.0/src/denckring/procedures/eodermdrome.py +78 -0
- denckring-0.1.0/src/denckring/procedures/epistrophe.py +46 -0
- denckring-0.1.0/src/denckring/procedures/every_nth_word.py +77 -0
- denckring-0.1.0/src/denckring/procedures/fold_in.py +157 -0
- denckring-0.1.0/src/denckring/procedures/ghazal.py +131 -0
- denckring-0.1.0/src/denckring/procedures/haibun.py +114 -0
- denckring-0.1.0/src/denckring/procedures/haiku.py +30 -0
- denckring-0.1.0/src/denckring/procedures/haikuization.py +113 -0
- denckring-0.1.0/src/denckring/procedures/hemeling.py +135 -0
- denckring-0.1.0/src/denckring/procedures/hendecasyllable.py +32 -0
- denckring-0.1.0/src/denckring/procedures/heroic_couplet.py +56 -0
- denckring-0.1.0/src/denckring/procedures/heterogram.py +62 -0
- denckring-0.1.0/src/denckring/procedures/homoconsonantism.py +47 -0
- denckring-0.1.0/src/denckring/procedures/homoteleuton.py +68 -0
- denckring-0.1.0/src/denckring/procedures/homovocalism.py +44 -0
- denckring-0.1.0/src/denckring/procedures/iambic_pentameter.py +42 -0
- denckring-0.1.0/src/denckring/procedures/ideenwuerfeln.py +186 -0
- denckring-0.1.0/src/denckring/procedures/kangaroo_word.py +100 -0
- denckring-0.1.0/src/denckring/procedures/larding.py +161 -0
- denckring-0.1.0/src/denckring/procedures/letter_bank.py +57 -0
- denckring-0.1.0/src/denckring/procedures/limerick.py +40 -0
- denckring-0.1.0/src/denckring/procedures/lipogram.py +62 -0
- denckring-0.1.0/src/denckring/procedures/lipogrammatic_translation.py +63 -0
- denckring-0.1.0/src/denckring/procedures/liponym.py +51 -0
- denckring-0.1.0/src/denckring/procedures/llull_figure.py +158 -0
- denckring-0.1.0/src/denckring/procedures/mathews_algorithm.py +144 -0
- denckring-0.1.0/src/denckring/procedures/melting_text.py +73 -0
- denckring-0.1.0/src/denckring/procedures/mesostic.py +118 -0
- denckring-0.1.0/src/denckring/procedures/monoconsonantal.py +71 -0
- denckring-0.1.0/src/denckring/procedures/monosyllabic_prose.py +50 -0
- denckring-0.1.0/src/denckring/procedures/multiple_constraint.py +131 -0
- denckring-0.1.0/src/denckring/procedures/n_plus_7.py +301 -0
- denckring-0.1.0/src/denckring/procedures/ottava_rima.py +39 -0
- denckring-0.1.0/src/denckring/procedures/palindrome.py +57 -0
- denckring-0.1.0/src/denckring/procedures/pangram.py +64 -0
- denckring-0.1.0/src/denckring/procedures/pangrammatic_lipogram.py +79 -0
- denckring-0.1.0/src/denckring/procedures/pangrammatic_window.py +78 -0
- denckring-0.1.0/src/denckring/procedures/pantoum.py +66 -0
- denckring-0.1.0/src/denckring/procedures/paragram.py +177 -0
- denckring-0.1.0/src/denckring/procedures/pasigraphy.py +158 -0
- denckring-0.1.0/src/denckring/procedures/petrarchan_sonnet.py +41 -0
- denckring-0.1.0/src/denckring/procedures/poesie_automat.py +166 -0
- denckring-0.1.0/src/denckring/procedures/prisoners_constraint.py +48 -0
- denckring-0.1.0/src/denckring/procedures/proteus_verse.py +314 -0
- denckring-0.1.0/src/denckring/procedures/quenina.py +158 -0
- denckring-0.1.0/src/denckring/procedures/recombination.py +106 -0
- denckring-0.1.0/src/denckring/procedures/renga.py +96 -0
- denckring-0.1.0/src/denckring/procedures/reverse_snowball.py +37 -0
- denckring-0.1.0/src/denckring/procedures/rhyme_royal.py +41 -0
- denckring-0.1.0/src/denckring/procedures/rhyme_scheme.py +156 -0
- denckring-0.1.0/src/denckring/procedures/rondeau.py +89 -0
- denckring-0.1.0/src/denckring/procedures/s_plus_7.py +51 -0
- denckring-0.1.0/src/denckring/procedures/sapphic_stanza.py +52 -0
- denckring-0.1.0/src/denckring/procedures/sator_square.py +109 -0
- denckring-0.1.0/src/denckring/procedures/semordnilap.py +60 -0
- denckring-0.1.0/src/denckring/procedures/senryu.py +30 -0
- denckring-0.1.0/src/denckring/procedures/sentence_length_constraint.py +51 -0
- denckring-0.1.0/src/denckring/procedures/serial_lipogram.py +113 -0
- denckring-0.1.0/src/denckring/procedures/sestina.py +31 -0
- denckring-0.1.0/src/denckring/procedures/shakespearean_sonnet.py +41 -0
- denckring-0.1.0/src/denckring/procedures/single_sentence.py +53 -0
- denckring-0.1.0/src/denckring/procedures/slenderizing.py +123 -0
- denckring-0.1.0/src/denckring/procedures/snowball.py +61 -0
- denckring-0.1.0/src/denckring/procedures/snowball_sentence.py +52 -0
- denckring-0.1.0/src/denckring/procedures/sonnet.py +66 -0
- denckring-0.1.0/src/denckring/procedures/spenserian_stanza.py +61 -0
- denckring-0.1.0/src/denckring/procedures/spoonerism.py +221 -0
- denckring-0.1.0/src/denckring/procedures/supervocalic.py +56 -0
- denckring-0.1.0/src/denckring/procedures/syllable_count.py +97 -0
- denckring-0.1.0/src/denckring/procedures/tanka.py +30 -0
- denckring-0.1.0/src/denckring/procedures/tautogram.py +72 -0
- denckring-0.1.0/src/denckring/procedures/tautonym.py +48 -0
- denckring-0.1.0/src/denckring/procedures/telestich.py +17 -0
- denckring-0.1.0/src/denckring/procedures/terza_rima.py +55 -0
- denckring-0.1.0/src/denckring/procedures/text_folding.py +126 -0
- denckring-0.1.0/src/denckring/procedures/tmesis.py +104 -0
- denckring-0.1.0/src/denckring/procedures/transposal.py +62 -0
- denckring-0.1.0/src/denckring/procedures/triolet.py +42 -0
- denckring-0.1.0/src/denckring/procedures/trochaic_tetrameter.py +42 -0
- denckring-0.1.0/src/denckring/procedures/univocalic.py +76 -0
- denckring-0.1.0/src/denckring/procedures/univocalic_translation.py +60 -0
- denckring-0.1.0/src/denckring/procedures/villanelle.py +42 -0
- denckring-0.1.0/src/denckring/procedures/wechselsatz.py +145 -0
- denckring-0.1.0/src/denckring/procedures/word_ladder.py +354 -0
- denckring-0.1.0/src/denckring/procedures/word_square.py +95 -0
- denckring-0.1.0/src/denckring/py.typed +0 -0
- denckring-0.1.0/tests/conftest.py +67 -0
- denckring-0.1.0/tests/strategies/__init__.py +16 -0
- denckring-0.1.0/tests/strategies/abecedarian.py +25 -0
- denckring-0.1.0/tests/strategies/acrostic.py +25 -0
- denckring-0.1.0/tests/strategies/alcaic_stanza.py +80 -0
- denckring-0.1.0/tests/strategies/alexandrine.py +20 -0
- denckring-0.1.0/tests/strategies/alliterative_verse.py +24 -0
- denckring-0.1.0/tests/strategies/alphabetical_sentence.py +15 -0
- denckring-0.1.0/tests/strategies/anagram.py +22 -0
- denckring-0.1.0/tests/strategies/anaphora.py +19 -0
- denckring-0.1.0/tests/strategies/antigram.py +20 -0
- denckring-0.1.0/tests/strategies/arca_musarithmica.py +48 -0
- denckring-0.1.0/tests/strategies/assonance_constraint.py +25 -0
- denckring-0.1.0/tests/strategies/ballade.py +53 -0
- denckring-0.1.0/tests/strategies/beau_present.py +17 -0
- denckring-0.1.0/tests/strategies/belle_absente.py +57 -0
- denckring-0.1.0/tests/strategies/bivocalic.py +19 -0
- denckring-0.1.0/tests/strategies/blank_verse.py +30 -0
- denckring-0.1.0/tests/strategies/boustrophedon.py +36 -0
- denckring-0.1.0/tests/strategies/buchstabwechsel.py +32 -0
- denckring-0.1.0/tests/strategies/calculator_word.py +57 -0
- denckring-0.1.0/tests/strategies/cent_mille_milliards.py +25 -0
- denckring-0.1.0/tests/strategies/charade.py +22 -0
- denckring-0.1.0/tests/strategies/chronogram.py +19 -0
- denckring-0.1.0/tests/strategies/cinquain.py +22 -0
- denckring-0.1.0/tests/strategies/clerihew.py +30 -0
- denckring-0.1.0/tests/strategies/column_reading.py +41 -0
- denckring-0.1.0/tests/strategies/consonantal_lipogram.py +17 -0
- denckring-0.1.0/tests/strategies/curtal_sonnet.py +34 -0
- denckring-0.1.0/tests/strategies/cut_up.py +24 -0
- denckring-0.1.0/tests/strategies/dactylic_hexameter.py +45 -0
- denckring-0.1.0/tests/strategies/definitional_expansion.py +29 -0
- denckring-0.1.0/tests/strategies/definitional_literature.py +31 -0
- denckring-0.1.0/tests/strategies/denckring.py +24 -0
- denckring-0.1.0/tests/strategies/diastic.py +32 -0
- denckring-0.1.0/tests/strategies/double_acrostic.py +30 -0
- denckring-0.1.0/tests/strategies/double_dactyl.py +83 -0
- denckring-0.1.0/tests/strategies/elegiac_couplet.py +64 -0
- denckring-0.1.0/tests/strategies/englyn.py +27 -0
- denckring-0.1.0/tests/strategies/eodermdrome.py +19 -0
- denckring-0.1.0/tests/strategies/epistrophe.py +22 -0
- denckring-0.1.0/tests/strategies/every_nth_word.py +19 -0
- denckring-0.1.0/tests/strategies/fold_in.py +59 -0
- denckring-0.1.0/tests/strategies/ghazal.py +30 -0
- denckring-0.1.0/tests/strategies/haibun.py +58 -0
- denckring-0.1.0/tests/strategies/haiku.py +22 -0
- denckring-0.1.0/tests/strategies/haikuization.py +31 -0
- denckring-0.1.0/tests/strategies/hemeling.py +41 -0
- denckring-0.1.0/tests/strategies/hendecasyllable.py +20 -0
- denckring-0.1.0/tests/strategies/heroic_couplet.py +30 -0
- denckring-0.1.0/tests/strategies/heterogram.py +19 -0
- denckring-0.1.0/tests/strategies/homoconsonantism.py +29 -0
- denckring-0.1.0/tests/strategies/homoteleuton.py +19 -0
- denckring-0.1.0/tests/strategies/homovocalism.py +30 -0
- denckring-0.1.0/tests/strategies/iambic_pentameter.py +27 -0
- denckring-0.1.0/tests/strategies/ideenwuerfeln.py +38 -0
- denckring-0.1.0/tests/strategies/kangaroo_word.py +19 -0
- denckring-0.1.0/tests/strategies/larding.py +40 -0
- denckring-0.1.0/tests/strategies/letter_bank.py +19 -0
- denckring-0.1.0/tests/strategies/limerick.py +32 -0
- denckring-0.1.0/tests/strategies/lipogram.py +20 -0
- denckring-0.1.0/tests/strategies/lipogrammatic_translation.py +25 -0
- denckring-0.1.0/tests/strategies/liponym.py +17 -0
- denckring-0.1.0/tests/strategies/llull_figure.py +25 -0
- denckring-0.1.0/tests/strategies/mathews_algorithm.py +51 -0
- denckring-0.1.0/tests/strategies/melting_text.py +19 -0
- denckring-0.1.0/tests/strategies/mesostic.py +31 -0
- denckring-0.1.0/tests/strategies/monoconsonantal.py +15 -0
- denckring-0.1.0/tests/strategies/monosyllabic_prose.py +16 -0
- denckring-0.1.0/tests/strategies/multiple_constraint.py +32 -0
- denckring-0.1.0/tests/strategies/n_plus_7.py +22 -0
- denckring-0.1.0/tests/strategies/ottava_rima.py +30 -0
- denckring-0.1.0/tests/strategies/palindrome.py +19 -0
- denckring-0.1.0/tests/strategies/pangram.py +17 -0
- denckring-0.1.0/tests/strategies/pangrammatic_lipogram.py +19 -0
- denckring-0.1.0/tests/strategies/pangrammatic_window.py +43 -0
- denckring-0.1.0/tests/strategies/pantoum.py +17 -0
- denckring-0.1.0/tests/strategies/paragram.py +44 -0
- denckring-0.1.0/tests/strategies/pasigraphy.py +50 -0
- denckring-0.1.0/tests/strategies/petrarchan_sonnet.py +42 -0
- denckring-0.1.0/tests/strategies/poesie_automat.py +31 -0
- denckring-0.1.0/tests/strategies/prisoners_constraint.py +18 -0
- denckring-0.1.0/tests/strategies/proteus_verse.py +42 -0
- denckring-0.1.0/tests/strategies/quenina.py +33 -0
- denckring-0.1.0/tests/strategies/recombination.py +25 -0
- denckring-0.1.0/tests/strategies/renga.py +58 -0
- denckring-0.1.0/tests/strategies/reverse_snowball.py +23 -0
- denckring-0.1.0/tests/strategies/rhyme_royal.py +33 -0
- denckring-0.1.0/tests/strategies/rhyme_scheme.py +30 -0
- denckring-0.1.0/tests/strategies/rondeau.py +42 -0
- denckring-0.1.0/tests/strategies/s_plus_7.py +22 -0
- denckring-0.1.0/tests/strategies/sapphic_stanza.py +48 -0
- denckring-0.1.0/tests/strategies/sator_square.py +19 -0
- denckring-0.1.0/tests/strategies/semordnilap.py +22 -0
- denckring-0.1.0/tests/strategies/senryu.py +22 -0
- denckring-0.1.0/tests/strategies/sentence_length_constraint.py +19 -0
- denckring-0.1.0/tests/strategies/serial_lipogram.py +52 -0
- denckring-0.1.0/tests/strategies/sestina.py +34 -0
- denckring-0.1.0/tests/strategies/shakespearean_sonnet.py +42 -0
- denckring-0.1.0/tests/strategies/single_sentence.py +15 -0
- denckring-0.1.0/tests/strategies/slenderizing.py +15 -0
- denckring-0.1.0/tests/strategies/snowball.py +23 -0
- denckring-0.1.0/tests/strategies/snowball_sentence.py +29 -0
- denckring-0.1.0/tests/strategies/sonnet.py +36 -0
- denckring-0.1.0/tests/strategies/spenserian_stanza.py +32 -0
- denckring-0.1.0/tests/strategies/spoonerism.py +25 -0
- denckring-0.1.0/tests/strategies/supervocalic.py +15 -0
- denckring-0.1.0/tests/strategies/syllable_count.py +31 -0
- denckring-0.1.0/tests/strategies/tanka.py +22 -0
- denckring-0.1.0/tests/strategies/tautogram.py +20 -0
- denckring-0.1.0/tests/strategies/tautonym.py +17 -0
- denckring-0.1.0/tests/strategies/telestich.py +25 -0
- denckring-0.1.0/tests/strategies/terza_rima.py +32 -0
- denckring-0.1.0/tests/strategies/text_folding.py +41 -0
- denckring-0.1.0/tests/strategies/tmesis.py +25 -0
- denckring-0.1.0/tests/strategies/transposal.py +19 -0
- denckring-0.1.0/tests/strategies/triolet.py +38 -0
- denckring-0.1.0/tests/strategies/trochaic_tetrameter.py +25 -0
- denckring-0.1.0/tests/strategies/univocalic.py +19 -0
- denckring-0.1.0/tests/strategies/univocalic_translation.py +24 -0
- denckring-0.1.0/tests/strategies/villanelle.py +47 -0
- denckring-0.1.0/tests/strategies/wechselsatz.py +25 -0
- denckring-0.1.0/tests/strategies/word_ladder.py +24 -0
- denckring-0.1.0/tests/strategies/word_square.py +30 -0
- denckring-0.1.0/tests/test_abecedarian.py +23 -0
- denckring-0.1.0/tests/test_acrostic.py +42 -0
- denckring-0.1.0/tests/test_alcaic_stanza.py +24 -0
- denckring-0.1.0/tests/test_alexandrine.py +25 -0
- denckring-0.1.0/tests/test_alphabetical_sentence.py +19 -0
- denckring-0.1.0/tests/test_anagram.py +176 -0
- denckring-0.1.0/tests/test_anaphora.py +19 -0
- denckring-0.1.0/tests/test_antigram.py +11 -0
- denckring-0.1.0/tests/test_apply_requires.py +66 -0
- denckring-0.1.0/tests/test_apply_spine.py +315 -0
- denckring-0.1.0/tests/test_arca_musarithmica.py +107 -0
- denckring-0.1.0/tests/test_beau_present.py +24 -0
- denckring-0.1.0/tests/test_belle_absente.py +61 -0
- denckring-0.1.0/tests/test_bivocalic.py +18 -0
- denckring-0.1.0/tests/test_blank_verse.py +24 -0
- denckring-0.1.0/tests/test_buchstabwechsel.py +126 -0
- denckring-0.1.0/tests/test_calculator_corpus.py +70 -0
- denckring-0.1.0/tests/test_calculator_display.py +58 -0
- denckring-0.1.0/tests/test_calculator_word.py +174 -0
- denckring-0.1.0/tests/test_capabilities.py +30 -0
- denckring-0.1.0/tests/test_catalogue.py +36 -0
- denckring-0.1.0/tests/test_catalogue_corrections.py +111 -0
- denckring-0.1.0/tests/test_catalogue_export.py +48 -0
- denckring-0.1.0/tests/test_catalogue_quality.py +95 -0
- denckring-0.1.0/tests/test_cent_mille_milliards.py +25 -0
- denckring-0.1.0/tests/test_charade.py +19 -0
- denckring-0.1.0/tests/test_chronogram.py +21 -0
- denckring-0.1.0/tests/test_cinquain.py +22 -0
- denckring-0.1.0/tests/test_cli.py +153 -0
- denckring-0.1.0/tests/test_cli_json.py +51 -0
- denckring-0.1.0/tests/test_cli_search.py +36 -0
- denckring-0.1.0/tests/test_composites.py +205 -0
- denckring-0.1.0/tests/test_consonantal_lipogram.py +15 -0
- denckring-0.1.0/tests/test_constraint_translations.py +87 -0
- denckring-0.1.0/tests/test_constructive_truth.py +43 -0
- denckring-0.1.0/tests/test_corpus.py +58 -0
- denckring-0.1.0/tests/test_cut_up.py +24 -0
- denckring-0.1.0/tests/test_dactylic_hexameter.py +55 -0
- denckring-0.1.0/tests/test_de_frequency_build.py +77 -0
- denckring-0.1.0/tests/test_de_frequency_corpus.py +68 -0
- denckring-0.1.0/tests/test_de_frequency_pack.py +58 -0
- denckring-0.1.0/tests/test_definitional.py +136 -0
- denckring-0.1.0/tests/test_denckring.py +135 -0
- denckring-0.1.0/tests/test_describe.py +136 -0
- denckring-0.1.0/tests/test_device.py +445 -0
- denckring-0.1.0/tests/test_device_address.py +238 -0
- denckring-0.1.0/tests/test_device_from_text.py +114 -0
- denckring-0.1.0/tests/test_disclosure.py +91 -0
- denckring-0.1.0/tests/test_double_acrostic.py +24 -0
- denckring-0.1.0/tests/test_double_dactyl.py +26 -0
- denckring-0.1.0/tests/test_elegiac_couplet.py +26 -0
- denckring-0.1.0/tests/test_elision_fr.py +140 -0
- denckring-0.1.0/tests/test_elision_seam.py +119 -0
- denckring-0.1.0/tests/test_eodermdrome.py +20 -0
- denckring-0.1.0/tests/test_epistrophe.py +15 -0
- denckring-0.1.0/tests/test_error_codes.py +167 -0
- denckring-0.1.0/tests/test_errors.py +103 -0
- denckring-0.1.0/tests/test_every_nth_word.py +19 -0
- denckring-0.1.0/tests/test_fold_param.py +23 -0
- denckring-0.1.0/tests/test_fold_symmetry.py +86 -0
- denckring-0.1.0/tests/test_folding_seam.py +192 -0
- denckring-0.1.0/tests/test_generators.py +154 -0
- denckring-0.1.0/tests/test_gloss_catalogue_corrections.py +37 -0
- denckring-0.1.0/tests/test_glosses.py +50 -0
- denckring-0.1.0/tests/test_golden.py +25 -0
- denckring-0.1.0/tests/test_haibun.py +47 -0
- denckring-0.1.0/tests/test_haiku.py +24 -0
- denckring-0.1.0/tests/test_harness.py +34 -0
- denckring-0.1.0/tests/test_hemeling.py +81 -0
- denckring-0.1.0/tests/test_hendecasyllable.py +10 -0
- denckring-0.1.0/tests/test_heroic_couplet.py +24 -0
- denckring-0.1.0/tests/test_heterogram.py +20 -0
- denckring-0.1.0/tests/test_homoteleuton.py +19 -0
- denckring-0.1.0/tests/test_iambic_pentameter.py +21 -0
- denckring-0.1.0/tests/test_ideenwuerfeln.py +139 -0
- denckring-0.1.0/tests/test_identical_rhyme_elision.py +55 -0
- denckring-0.1.0/tests/test_input_adequacy.py +162 -0
- denckring-0.1.0/tests/test_instruction_rules.py +95 -0
- denckring-0.1.0/tests/test_invariants.py +114 -0
- denckring-0.1.0/tests/test_kangaroo_word.py +38 -0
- denckring-0.1.0/tests/test_kangaroo_word_folding.py +37 -0
- denckring-0.1.0/tests/test_lang_de.py +52 -0
- denckring-0.1.0/tests/test_lang_de_data.py +195 -0
- denckring-0.1.0/tests/test_lang_de_wiktionary.py +227 -0
- denckring-0.1.0/tests/test_lang_discovery.py +62 -0
- denckring-0.1.0/tests/test_lang_en.py +45 -0
- denckring-0.1.0/tests/test_lang_en_data.py +99 -0
- denckring-0.1.0/tests/test_lang_fr.py +68 -0
- denckring-0.1.0/tests/test_lang_fr_data.py +350 -0
- denckring-0.1.0/tests/test_layers.py +81 -0
- denckring-0.1.0/tests/test_letter_bank.py +25 -0
- denckring-0.1.0/tests/test_letter_class.py +30 -0
- denckring-0.1.0/tests/test_limerick.py +26 -0
- denckring-0.1.0/tests/test_line_sound.py +47 -0
- denckring-0.1.0/tests/test_line_syllables.py +53 -0
- denckring-0.1.0/tests/test_lipogram.py +40 -0
- denckring-0.1.0/tests/test_liponym.py +19 -0
- denckring-0.1.0/tests/test_llull_figure.py +87 -0
- denckring-0.1.0/tests/test_mcp_tools.py +172 -0
- denckring-0.1.0/tests/test_melting_text.py +14 -0
- denckring-0.1.0/tests/test_monoconsonantal.py +18 -0
- denckring-0.1.0/tests/test_monosyllabic_prose.py +15 -0
- denckring-0.1.0/tests/test_n_plus_7.py +161 -0
- denckring-0.1.0/tests/test_non_degeneracy.py +137 -0
- denckring-0.1.0/tests/test_package.py +5 -0
- denckring-0.1.0/tests/test_packaging.py +187 -0
- denckring-0.1.0/tests/test_palindrome.py +22 -0
- denckring-0.1.0/tests/test_pangram.py +25 -0
- denckring-0.1.0/tests/test_pangrammatic_lipogram.py +23 -0
- denckring-0.1.0/tests/test_pangrammatic_window.py +76 -0
- denckring-0.1.0/tests/test_pantoum.py +15 -0
- denckring-0.1.0/tests/test_paragram.py +212 -0
- denckring-0.1.0/tests/test_pasigraphy.py +105 -0
- denckring-0.1.0/tests/test_petrarchan_sonnet.py +36 -0
- denckring-0.1.0/tests/test_poesie_automat.py +454 -0
- denckring-0.1.0/tests/test_prisoners_constraint.py +36 -0
- denckring-0.1.0/tests/test_production.py +244 -0
- denckring-0.1.0/tests/test_prosody.py +232 -0
- denckring-0.1.0/tests/test_prosody_robustness.py +182 -0
- denckring-0.1.0/tests/test_proteus_verse.py +138 -0
- denckring-0.1.0/tests/test_protocol.py +38 -0
- denckring-0.1.0/tests/test_published_docs.py +161 -0
- denckring-0.1.0/tests/test_quenina.py +67 -0
- denckring-0.1.0/tests/test_reading_boundary.py +56 -0
- denckring-0.1.0/tests/test_readme.py +132 -0
- denckring-0.1.0/tests/test_rearrangement.py +64 -0
- denckring-0.1.0/tests/test_rearrangement_remainder.py +91 -0
- denckring-0.1.0/tests/test_recombination.py +56 -0
- denckring-0.1.0/tests/test_registry.py +44 -0
- denckring-0.1.0/tests/test_renga.py +63 -0
- denckring-0.1.0/tests/test_repeating_forms.py +59 -0
- denckring-0.1.0/tests/test_requires_honesty.py +390 -0
- denckring-0.1.0/tests/test_reverse_snowball.py +11 -0
- denckring-0.1.0/tests/test_rhyme_royal.py +27 -0
- denckring-0.1.0/tests/test_rhyme_scheme.py +24 -0
- denckring-0.1.0/tests/test_round_trip.py +449 -0
- denckring-0.1.0/tests/test_s_plus_7.py +30 -0
- denckring-0.1.0/tests/test_sampa_fr.py +71 -0
- denckring-0.1.0/tests/test_sapphic_stanza.py +21 -0
- denckring-0.1.0/tests/test_sator_square.py +21 -0
- denckring-0.1.0/tests/test_scaffold.py +46 -0
- denckring-0.1.0/tests/test_selection.py +81 -0
- denckring-0.1.0/tests/test_selection_remainder.py +70 -0
- denckring-0.1.0/tests/test_semordnilap.py +21 -0
- denckring-0.1.0/tests/test_senryu.py +14 -0
- denckring-0.1.0/tests/test_sentence_length_constraint.py +20 -0
- denckring-0.1.0/tests/test_serial_lipogram.py +104 -0
- denckring-0.1.0/tests/test_sestina.py +47 -0
- denckring-0.1.0/tests/test_shakespearean_sonnet.py +36 -0
- denckring-0.1.0/tests/test_short_forms.py +46 -0
- denckring-0.1.0/tests/test_single_sentence.py +19 -0
- denckring-0.1.0/tests/test_slenderizing.py +125 -0
- denckring-0.1.0/tests/test_snowball.py +27 -0
- denckring-0.1.0/tests/test_snowball_sentence.py +14 -0
- denckring-0.1.0/tests/test_sonnet.py +47 -0
- denckring-0.1.0/tests/test_source_param.py +37 -0
- denckring-0.1.0/tests/test_stanzaic_forms.py +102 -0
- denckring-0.1.0/tests/test_strategies.py +39 -0
- denckring-0.1.0/tests/test_supervocalic.py +21 -0
- denckring-0.1.0/tests/test_syllable_count.py +14 -0
- denckring-0.1.0/tests/test_syllables.py +75 -0
- denckring-0.1.0/tests/test_syllables_de.py +71 -0
- denckring-0.1.0/tests/test_tanka.py +20 -0
- denckring-0.1.0/tests/test_tautogram.py +24 -0
- denckring-0.1.0/tests/test_tautonym.py +15 -0
- denckring-0.1.0/tests/test_telestich.py +9 -0
- denckring-0.1.0/tests/test_terza_rima.py +26 -0
- denckring-0.1.0/tests/test_text.py +66 -0
- denckring-0.1.0/tests/test_text_helpers.py +74 -0
- denckring-0.1.0/tests/test_transposal.py +16 -0
- denckring-0.1.0/tests/test_triolet.py +32 -0
- denckring-0.1.0/tests/test_trochaic_tetrameter.py +19 -0
- denckring-0.1.0/tests/test_univocalic.py +24 -0
- denckring-0.1.0/tests/test_villanelle.py +41 -0
- denckring-0.1.0/tests/test_vowel_inventory.py +70 -0
- denckring-0.1.0/tests/test_wechselsatz.py +18 -0
- denckring-0.1.0/tests/test_word_ladder.py +111 -0
- denckring-0.1.0/tests/test_word_square.py +28 -0
- denckring-0.1.0/tests/test_word_surgery.py +130 -0
- denckring-0.1.0/uv.lock +2105 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: A procedure gives the wrong answer, or something crashes
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
If a procedure disagrees with a literary authority about what a form requires,
|
|
9
|
+
that is a bug — please say which authority.
|
|
10
|
+
- type: input
|
|
11
|
+
id: procedure
|
|
12
|
+
attributes:
|
|
13
|
+
label: Procedure
|
|
14
|
+
placeholder: lipogram
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: reproduce
|
|
19
|
+
attributes:
|
|
20
|
+
label: What you ran
|
|
21
|
+
description: The command or the `check(...)` call, with the text and parameters.
|
|
22
|
+
render: python
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: expected
|
|
27
|
+
attributes:
|
|
28
|
+
label: What you expected, and what happened
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
- type: input
|
|
32
|
+
id: version
|
|
33
|
+
attributes:
|
|
34
|
+
label: Version
|
|
35
|
+
description: "`denckring --version`, and whether `denckring[en]` is installed."
|
|
36
|
+
validations:
|
|
37
|
+
required: true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: New procedure
|
|
2
|
+
description: Propose a writing procedure for the catalogue
|
|
3
|
+
labels: [catalogue]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
The catalogue's value is that its entries are sourced. An entry with no source
|
|
9
|
+
is not one we can add.
|
|
10
|
+
- type: input
|
|
11
|
+
id: name
|
|
12
|
+
attributes:
|
|
13
|
+
label: Name of the procedure
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: definition
|
|
18
|
+
attributes:
|
|
19
|
+
label: Definition
|
|
20
|
+
description: One or two sentences. What must a text do to satisfy it?
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
- type: input
|
|
24
|
+
id: source
|
|
25
|
+
attributes:
|
|
26
|
+
label: Source
|
|
27
|
+
description: "Author, work and year, or the reference work that documents it."
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
- type: dropdown
|
|
31
|
+
id: attribution
|
|
32
|
+
attributes:
|
|
33
|
+
label: How is that source established?
|
|
34
|
+
options:
|
|
35
|
+
- primary — a named author, work and year
|
|
36
|
+
- reference — attested in a standard reference, origin not traced
|
|
37
|
+
- traditional — classical or folk, no single origin
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
- type: dropdown
|
|
41
|
+
id: checkability
|
|
42
|
+
attributes:
|
|
43
|
+
label: Can a program decide it?
|
|
44
|
+
options:
|
|
45
|
+
- self — from the text and its parameters alone
|
|
46
|
+
- source — only against the text it was made from
|
|
47
|
+
- none — no computable acceptance criterion exists
|
|
48
|
+
validations:
|
|
49
|
+
required: true
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
# Each ecosystem opens ONE grouped pull request, not one per dependency.
|
|
4
|
+
#
|
|
5
|
+
# `ci.yml` is 9 jobs of which `test` is a 13-cell matrix, so every run is 21
|
|
6
|
+
# runner-jobs — 13 Linux, 4 Windows, 4 macOS — and `pull_request` fires the whole
|
|
7
|
+
# thing. Against a private repo's included minutes, where Windows counts double
|
|
8
|
+
# and macOS tenfold, that is roughly 280 billable minutes per run, about 71% of
|
|
9
|
+
# it macOS.
|
|
10
|
+
#
|
|
11
|
+
# Ungrouped, the default limit of five open PRs per ecosystem means up to ten
|
|
12
|
+
# runs a month from Dependabot alone, ~2,800 minutes, which exceeds the whole
|
|
13
|
+
# monthly allowance before any human pushes anything. That is not a projection:
|
|
14
|
+
# on 2026-08-30 the first push opened eight PRs at once and the nine resulting
|
|
15
|
+
# runs exhausted the quota, failing every job except `core-only`.
|
|
16
|
+
#
|
|
17
|
+
# Grouping costs bisectability — a red grouped PR does not say which member
|
|
18
|
+
# broke it — which is why the two ecosystems stay in separate groups rather than
|
|
19
|
+
# one. A lockfile bump and an Actions bump fail for entirely different reasons.
|
|
20
|
+
updates:
|
|
21
|
+
- package-ecosystem: github-actions
|
|
22
|
+
directory: "/"
|
|
23
|
+
schedule:
|
|
24
|
+
interval: monthly
|
|
25
|
+
commit-message:
|
|
26
|
+
prefix: "chore"
|
|
27
|
+
groups:
|
|
28
|
+
github-actions:
|
|
29
|
+
patterns: ["*"]
|
|
30
|
+
|
|
31
|
+
- package-ecosystem: uv
|
|
32
|
+
directory: "/"
|
|
33
|
+
schedule:
|
|
34
|
+
interval: monthly
|
|
35
|
+
commit-message:
|
|
36
|
+
prefix: "chore"
|
|
37
|
+
groups:
|
|
38
|
+
python-packages:
|
|
39
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `uv run pytest` passes
|
|
8
|
+
- [ ] `uv run ruff check` and `uv run ruff format --check` pass
|
|
9
|
+
- [ ] `uv run mypy --strict src tests packages/denckring-en-data/src` passes
|
|
10
|
+
- [ ] `uv run denckring eval --all` is green
|
|
11
|
+
|
|
12
|
+
If this adds a procedure:
|
|
13
|
+
|
|
14
|
+
- [ ] One module, named for the procedure id
|
|
15
|
+
- [ ] A catalogue row with a real source, an `attribution` and a `checkability`
|
|
16
|
+
- [ ] Golden fixtures: at least one genuine instance and one counterexample
|
|
17
|
+
- [ ] Hypothesis strategies under `tests/strategies/`
|
|
18
|
+
- [ ] The catalogue definition claims no more than the checker verifies
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
env:
|
|
13
|
+
UV_FROZEN: "1"
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: astral-sh/setup-uv@v5
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr
|
|
24
|
+
- run: uv run ruff check
|
|
25
|
+
- run: uv run ruff format --check
|
|
26
|
+
|
|
27
|
+
typecheck:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- uses: astral-sh/setup-uv@v5
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr --extra mcp
|
|
35
|
+
- run: >-
|
|
36
|
+
uv run mypy --strict src tests packages/denckring-en-data/src
|
|
37
|
+
packages/denckring-de-data/src packages/denckring-de-wiktionary/src
|
|
38
|
+
packages/denckring-de-frequency/src
|
|
39
|
+
|
|
40
|
+
test:
|
|
41
|
+
strategy:
|
|
42
|
+
fail-fast: false
|
|
43
|
+
matrix:
|
|
44
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
45
|
+
python: ["3.11", "3.12", "3.13", "3.14"]
|
|
46
|
+
include:
|
|
47
|
+
# The free-threaded build, on one platform. Nothing here holds a lock
|
|
48
|
+
# or touches a C extension, so the claim costs one job to keep honest
|
|
49
|
+
# — and an unverified claim is worse than none.
|
|
50
|
+
- os: ubuntu-latest
|
|
51
|
+
python: "3.14t"
|
|
52
|
+
runs-on: ${{ matrix.os }}
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
- uses: astral-sh/setup-uv@v5
|
|
56
|
+
with:
|
|
57
|
+
enable-cache: true
|
|
58
|
+
python-version: ${{ matrix.python }}
|
|
59
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr
|
|
60
|
+
- run: uv run pytest -q
|
|
61
|
+
|
|
62
|
+
coverage:
|
|
63
|
+
# A floor, not a report. The README's badge states the same 97 this job
|
|
64
|
+
# enforces, so the badge cannot go stale upward-or-downward without CI
|
|
65
|
+
# going red — which is the only way a number in prose stays true here.
|
|
66
|
+
#
|
|
67
|
+
# Measured 97.1% on 2026-09-05: 6,015 of 6,194 statements. The margin over
|
|
68
|
+
# the floor is about seven statements, and hypothesis moves the last one or
|
|
69
|
+
# two between runs, so a drop that turns this red is a real drop. Raising
|
|
70
|
+
# the floor means raising the badge in the same commit.
|
|
71
|
+
#
|
|
72
|
+
# `--extra mcp` because the matrix runs without it and `pytest.importorskip`
|
|
73
|
+
# then skips every MCP test: measuring the suite that skips them would
|
|
74
|
+
# report `mcp/server.py` as uncovered code nobody had chosen not to cover.
|
|
75
|
+
#
|
|
76
|
+
# Scoped to `denckring` alone. The workspace data packages are vendored
|
|
77
|
+
# tables with a few lines of accessor each, and folding them in would move
|
|
78
|
+
# the figure without saying anything about the library.
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
- uses: astral-sh/setup-uv@v5
|
|
83
|
+
with:
|
|
84
|
+
enable-cache: true
|
|
85
|
+
- run: >-
|
|
86
|
+
uv sync --extra en --extra de --extra de-wiktionary
|
|
87
|
+
--extra de-frequency --extra fr --extra mcp
|
|
88
|
+
- run: uv run pytest -q --cov=denckring --cov-report=term-missing --cov-fail-under=97
|
|
89
|
+
|
|
90
|
+
eval:
|
|
91
|
+
# The acceptance criterion the project set itself for unattended runs. A
|
|
92
|
+
# passing test suite is a different claim from a green scoreboard, so this
|
|
93
|
+
# is a gate of its own.
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
steps:
|
|
96
|
+
- uses: actions/checkout@v4
|
|
97
|
+
- uses: astral-sh/setup-uv@v5
|
|
98
|
+
with:
|
|
99
|
+
enable-cache: true
|
|
100
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr
|
|
101
|
+
- run: uv run denckring eval --all
|
|
102
|
+
- run: uv run denckring status
|
|
103
|
+
|
|
104
|
+
mcp:
|
|
105
|
+
# The matrix runs without [mcp], so `pytest.importorskip` skips every MCP
|
|
106
|
+
# test there — the extra's own code would otherwise be tested nowhere. One
|
|
107
|
+
# job installs it and runs them for real. A skipped test reports green.
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/checkout@v4
|
|
111
|
+
- uses: astral-sh/setup-uv@v5
|
|
112
|
+
with:
|
|
113
|
+
enable-cache: true
|
|
114
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr --extra mcp
|
|
115
|
+
- run: uv run pytest tests/test_mcp_tools.py -q
|
|
116
|
+
- name: The server starts and lists its four tools
|
|
117
|
+
run: |
|
|
118
|
+
uv run python -c "
|
|
119
|
+
import asyncio
|
|
120
|
+
from denckring.mcp.server import server
|
|
121
|
+
names = {t.name for t in asyncio.run(server.list_tools())}
|
|
122
|
+
assert names == {'list_procedures', 'describe_procedure', 'check_text', 'apply_procedure'}, names
|
|
123
|
+
print('mcp:', sorted(names))
|
|
124
|
+
"
|
|
125
|
+
|
|
126
|
+
core-only:
|
|
127
|
+
# Nothing else exercises the install without the data package, and that is
|
|
128
|
+
# the path most likely to break silently: a procedure quietly requiring a
|
|
129
|
+
# capability core does not have would pass every other job here.
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
- uses: astral-sh/setup-uv@v5
|
|
134
|
+
with:
|
|
135
|
+
enable-cache: true
|
|
136
|
+
- name: Install the core distribution alone
|
|
137
|
+
run: |
|
|
138
|
+
uv venv /tmp/core-only
|
|
139
|
+
VIRTUAL_ENV=/tmp/core-only uv pip install .
|
|
140
|
+
- name: The data-free procedures work
|
|
141
|
+
run: |
|
|
142
|
+
/tmp/core-only/bin/python -c "
|
|
143
|
+
from denckring import check
|
|
144
|
+
assert check('lipogram', 'aaa', forbidden='z').satisfied
|
|
145
|
+
assert check('pangram', 'Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich', lang='de').satisfied
|
|
146
|
+
print('core-only: data-free procedures OK')
|
|
147
|
+
"
|
|
148
|
+
- name: The data-dependent ones raise, naming the extra
|
|
149
|
+
run: |
|
|
150
|
+
/tmp/core-only/bin/python -c "
|
|
151
|
+
from denckring import check
|
|
152
|
+
from denckring.core.errors import MissingCapability
|
|
153
|
+
try:
|
|
154
|
+
check('iambic_pentameter', 'the cat can see the moon above the tree')
|
|
155
|
+
except MissingCapability as exc:
|
|
156
|
+
print('core-only: raised as expected —', exc)
|
|
157
|
+
else:
|
|
158
|
+
raise SystemExit('iambic_pentameter should require a capability core lacks')
|
|
159
|
+
"
|
|
160
|
+
|
|
161
|
+
german-without-pronunciations:
|
|
162
|
+
# `denckring[de]` is two distributions and either may be installed alone, so
|
|
163
|
+
# the lexical-only install is a real shape a user can have. ADR 0030 puts the
|
|
164
|
+
# choice between the two packs in one factory; this is the job that proves the
|
|
165
|
+
# factory picks the lexical one and that a phonetic row then refuses rather
|
|
166
|
+
# than guessing. Nothing in the suite covers it, because the suite runs with
|
|
167
|
+
# both installed.
|
|
168
|
+
runs-on: ubuntu-latest
|
|
169
|
+
steps:
|
|
170
|
+
- uses: actions/checkout@v4
|
|
171
|
+
- uses: astral-sh/setup-uv@v5
|
|
172
|
+
with:
|
|
173
|
+
enable-cache: true
|
|
174
|
+
- name: Install the lexical German data and not the phonetic
|
|
175
|
+
run: |
|
|
176
|
+
uv venv /tmp/de-lexical
|
|
177
|
+
VIRTUAL_ENV=/tmp/de-lexical uv pip install ".[de]"
|
|
178
|
+
- name: The lexical rows work and the phonetic ones name what is missing
|
|
179
|
+
run: |
|
|
180
|
+
/tmp/de-lexical/bin/python -c "
|
|
181
|
+
from denckring import check
|
|
182
|
+
from denckring.core.errors import MissingCapability
|
|
183
|
+
from denckring.lang import get_pack
|
|
184
|
+
pack = get_pack('de')
|
|
185
|
+
assert type(pack).__name__ == 'GermanDataPack', type(pack).__name__
|
|
186
|
+
assert check('charade', 'Tal', lang='de').satisfied is not None
|
|
187
|
+
try:
|
|
188
|
+
check('iambic_pentameter', 'der Wind bewegt die Blätter in der Nacht', lang='de')
|
|
189
|
+
except MissingCapability as exc:
|
|
190
|
+
assert 'stress' in str(exc), exc
|
|
191
|
+
print('de-lexical: raised as expected —', exc)
|
|
192
|
+
else:
|
|
193
|
+
raise SystemExit('iambic_pentameter needs stress, which this install lacks')
|
|
194
|
+
"
|
|
195
|
+
|
|
196
|
+
french-without-data:
|
|
197
|
+
# French ships in core with no data at all, which is a real install shape and
|
|
198
|
+
# the one the suite never runs: it always has `denckring[fr]`. ADR 0034 leaves
|
|
199
|
+
# 18 rows blocked in French — down from ADR 0032's 41, and all of them on
|
|
200
|
+
# `stress` — so every row this job exercises is one `denckring[fr]` unblocks,
|
|
201
|
+
# and each must refuse by naming what is missing rather than guessing.
|
|
202
|
+
#
|
|
203
|
+
# The `phonemes` assertion below has no other home. ADR 0034 gave French
|
|
204
|
+
# `phonemes`, so no installed pack lacks that capability any more, and
|
|
205
|
+
# `tests/test_prosody_robustness.py` had to move its refusal test to `stress`.
|
|
206
|
+
# A core-only install is now the only place a phonemes refusal runs at all.
|
|
207
|
+
runs-on: ubuntu-latest
|
|
208
|
+
steps:
|
|
209
|
+
- uses: actions/checkout@v4
|
|
210
|
+
- uses: astral-sh/setup-uv@v5
|
|
211
|
+
with:
|
|
212
|
+
enable-cache: true
|
|
213
|
+
- name: Install the core distribution alone
|
|
214
|
+
run: |
|
|
215
|
+
uv venv /tmp/fr-core
|
|
216
|
+
VIRTUAL_ENV=/tmp/fr-core uv pip install .
|
|
217
|
+
- name: The data-free French rows work and the data-fed ones name what is missing
|
|
218
|
+
run: |
|
|
219
|
+
/tmp/fr-core/bin/python -c "
|
|
220
|
+
from denckring import check
|
|
221
|
+
from denckring.core.errors import MissingCapability
|
|
222
|
+
assert check('lipogram', 'aaa', forbidden='z', lang='fr').satisfied
|
|
223
|
+
try:
|
|
224
|
+
check('n_plus_7', 'la maison', lang='fr')
|
|
225
|
+
except MissingCapability as exc:
|
|
226
|
+
assert 'lexicon.nouns' in str(exc), exc
|
|
227
|
+
print('fr-core: lexical row raised as expected —', exc)
|
|
228
|
+
else:
|
|
229
|
+
raise SystemExit('n_plus_7 needs lexicon.nouns, which this install lacks')
|
|
230
|
+
try:
|
|
231
|
+
check('alexandrine', 'le temps n\'est plus', lang='fr')
|
|
232
|
+
except MissingCapability as exc:
|
|
233
|
+
assert 'syllables' in str(exc), exc
|
|
234
|
+
print('fr-core: syllabic row raised as expected —', exc)
|
|
235
|
+
else:
|
|
236
|
+
raise SystemExit('alexandrine needs syllables, which this install lacks')
|
|
237
|
+
try:
|
|
238
|
+
check('rhyme_scheme', 'le chat dort\nle chien court', scheme='AA', lang='fr')
|
|
239
|
+
except MissingCapability as exc:
|
|
240
|
+
assert 'phonemes' in str(exc), exc
|
|
241
|
+
print('fr-core: rhyme row raised as expected —', exc)
|
|
242
|
+
else:
|
|
243
|
+
raise SystemExit('rhyme_scheme needs phonemes, which this install lacks')
|
|
244
|
+
"
|
|
245
|
+
|
|
246
|
+
docs:
|
|
247
|
+
runs-on: ubuntu-latest
|
|
248
|
+
steps:
|
|
249
|
+
- uses: actions/checkout@v4
|
|
250
|
+
- uses: astral-sh/setup-uv@v5
|
|
251
|
+
with:
|
|
252
|
+
enable-cache: true
|
|
253
|
+
- run: uv sync --extra en --extra de --extra de-wiktionary --extra de-frequency --extra fr
|
|
254
|
+
- name: Regenerate the gallery
|
|
255
|
+
run: uv run python scripts/build_docs.py
|
|
256
|
+
- name: Build the site
|
|
257
|
+
run: uv run mkdocs build --strict
|
|
258
|
+
|
|
259
|
+
explorer:
|
|
260
|
+
# A development tool, but a tested one: its own suite, which no other job in
|
|
261
|
+
# this workflow collects and which has never run in CI before this job.
|
|
262
|
+
runs-on: ubuntu-latest
|
|
263
|
+
defaults:
|
|
264
|
+
run:
|
|
265
|
+
# uv run --project apps/explorer still executes with the repo root as
|
|
266
|
+
# cwd, so pytest's rootdir search finds this repo's own testpaths
|
|
267
|
+
# config and collects ../../tests instead. Running inside the app's
|
|
268
|
+
# directory is what actually resolves its test paths.
|
|
269
|
+
working-directory: apps/explorer
|
|
270
|
+
steps:
|
|
271
|
+
- uses: actions/checkout@v4
|
|
272
|
+
- uses: astral-sh/setup-uv@v5
|
|
273
|
+
with:
|
|
274
|
+
enable-cache: true
|
|
275
|
+
- run: uv sync
|
|
276
|
+
- run: uv run ruff check
|
|
277
|
+
- run: uv run ruff format --check
|
|
278
|
+
- run: uv run mypy --strict src tests
|
|
279
|
+
- run: uv run pytest -q
|
|
280
|
+
|
|
281
|
+
build:
|
|
282
|
+
runs-on: ubuntu-latest
|
|
283
|
+
steps:
|
|
284
|
+
- uses: actions/checkout@v4
|
|
285
|
+
- uses: astral-sh/setup-uv@v5
|
|
286
|
+
with:
|
|
287
|
+
enable-cache: true
|
|
288
|
+
- run: uv build --all-packages
|
|
289
|
+
- run: uvx twine check dist/*
|
|
290
|
+
- uses: actions/upload-artifact@v4
|
|
291
|
+
with:
|
|
292
|
+
name: distributions
|
|
293
|
+
path: dist/
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Two entry points, and the second one is why this file changed before the first
|
|
4
|
+
# release rather than after it.
|
|
5
|
+
#
|
|
6
|
+
# A `v*` tag publishes to PyPI for real. `workflow_dispatch` publishes to TestPyPI
|
|
7
|
+
# instead, so the whole path — build, check, upload through Trusted Publishing —
|
|
8
|
+
# can be walked once against a registry where a mistake is recoverable. PyPI
|
|
9
|
+
# refuses a re-upload of a version that already exists, so without a rehearsal the
|
|
10
|
+
# first genuine tag is also the first time this workflow has ever run end to end.
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
tags: ["v*"]
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
inputs:
|
|
16
|
+
target:
|
|
17
|
+
description: Which index to publish to.
|
|
18
|
+
type: choice
|
|
19
|
+
default: testpypi
|
|
20
|
+
options: [testpypi, none]
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: astral-sh/setup-uv@v5
|
|
28
|
+
with:
|
|
29
|
+
enable-cache: true
|
|
30
|
+
- run: uv build --all-packages
|
|
31
|
+
- run: uvx twine check dist/*
|
|
32
|
+
- uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: distributions
|
|
35
|
+
path: dist/
|
|
36
|
+
|
|
37
|
+
# Before `publish`, not after it. This used to run last, so a docs failure left
|
|
38
|
+
# the release on PyPI and undocumented — and unrecoverable, because PyPI will not
|
|
39
|
+
# take the version again. It also fails outright on a private repository, where
|
|
40
|
+
# `gh-deploy` needs a paid plan, which meant the old order guaranteed that the
|
|
41
|
+
# first release would publish and then go red.
|
|
42
|
+
docs:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
permissions:
|
|
45
|
+
contents: write
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
- uses: astral-sh/setup-uv@v5
|
|
51
|
+
with:
|
|
52
|
+
enable-cache: true
|
|
53
|
+
- run: uv sync --extra en
|
|
54
|
+
- run: uv run python scripts/build_docs.py
|
|
55
|
+
# A dispatch run rehearses the site build without deploying it: a rehearsal
|
|
56
|
+
# that pushed to gh-pages would not be a rehearsal.
|
|
57
|
+
- if: github.event_name == 'workflow_dispatch'
|
|
58
|
+
run: uv run mkdocs build --strict
|
|
59
|
+
- if: github.event_name == 'push'
|
|
60
|
+
run: uv run mkdocs gh-deploy --force --strict
|
|
61
|
+
|
|
62
|
+
rehearse:
|
|
63
|
+
# TestPyPI, from a manual run. One leg per distribution, for the reason the
|
|
64
|
+
# `publish` matrix below spells out.
|
|
65
|
+
if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
66
|
+
needs: [build, docs]
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
strategy:
|
|
69
|
+
# Every leg is independent and each says something different: stopping the
|
|
70
|
+
# others on the first failure would hide which of the six are misconfigured,
|
|
71
|
+
# which is the whole question a rehearsal answers.
|
|
72
|
+
fail-fast: false
|
|
73
|
+
matrix:
|
|
74
|
+
include:
|
|
75
|
+
- {dist: denckring, files: "denckring-", environment: testpypi}
|
|
76
|
+
- {dist: denckring-en-data, files: "denckring_en_data-", environment: testpypi-en-data}
|
|
77
|
+
- {dist: denckring-de-data, files: "denckring_de_data-", environment: testpypi-de-data}
|
|
78
|
+
- {dist: denckring-de-wiktionary, files: "denckring_de_wiktionary-", environment: testpypi-de-wiktionary}
|
|
79
|
+
- {dist: denckring-de-frequency, files: "denckring_de_frequency-", environment: testpypi-de-frequency}
|
|
80
|
+
- {dist: denckring-fr-data, files: "denckring_fr_data-", environment: testpypi-fr-data}
|
|
81
|
+
environment: ${{ matrix.environment }}
|
|
82
|
+
permissions:
|
|
83
|
+
id-token: write
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/download-artifact@v4
|
|
86
|
+
with:
|
|
87
|
+
name: distributions
|
|
88
|
+
path: all-dist/
|
|
89
|
+
- name: Take only this distribution's artefacts
|
|
90
|
+
run: |
|
|
91
|
+
mkdir -p dist
|
|
92
|
+
cp all-dist/${{ matrix.files }}* dist/
|
|
93
|
+
# An empty or over-full `dist/` is the failure this split can produce and
|
|
94
|
+
# the one an upload would not report: publishing nothing succeeds. Exactly
|
|
95
|
+
# a wheel and an sdist, or stop.
|
|
96
|
+
count=$(ls dist | wc -l)
|
|
97
|
+
test "$count" -eq 2 || {
|
|
98
|
+
echo "expected 2 artefacts for ${{ matrix.dist }}, found $count"; ls -l dist; exit 1;
|
|
99
|
+
}
|
|
100
|
+
ls -l dist
|
|
101
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
102
|
+
with:
|
|
103
|
+
repository-url: https://test.pypi.org/legacy/
|
|
104
|
+
# Off here and on for the real thing: TestPyPI is periodically pruned,
|
|
105
|
+
# so an attestation made against it outlives what it attests to.
|
|
106
|
+
attestations: false
|
|
107
|
+
# A rehearsal that has been rehearsed before should not fail on that.
|
|
108
|
+
skip-existing: true
|
|
109
|
+
|
|
110
|
+
publish:
|
|
111
|
+
# All six distributions publish from one workflow because they must stay
|
|
112
|
+
# version-locked: denckring-en-data subclasses the core English pack,
|
|
113
|
+
# denckring-de-data carries the sole `de` entry point,
|
|
114
|
+
# denckring-de-wiktionary is the pack that entry point resolves to when it is
|
|
115
|
+
# installed, denckring-de-frequency adds `lexicon.graded_words` to that pack
|
|
116
|
+
# under its own licence (ADR 0038), and denckring-fr-data subclasses the core
|
|
117
|
+
# French pack (ADR 0032). `uv build --all-packages` picks up every workspace
|
|
118
|
+
# member, so the sixth needed no change here.
|
|
119
|
+
#
|
|
120
|
+
# One job per distribution, each with its own environment, and that is forced
|
|
121
|
+
# rather than chosen. PyPI requires a *pending* publisher to be unique on
|
|
122
|
+
# (owner, repository, workflow, environment), so six pending publishers sharing
|
|
123
|
+
# one environment cannot be registered at all — the second is refused with "a
|
|
124
|
+
# pending trusted publisher matching this configuration has already been
|
|
125
|
+
# registered for a different project name" (pypi/warehouse#16920). Environment
|
|
126
|
+
# is the only part of that tuple this workflow can vary, so it varies.
|
|
127
|
+
#
|
|
128
|
+
# The alternatives were worse: create the projects with API tokens and enrol
|
|
129
|
+
# publishers afterwards, or publish one distribution per release event until
|
|
130
|
+
# each pending publisher has been converted. The first reintroduces the upload
|
|
131
|
+
# token this whole arrangement exists to avoid; the second breaks the version
|
|
132
|
+
# lock these six are released under.
|
|
133
|
+
if: github.event_name == 'push'
|
|
134
|
+
needs: [build, docs]
|
|
135
|
+
runs-on: ubuntu-latest
|
|
136
|
+
strategy:
|
|
137
|
+
# A partial release is the failure mode here, and it is worth seeing whole:
|
|
138
|
+
# if one distribution's publisher is misconfigured, the remaining five should
|
|
139
|
+
# still report rather than be cancelled. PyPI will not re-take a version that
|
|
140
|
+
# landed, so the recovery is a version bump either way — knowing which legs
|
|
141
|
+
# succeeded is what makes that recovery short.
|
|
142
|
+
fail-fast: false
|
|
143
|
+
matrix:
|
|
144
|
+
include:
|
|
145
|
+
- {dist: denckring, files: "denckring-", environment: pypi}
|
|
146
|
+
- {dist: denckring-en-data, files: "denckring_en_data-", environment: pypi-en-data}
|
|
147
|
+
- {dist: denckring-de-data, files: "denckring_de_data-", environment: pypi-de-data}
|
|
148
|
+
- {dist: denckring-de-wiktionary, files: "denckring_de_wiktionary-", environment: pypi-de-wiktionary}
|
|
149
|
+
- {dist: denckring-de-frequency, files: "denckring_de_frequency-", environment: pypi-de-frequency}
|
|
150
|
+
- {dist: denckring-fr-data, files: "denckring_fr_data-", environment: pypi-fr-data}
|
|
151
|
+
environment: ${{ matrix.environment }}
|
|
152
|
+
permissions:
|
|
153
|
+
# Trusted Publishing. No API token is stored in repository secrets.
|
|
154
|
+
id-token: write
|
|
155
|
+
attestations: write
|
|
156
|
+
steps:
|
|
157
|
+
- uses: actions/download-artifact@v4
|
|
158
|
+
with:
|
|
159
|
+
name: distributions
|
|
160
|
+
path: all-dist/
|
|
161
|
+
- name: Take only this distribution's artefacts
|
|
162
|
+
run: |
|
|
163
|
+
mkdir -p dist
|
|
164
|
+
cp all-dist/${{ matrix.files }}* dist/
|
|
165
|
+
# `denckring-` is unambiguous because every other distribution builds with
|
|
166
|
+
# underscores — denckring_en_data-0.1.0 and so on — so the core's prefix
|
|
167
|
+
# cannot swallow its siblings. The count below is what actually enforces it.
|
|
168
|
+
count=$(ls dist | wc -l)
|
|
169
|
+
test "$count" -eq 2 || {
|
|
170
|
+
echo "expected 2 artefacts for ${{ matrix.dist }}, found $count"; ls -l dist; exit 1;
|
|
171
|
+
}
|
|
172
|
+
ls -l dist
|
|
173
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
174
|
+
with:
|
|
175
|
+
attestations: true
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.hypothesis/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
dist/
|
|
11
|
+
|
|
12
|
+
# Generated docs and site build
|
|
13
|
+
docs/gallery/
|
|
14
|
+
docs/index.md
|
|
15
|
+
docs/contributing.md
|
|
16
|
+
docs/changelog.md
|
|
17
|
+
site/
|
|
18
|
+
|
|
19
|
+
# The explorer keeps its own environment
|
|
20
|
+
apps/explorer/.venv/
|
|
21
|
+
|
|
22
|
+
# Local secrets and paths for the explorer
|
|
23
|
+
apps/explorer/.env
|
|
24
|
+
|
|
25
|
+
# Claude Code session state, including worktrees
|
|
26
|
+
.claude/
|
|
27
|
+
|
|
28
|
+
# Subagent-driven-development scratch workspace (ledgers, briefs, review packages).
|
|
29
|
+
.superpowers/
|
|
30
|
+
|
|
31
|
+
# Node modules for the explorer's browser reproductions (apps/explorer/tests/browser).
|
|
32
|
+
# The manifest and lockfile beside them ARE tracked, so `npm ci --prefix apps/explorer`
|
|
33
|
+
# reinstalls exactly what those scripts were verified against; the 19MB tree is not.
|
|
34
|
+
apps/explorer/node_modules/
|
|
35
|
+
|
|
36
|
+
# pytest-cov writes this on every --cov run; the report is CI's, not the repo's.
|
|
37
|
+
.coverage
|
|
38
|
+
.coverage.*
|
|
39
|
+
htmlcov/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Mirrors the lint and typecheck jobs in .github/workflows/ci.yml, so a failure
|
|
2
|
+
# here is a failure there.
|
|
3
|
+
repos:
|
|
4
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
5
|
+
rev: v0.16.2
|
|
6
|
+
hooks:
|
|
7
|
+
- id: ruff-check
|
|
8
|
+
args: [--fix]
|
|
9
|
+
- id: ruff-format
|
|
10
|
+
|
|
11
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
12
|
+
rev: v5.0.0
|
|
13
|
+
hooks:
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
exclude: ^mkdocs\.yml$
|
|
16
|
+
- id: check-toml
|
|
17
|
+
- id: end-of-file-fixer
|
|
18
|
+
- id: trailing-whitespace
|
|
19
|
+
- id: check-merge-conflict
|
|
20
|
+
- id: check-added-large-files
|
|
21
|
+
# The vendored pronouncing dictionary is 3.6 MB and belongs in the repo.
|
|
22
|
+
args: [--maxkb=4096]
|
|
23
|
+
|
|
24
|
+
- repo: local
|
|
25
|
+
hooks:
|
|
26
|
+
- id: mypy
|
|
27
|
+
name: mypy --strict
|
|
28
|
+
entry: uv run mypy --strict src tests packages/denckring-en-data/src
|
|
29
|
+
language: system
|
|
30
|
+
pass_filenames: false
|
|
31
|
+
types: [python]
|