dipo 0.2.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.
Files changed (119) hide show
  1. dipo-0.2.0/LICENSE +21 -0
  2. dipo-0.2.0/PKG-INFO +278 -0
  3. dipo-0.2.0/README.md +238 -0
  4. dipo-0.2.0/dipo/__init__.py +22 -0
  5. dipo-0.2.0/dipo/__main__.py +103 -0
  6. dipo-0.2.0/dipo/common/__init__.py +0 -0
  7. dipo-0.2.0/dipo/common/log.py +65 -0
  8. dipo-0.2.0/dipo/common/training.py +613 -0
  9. dipo-0.2.0/dipo/rst/__init__.py +34 -0
  10. dipo-0.2.0/dipo/rst/data/__init__.py +0 -0
  11. dipo-0.2.0/dipo/rst/data/metrics.py +280 -0
  12. dipo-0.2.0/dipo/rst/data/reader.py +280 -0
  13. dipo-0.2.0/dipo/rst/data/seg_metrics.py +157 -0
  14. dipo-0.2.0/dipo/rst/data/tree.py +1106 -0
  15. dipo-0.2.0/dipo/rst/parsers/__init__.py +94 -0
  16. dipo-0.2.0/dipo/rst/parsers/common/__init__.py +0 -0
  17. dipo-0.2.0/dipo/rst/parsers/common/biaffine.py +49 -0
  18. dipo-0.2.0/dipo/rst/parsers/common/config.py +135 -0
  19. dipo-0.2.0/dipo/rst/parsers/common/curriculum.py +144 -0
  20. dipo-0.2.0/dipo/rst/parsers/common/detokenization.py +43 -0
  21. dipo-0.2.0/dipo/rst/parsers/common/encoding.py +474 -0
  22. dipo-0.2.0/dipo/rst/parsers/common/generative_eval.py +232 -0
  23. dipo-0.2.0/dipo/rst/parsers/common/inference.py +107 -0
  24. dipo-0.2.0/dipo/rst/parsers/common/pointer.py +47 -0
  25. dipo-0.2.0/dipo/rst/parsers/common/predict_cli.py +152 -0
  26. dipo-0.2.0/dipo/rst/parsers/common/segmentation.py +300 -0
  27. dipo-0.2.0/dipo/rst/parsers/common/seqgen.py +522 -0
  28. dipo-0.2.0/dipo/rst/parsers/common/sexp_constraints.py +763 -0
  29. dipo-0.2.0/dipo/rst/parsers/common/whitespace.py +110 -0
  30. dipo-0.2.0/dipo/rst/parsers/dmrst/__init__.py +2 -0
  31. dipo-0.2.0/dipo/rst/parsers/dmrst/configuration_dmrst.py +174 -0
  32. dipo-0.2.0/dipo/rst/parsers/dmrst/modeling_dmrst.py +818 -0
  33. dipo-0.2.0/dipo/rst/parsers/dmrst/predict_dmrst.py +9 -0
  34. dipo-0.2.0/dipo/rst/parsers/dmrst/train_dmrst.py +528 -0
  35. dipo-0.2.0/dipo/rst/parsers/gen/__init__.py +4 -0
  36. dipo-0.2.0/dipo/rst/parsers/gen/backbones/__init__.py +10 -0
  37. dipo-0.2.0/dipo/rst/parsers/gen/backbones/base.py +466 -0
  38. dipo-0.2.0/dipo/rst/parsers/gen/backbones/decoder_only.py +415 -0
  39. dipo-0.2.0/dipo/rst/parsers/gen/backbones/seq2seq.py +372 -0
  40. dipo-0.2.0/dipo/rst/parsers/gen/configuration_gen.py +299 -0
  41. dipo-0.2.0/dipo/rst/parsers/gen/decode.py +337 -0
  42. dipo-0.2.0/dipo/rst/parsers/gen/errors.py +31 -0
  43. dipo-0.2.0/dipo/rst/parsers/gen/eval_gen.py +176 -0
  44. dipo-0.2.0/dipo/rst/parsers/gen/modeling_gen.py +393 -0
  45. dipo-0.2.0/dipo/rst/parsers/gen/predict_gen.py +9 -0
  46. dipo-0.2.0/dipo/rst/parsers/gen/serializations/__init__.py +10 -0
  47. dipo-0.2.0/dipo/rst/parsers/gen/serializations/base.py +231 -0
  48. dipo-0.2.0/dipo/rst/parsers/gen/serializations/sexp.py +487 -0
  49. dipo-0.2.0/dipo/rst/parsers/gen/serializations/sr.py +351 -0
  50. dipo-0.2.0/dipo/rst/parsers/gen/train_gen.py +484 -0
  51. dipo-0.2.0/dipo/rst/parsers/hfhub/__init__.py +22 -0
  52. dipo-0.2.0/dipo/rst/parsers/hfhub/datasets.py +188 -0
  53. dipo-0.2.0/dipo/rst/parsers/hfhub/hub.py +502 -0
  54. dipo-0.2.0/dipo/rst/parsers/hfhub/push.py +49 -0
  55. dipo-0.2.0/dipo/rst/parsers/icl/__init__.py +14 -0
  56. dipo-0.2.0/dipo/rst/parsers/icl/_cli_common.py +48 -0
  57. dipo-0.2.0/dipo/rst/parsers/icl/configuration_icl.py +274 -0
  58. dipo-0.2.0/dipo/rst/parsers/icl/eval_icl.py +239 -0
  59. dipo-0.2.0/dipo/rst/parsers/icl/eval_metrics.py +95 -0
  60. dipo-0.2.0/dipo/rst/parsers/icl/modeling_icl.py +293 -0
  61. dipo-0.2.0/dipo/rst/parsers/icl/predict_icl.py +84 -0
  62. dipo-0.2.0/dipo/rst/parsers/icl/provider.py +445 -0
  63. dipo-0.2.0/dipo/rst/parsers/icl/serialize.py +748 -0
  64. dipo-0.2.0/dipo/rst/parsers/sr_biaffine/__init__.py +2 -0
  65. dipo-0.2.0/dipo/rst/parsers/sr_biaffine/configuration_sr_biaffine.py +82 -0
  66. dipo-0.2.0/dipo/rst/parsers/sr_biaffine/modeling_sr_biaffine.py +240 -0
  67. dipo-0.2.0/dipo/rst/parsers/sr_biaffine/predict_sr_biaffine.py +9 -0
  68. dipo-0.2.0/dipo/rst/parsers/sr_biaffine/train_sr_biaffine.py +369 -0
  69. dipo-0.2.0/dipo/rst/parsers/topdown_biaffine/__init__.py +2 -0
  70. dipo-0.2.0/dipo/rst/parsers/topdown_biaffine/configuration_topdown_biaffine.py +76 -0
  71. dipo-0.2.0/dipo/rst/parsers/topdown_biaffine/modeling_topdown_biaffine.py +216 -0
  72. dipo-0.2.0/dipo/rst/parsers/topdown_biaffine/predict_topdown_biaffine.py +9 -0
  73. dipo-0.2.0/dipo/rst/parsers/topdown_biaffine/train_topdown_biaffine.py +369 -0
  74. dipo-0.2.0/dipo/runs.py +745 -0
  75. dipo-0.2.0/dipo.egg-info/PKG-INFO +278 -0
  76. dipo-0.2.0/dipo.egg-info/SOURCES.txt +117 -0
  77. dipo-0.2.0/dipo.egg-info/dependency_links.txt +1 -0
  78. dipo-0.2.0/dipo.egg-info/entry_points.txt +3 -0
  79. dipo-0.2.0/dipo.egg-info/requires.txt +16 -0
  80. dipo-0.2.0/dipo.egg-info/top_level.txt +1 -0
  81. dipo-0.2.0/pyproject.toml +86 -0
  82. dipo-0.2.0/setup.cfg +4 -0
  83. dipo-0.2.0/tests/test_action_loss_chunked.py +106 -0
  84. dipo-0.2.0/tests/test_beam_nan_poisoning.py +95 -0
  85. dipo-0.2.0/tests/test_budget_range_gold_edu_forcer.py +369 -0
  86. dipo-0.2.0/tests/test_cjk_split.py +100 -0
  87. dipo-0.2.0/tests/test_decode_invariants.py +210 -0
  88. dipo-0.2.0/tests/test_decode_positional_budget.py +160 -0
  89. dipo-0.2.0/tests/test_edu_token_alignment.py +139 -0
  90. dipo-0.2.0/tests/test_encoder_backbones.py +274 -0
  91. dipo-0.2.0/tests/test_gen_accum_windows.py +143 -0
  92. dipo-0.2.0/tests/test_gen_batched_greedy_equivalence.py +180 -0
  93. dipo-0.2.0/tests/test_gen_batched_sexp_cascade.py +171 -0
  94. dipo-0.2.0/tests/test_gen_document_weights.py +39 -0
  95. dipo-0.2.0/tests/test_gen_equivalence.py +191 -0
  96. dipo-0.2.0/tests/test_gen_inference_method.py +44 -0
  97. dipo-0.2.0/tests/test_gen_overlength.py +90 -0
  98. dipo-0.2.0/tests/test_gen_train_smoke.py +165 -0
  99. dipo-0.2.0/tests/test_gold_edu_beam.py +183 -0
  100. dipo-0.2.0/tests/test_gold_edu_semantics_parity.py +96 -0
  101. dipo-0.2.0/tests/test_icl.py +491 -0
  102. dipo-0.2.0/tests/test_model_card.py +81 -0
  103. dipo-0.2.0/tests/test_peft_inert_fields.py +116 -0
  104. dipo-0.2.0/tests/test_qlora_4bit_loading.py +215 -0
  105. dipo-0.2.0/tests/test_retired_config_keys.py +66 -0
  106. dipo-0.2.0/tests/test_seq2seq_input_budget.py +190 -0
  107. dipo-0.2.0/tests/test_seqgen_checkpoint_and_batch.py +113 -0
  108. dipo-0.2.0/tests/test_sexp_constraints.py +712 -0
  109. dipo-0.2.0/tests/test_sexp_empty_tree_fallback.py +101 -0
  110. dipo-0.2.0/tests/test_sexp_roundtrip.py +100 -0
  111. dipo-0.2.0/tests/test_sexp_words_labels.py +176 -0
  112. dipo-0.2.0/tests/test_shift_reduce_roundtrip.py +141 -0
  113. dipo-0.2.0/tests/test_sr_biaffine.py +108 -0
  114. dipo-0.2.0/tests/test_sr_decode_state.py +105 -0
  115. dipo-0.2.0/tests/test_sr_deep_tree_degrades.py +63 -0
  116. dipo-0.2.0/tests/test_trainable_only_shadow_checkpoint.py +211 -0
  117. dipo-0.2.0/tests/test_training_checkpoint.py +181 -0
  118. dipo-0.2.0/tests/test_whitespace_input.py +174 -0
  119. dipo-0.2.0/tests/test_wsd_scheduler.py +62 -0
dipo-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luke Gessler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
dipo-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,278 @@
1
+ Metadata-Version: 2.4
2
+ Name: dipo
3
+ Version: 0.2.0
4
+ Summary: Dipo, the Discourse Parsing Omnibus: a collection of easy-to-use discourse parsers and associated code.
5
+ Author-email: Luke Gessler <lukegessler@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/larc-iu/dipo
8
+ Project-URL: Repository, https://github.com/larc-iu/dipo
9
+ Project-URL: Issues, https://github.com/larc-iu/dipo/issues
10
+ Keywords: discourse parsing,rhetorical structure theory,RST,NLP,computational linguistics
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Text Processing :: Linguistic
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: torch
25
+ Requires-Dist: transformers
26
+ Requires-Dist: huggingface_hub
27
+ Requires-Dist: tonga-config
28
+ Requires-Dist: lxml
29
+ Requires-Dist: rich
30
+ Requires-Dist: sentencepiece
31
+ Requires-Dist: sacremoses
32
+ Requires-Dist: peft
33
+ Requires-Dist: tensorboard
34
+ Requires-Dist: setuptools<81
35
+ Provides-Extra: dev
36
+ Requires-Dist: ruff; extra == "dev"
37
+ Requires-Dist: build; extra == "dev"
38
+ Requires-Dist: twine; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ # Dipo
42
+
43
+ The **<u>Di</u>scourse <u>P</u>arsing <u>O</u>mnibus** (Dipo, said like "depot") is a collection of easy-to-use discourse parsers and other code related to discourse parsing.
44
+
45
+ Dipo was formerly called IUDEX (`larc-iudex` on PyPI, with the command `iudex`).
46
+
47
+ ## Setup
48
+
49
+ For the latest release:
50
+
51
+ ```
52
+ pip install dipo
53
+ ```
54
+
55
+ For the current state of `master`:
56
+
57
+ ```
58
+ pip install git+https://github.com/larc-iu/dipo
59
+ ```
60
+
61
+ Or for development:
62
+
63
+ ```
64
+ git clone https://github.com/larc-iu/dipo && cd dipo
65
+ pip install -e .
66
+ ```
67
+
68
+ The old `iudex` command still works for now, as a deprecated alias of `dipo` that prints a notice. `import iudex` is now `import dipo`.
69
+
70
+ ## Quick Start with Inference
71
+
72
+ Parse a sample document end-to-end with a pretrained DMRST model pulled from the HuggingFace Hub. From the command line:
73
+
74
+ ```bash
75
+ dipo dmrst predict \
76
+ --hub-id larc-iu/dmrst-ettin-400m-gum-12.1.0 \
77
+ --text "Although the experiment was carefully designed, the results were inconclusive. We plan to repeat it tonight."
78
+ ```
79
+ This yields the parsed tree in `.rs3` format printed to `stdout`:
80
+ ```xml
81
+ <rst>
82
+ <relations><!-- ... --></relations>
83
+ <body>
84
+ <segment id="1" parent="2" relname="adversative-concession">Although the experiment was carefully # designed,</segment>
85
+ <segment id="2" parent="4" relname="span">the results were inconclusive.</segment>
86
+ <segment id="3" parent="5" relname="span">We plan to repeat it tonight.</segment>
87
+ <group id="4" type="span" parent="3" relname="adversative-antithesis"/>
88
+ <group id="5" type="span"/>
89
+ </body>
90
+ </rst>
91
+ ```
92
+
93
+ The same flow from Python:
94
+
95
+ ```python
96
+ from dipo.rst.parsers.dmrst.modeling_dmrst import DMRSTParser
97
+ parser = DMRSTParser.from_pretrained("larc-iu/dmrst-ettin-400m-gum-12.1.0")
98
+ tree = parser.predict_from_text(
99
+ "Although the experiment was carefully designed, "
100
+ "the results were inconclusive. "
101
+ "We plan to repeat it tonight."
102
+ )
103
+ print(tree.to_rs4_string())
104
+ ```
105
+ Yields:
106
+ ```xml
107
+ <rst>
108
+ <relations><!-- ... --></relations>
109
+ <body>
110
+ <segment id="1" parent="2" relname="adversative-concession">Although the experiment was carefully # designed,</segment>
111
+ <segment id="2" parent="4" relname="span">the results were inconclusive.</segment>
112
+ <segment id="3" parent="5" relname="span">We plan to repeat it tonight.</segment>
113
+ <group id="4" type="span" parent="3" relname="adversative-antithesis"/>
114
+ <group id="5" type="span"/>
115
+ </body>
116
+ </rst>
117
+ ```
118
+
119
+ ## Inference CLI
120
+
121
+ To identify a model on the command line, you may use a configuration file (`--config`), a PyTorch checkpoint (`--checkpoint`), or a HuggingFace Hub repository (`--hub-id`).
122
+
123
+ To provide input, you may specify an inline string (`--text`), a path to a raw text file or directory (`--text-file`, for parsers which support this), or an RS3/RS4 file or directory with gold EDUs already supplied (`--input`).
124
+
125
+ For `--text-file` and `--input`, results are written to `--output-dir` as `.rs4` files.
126
+
127
+ ```
128
+ # From the Hub, end-to-end on a directory of .txt files:
129
+ dipo dmrst predict \
130
+ --hub-id larc-iu/dmrst-ettin-400m-gum-12.1.0 \
131
+ --text-file path/to/docs/ \
132
+ --output-dir out/ \
133
+ --device cuda
134
+
135
+ # From an explicit checkpoint:
136
+ dipo dmrst predict \
137
+ --checkpoint checkpoints/<run_id>/best_model.pt \
138
+ --text-file path/to/doc.txt \
139
+ --output-dir out/
140
+
141
+ # From a trained run's config, parsing pre-segmented RS3/RS4 with gold EDUs:
142
+ dipo topdown_biaffine predict \
143
+ --config configs/topdown_biaffine_rstdt.jsonnet \
144
+ --input data/rstdt/test \
145
+ --output-dir out/
146
+ ```
147
+
148
+ ## Available Models
149
+ All official Dipo model releases are [tagged with `dipo` on the HuggingFace Hub](https://huggingface.co/models?other=dipo) (they also carry the old `iudex` tag for now).
150
+
151
+ All of the models below parse raw text end to end (segmentation and structure) and were trained on untokenized text, so plain prose works as input.
152
+ There is no need to tokenize it or to remove line breaks, and Chinese should be given unspaced.
153
+ Scores are original Parseval Full F1 on each corpus's test set, end to end from raw text.
154
+
155
+ | Hub ID | Parser | Backbone | Corpus | Test Full |
156
+ | --- | --- | --- | --- | --- |
157
+ | [`larc-iu/dmrst-ettin-400m-rstdt-coarse`](https://huggingface.co/larc-iu/dmrst-ettin-400m-rstdt-coarse) | `dmrst` | Ettin encoder 400M | RST-DT (English) | 53.2 |
158
+ | [`larc-iu/gen-sr-t5gemma-2-1b-1b-rstdt-coarse`](https://huggingface.co/larc-iu/gen-sr-t5gemma-2-1b-1b-rstdt-coarse) | `gen` | T5Gemma 2 1B-1B | RST-DT (English) | 49.6 |
159
+ | [`larc-iu/gen-sr-gemma-4-31b-it-rstdt-coarse`](https://huggingface.co/larc-iu/gen-sr-gemma-4-31b-it-rstdt-coarse) | `gen` | Gemma 4 31B | RST-DT (English) | 54.7 |
160
+ | [`larc-iu/dmrst-ettin-400m-gum-12.1.0`](https://huggingface.co/larc-iu/dmrst-ettin-400m-gum-12.1.0) | `dmrst` | Ettin encoder 400M | GUM 12.1.0 (English) | 45.6 |
161
+ | [`larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0`](https://huggingface.co/larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0) | `gen` | T5Gemma 2 1B-1B | GUM 12.1.0 (English) | 39.4 |
162
+ | [`larc-iu/gen-sr-gemma-4-31b-it-gum-12.1.0`](https://huggingface.co/larc-iu/gen-sr-gemma-4-31b-it-gum-12.1.0) | `gen` | Gemma 4 31B | GUM 12.1.0 (English) | 45.8 |
163
+ | [`larc-iu/dmrst-xlm-roberta-base-ert`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-ert) | `dmrst` | XLM-R base | RST Basque TreeBank | 27.6 |
164
+ | [`larc-iu/dmrst-xlm-roberta-base-pcc-2.2`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-pcc-2.2) | `dmrst` | XLM-R base | Potsdam Commentary Corpus 2.2 (German) | 18.6 |
165
+ | [`larc-iu/dmrst-xlm-roberta-base-prstc`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-prstc) | `dmrst` | XLM-R base | Persian RST Corpus | 32.2 |
166
+ | [`larc-iu/dmrst-xlm-roberta-base-gcdt`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-gcdt) | `dmrst` | XLM-R base | GCDT (Chinese) | 29.4 |
167
+
168
+ The `dmrst` models cannot see line breaks, so `predict_from_text` also starts a new segment at blank-line paragraph breaks and after short heading-like lines.
169
+ Pass `break_at_paragraphs=False` to use the model's own segmentation alone.
170
+
171
+ The `gen` models are built on a pretrained backbone, and loading one also downloads that backbone from the Hub.
172
+ The two Gemma 4 models are small adapters (about 0.5 GB), so they require accepting Google's terms for `google/gemma-4-31B-it` and a GPU with roughly 70 GB of memory.
173
+ The T5Gemma models store their full weights (about 4.4 GB).
174
+ They are invoked like the others, e.g. `dipo gen predict --hub-id larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0 --text "..."`.
175
+ A document longer than a `gen` model's context window (16,384 tokens) is rejected with an error rather than silently truncated.
176
+
177
+ ## Training
178
+
179
+ To train a new top-down biaffine parser on RSTDT:
180
+
181
+ ```
182
+ dipo topdown_biaffine train configs/topdown_biaffine_rstdt.jsonnet
183
+ ```
184
+
185
+ Note that `configs/topdown_biaffine_rstdt.jsonnet` is a configuration.
186
+ You may either edit it directly or copy and modify it in a new location.
187
+
188
+ ### Training on Raw Text
189
+
190
+ Several corpora distribute their EDUs word-tokenized (`the drug trade ,`), and a parser trained on that text sees punctuation spacing at inference that real input never has.
191
+ `scripts/build_raw_text_data.py` writes untokenized copies of RST-DT, PCC, GCDT and the Persian corpus to `data/<corpus>_notok`, with identical trees, and the released models were trained on these.
192
+ RST-DT's raw text comes from the LDC release, which must be present at `data/rst_discourse_treebank`.
193
+ For unspaced Chinese, also set `split_cjk_tokens: true` in a DMRST config, so that every EDU boundary falls on a token boundary.
194
+
195
+ ### Grabbing Example Configurations
196
+
197
+ Model configurations required for training are not bundled with the package distributed via PyPI.
198
+
199
+ To get them you may visit [the associated directory](https://github.com/larc-iu/dipo/tree/master/configs) and download the configurations you're interested in manually.
200
+
201
+ If you want to grab all of them at once, you can use the command line like so:
202
+
203
+ **bash / zsh / macOS / Linux:**
204
+
205
+ ```bash
206
+ curl -fL https://github.com/larc-iu/dipo/archive/refs/heads/master.tar.gz \
207
+ | tar -xz --strip-components=1 --wildcards '*/configs'
208
+ ```
209
+
210
+ **Windows PowerShell:**
211
+
212
+ ```powershell
213
+ Invoke-WebRequest https://github.com/larc-iu/dipo/archive/refs/heads/master.zip -OutFile dipo.zip
214
+ Expand-Archive dipo.zip -DestinationPath .
215
+ Move-Item dipo-master/configs configs
216
+ Remove-Item -Recurse -Force dipo-master, dipo.zip
217
+ ```
218
+
219
+ Either leaves you with a local `configs/` directory you can edit and pass to `dipo … train configs/<name>.jsonnet`.
220
+
221
+ ### Configuration Hashes
222
+
223
+ Your configuration is used as the basis for a unique hash, which (by default) corresponds to a directory under `checkpoints/`.
224
+ This hash is used for several purposes.
225
+ For example, running the same config again resumes from the last epoch's checkpoint `last.pt` automatically if the run was interrupted.
226
+
227
+ To view all runs and their status, you may run the `runs list` subcommand:
228
+
229
+ ```
230
+ $ dipo runs list
231
+ Runs in checkpoints
232
+ ┏━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━┓
233
+ ┃ run_id ┃ run_name ┃ parser ┃ model_name ┃ train_dir ┃ best_val ┃ step ┃ modified ┃
234
+ ┡━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━┩
235
+ │ 245b1d774676 │ - │ dmrst │ xlm-roberta-base │ data/gum_12.1.0/train │ 0.3099 │ 1704 │ 2026-05-18 18:02 │
236
+ │ 41bc0fe1dd50 │ - │ topdown_biaffine │ SpanBERT/spanbert-base-cased │ data/rstdt/train │ 0.7576 │ 2149 │ 2026-05-18 13:51 │
237
+ │ 91525e48d63d │ - │ topdown_biaffine │ SpanBERT/spanbert-base-cased │ data/gum_12.1.0/train │ 0.6364 │ 1899 │ 2026-05-18 14:31 │
238
+ │ ad934ca992d4 │ - │ dmrst │ xlm-roberta-base │ data/rstdt/train │ 0.4665 │ 3090 │ 2026-05-18 16:46 │
239
+ └──────────────┴──────────┴──────────────────┴──────────────────────────────┴───────────────────────┴───────────┴──────┴──────────────────┘
240
+ ```
241
+
242
+ ### Monitoring with TensorBoard
243
+
244
+ Every run writes TensorBoard scalars (train loss, learning rate, gradient norm, and dev metrics) to `<run_dir>/tb/`. Point TensorBoard at your checkpoints directory to watch any run live or compare runs:
245
+
246
+ ```
247
+ tensorboard --logdir checkpoints/
248
+ ```
249
+
250
+ ### Pushing Models to HF Hub
251
+ You may host a trained model using each parser's `push` subcommand.
252
+ Each uploads `best_model.pt`, `config.json`, and an auto-generated `README.md` in a single commit:
253
+
254
+ ```
255
+ dipo topdown_biaffine push \
256
+ --config configs/topdown_biaffine_rstdt.jsonnet \
257
+ --repo-id larc-iu/topdown_biaffine-rstdt-coarse \
258
+ [--private] [--message "..."] [--token $HF_TOKEN]
259
+ ```
260
+
261
+ ## Citation
262
+
263
+ If you use Dipo in your research, please cite it as:
264
+
265
+ > Gessler, Luke. 2026. *Dipo: The Discourse Parsing Omnibus.* https://github.com/larc-iu/dipo.
266
+
267
+ BibTeX:
268
+
269
+ ```bibtex
270
+ @misc{gessler-dipo-2026,
271
+ author = {Gessler, Luke},
272
+ title = {{Dipo: The Discourse Parsing Omnibus}},
273
+ year = {2026},
274
+ howpublished = {\url{https://github.com/larc-iu/dipo}},
275
+ }
276
+ ```
277
+
278
+ If you use one of the included parser re-implementations, please **also** cite the original paper (see each model's Hub card for the canonical reference).
dipo-0.2.0/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # Dipo
2
+
3
+ The **<u>Di</u>scourse <u>P</u>arsing <u>O</u>mnibus** (Dipo, said like "depot") is a collection of easy-to-use discourse parsers and other code related to discourse parsing.
4
+
5
+ Dipo was formerly called IUDEX (`larc-iudex` on PyPI, with the command `iudex`).
6
+
7
+ ## Setup
8
+
9
+ For the latest release:
10
+
11
+ ```
12
+ pip install dipo
13
+ ```
14
+
15
+ For the current state of `master`:
16
+
17
+ ```
18
+ pip install git+https://github.com/larc-iu/dipo
19
+ ```
20
+
21
+ Or for development:
22
+
23
+ ```
24
+ git clone https://github.com/larc-iu/dipo && cd dipo
25
+ pip install -e .
26
+ ```
27
+
28
+ The old `iudex` command still works for now, as a deprecated alias of `dipo` that prints a notice. `import iudex` is now `import dipo`.
29
+
30
+ ## Quick Start with Inference
31
+
32
+ Parse a sample document end-to-end with a pretrained DMRST model pulled from the HuggingFace Hub. From the command line:
33
+
34
+ ```bash
35
+ dipo dmrst predict \
36
+ --hub-id larc-iu/dmrst-ettin-400m-gum-12.1.0 \
37
+ --text "Although the experiment was carefully designed, the results were inconclusive. We plan to repeat it tonight."
38
+ ```
39
+ This yields the parsed tree in `.rs3` format printed to `stdout`:
40
+ ```xml
41
+ <rst>
42
+ <relations><!-- ... --></relations>
43
+ <body>
44
+ <segment id="1" parent="2" relname="adversative-concession">Although the experiment was carefully # designed,</segment>
45
+ <segment id="2" parent="4" relname="span">the results were inconclusive.</segment>
46
+ <segment id="3" parent="5" relname="span">We plan to repeat it tonight.</segment>
47
+ <group id="4" type="span" parent="3" relname="adversative-antithesis"/>
48
+ <group id="5" type="span"/>
49
+ </body>
50
+ </rst>
51
+ ```
52
+
53
+ The same flow from Python:
54
+
55
+ ```python
56
+ from dipo.rst.parsers.dmrst.modeling_dmrst import DMRSTParser
57
+ parser = DMRSTParser.from_pretrained("larc-iu/dmrst-ettin-400m-gum-12.1.0")
58
+ tree = parser.predict_from_text(
59
+ "Although the experiment was carefully designed, "
60
+ "the results were inconclusive. "
61
+ "We plan to repeat it tonight."
62
+ )
63
+ print(tree.to_rs4_string())
64
+ ```
65
+ Yields:
66
+ ```xml
67
+ <rst>
68
+ <relations><!-- ... --></relations>
69
+ <body>
70
+ <segment id="1" parent="2" relname="adversative-concession">Although the experiment was carefully # designed,</segment>
71
+ <segment id="2" parent="4" relname="span">the results were inconclusive.</segment>
72
+ <segment id="3" parent="5" relname="span">We plan to repeat it tonight.</segment>
73
+ <group id="4" type="span" parent="3" relname="adversative-antithesis"/>
74
+ <group id="5" type="span"/>
75
+ </body>
76
+ </rst>
77
+ ```
78
+
79
+ ## Inference CLI
80
+
81
+ To identify a model on the command line, you may use a configuration file (`--config`), a PyTorch checkpoint (`--checkpoint`), or a HuggingFace Hub repository (`--hub-id`).
82
+
83
+ To provide input, you may specify an inline string (`--text`), a path to a raw text file or directory (`--text-file`, for parsers which support this), or an RS3/RS4 file or directory with gold EDUs already supplied (`--input`).
84
+
85
+ For `--text-file` and `--input`, results are written to `--output-dir` as `.rs4` files.
86
+
87
+ ```
88
+ # From the Hub, end-to-end on a directory of .txt files:
89
+ dipo dmrst predict \
90
+ --hub-id larc-iu/dmrst-ettin-400m-gum-12.1.0 \
91
+ --text-file path/to/docs/ \
92
+ --output-dir out/ \
93
+ --device cuda
94
+
95
+ # From an explicit checkpoint:
96
+ dipo dmrst predict \
97
+ --checkpoint checkpoints/<run_id>/best_model.pt \
98
+ --text-file path/to/doc.txt \
99
+ --output-dir out/
100
+
101
+ # From a trained run's config, parsing pre-segmented RS3/RS4 with gold EDUs:
102
+ dipo topdown_biaffine predict \
103
+ --config configs/topdown_biaffine_rstdt.jsonnet \
104
+ --input data/rstdt/test \
105
+ --output-dir out/
106
+ ```
107
+
108
+ ## Available Models
109
+ All official Dipo model releases are [tagged with `dipo` on the HuggingFace Hub](https://huggingface.co/models?other=dipo) (they also carry the old `iudex` tag for now).
110
+
111
+ All of the models below parse raw text end to end (segmentation and structure) and were trained on untokenized text, so plain prose works as input.
112
+ There is no need to tokenize it or to remove line breaks, and Chinese should be given unspaced.
113
+ Scores are original Parseval Full F1 on each corpus's test set, end to end from raw text.
114
+
115
+ | Hub ID | Parser | Backbone | Corpus | Test Full |
116
+ | --- | --- | --- | --- | --- |
117
+ | [`larc-iu/dmrst-ettin-400m-rstdt-coarse`](https://huggingface.co/larc-iu/dmrst-ettin-400m-rstdt-coarse) | `dmrst` | Ettin encoder 400M | RST-DT (English) | 53.2 |
118
+ | [`larc-iu/gen-sr-t5gemma-2-1b-1b-rstdt-coarse`](https://huggingface.co/larc-iu/gen-sr-t5gemma-2-1b-1b-rstdt-coarse) | `gen` | T5Gemma 2 1B-1B | RST-DT (English) | 49.6 |
119
+ | [`larc-iu/gen-sr-gemma-4-31b-it-rstdt-coarse`](https://huggingface.co/larc-iu/gen-sr-gemma-4-31b-it-rstdt-coarse) | `gen` | Gemma 4 31B | RST-DT (English) | 54.7 |
120
+ | [`larc-iu/dmrst-ettin-400m-gum-12.1.0`](https://huggingface.co/larc-iu/dmrst-ettin-400m-gum-12.1.0) | `dmrst` | Ettin encoder 400M | GUM 12.1.0 (English) | 45.6 |
121
+ | [`larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0`](https://huggingface.co/larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0) | `gen` | T5Gemma 2 1B-1B | GUM 12.1.0 (English) | 39.4 |
122
+ | [`larc-iu/gen-sr-gemma-4-31b-it-gum-12.1.0`](https://huggingface.co/larc-iu/gen-sr-gemma-4-31b-it-gum-12.1.0) | `gen` | Gemma 4 31B | GUM 12.1.0 (English) | 45.8 |
123
+ | [`larc-iu/dmrst-xlm-roberta-base-ert`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-ert) | `dmrst` | XLM-R base | RST Basque TreeBank | 27.6 |
124
+ | [`larc-iu/dmrst-xlm-roberta-base-pcc-2.2`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-pcc-2.2) | `dmrst` | XLM-R base | Potsdam Commentary Corpus 2.2 (German) | 18.6 |
125
+ | [`larc-iu/dmrst-xlm-roberta-base-prstc`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-prstc) | `dmrst` | XLM-R base | Persian RST Corpus | 32.2 |
126
+ | [`larc-iu/dmrst-xlm-roberta-base-gcdt`](https://huggingface.co/larc-iu/dmrst-xlm-roberta-base-gcdt) | `dmrst` | XLM-R base | GCDT (Chinese) | 29.4 |
127
+
128
+ The `dmrst` models cannot see line breaks, so `predict_from_text` also starts a new segment at blank-line paragraph breaks and after short heading-like lines.
129
+ Pass `break_at_paragraphs=False` to use the model's own segmentation alone.
130
+
131
+ The `gen` models are built on a pretrained backbone, and loading one also downloads that backbone from the Hub.
132
+ The two Gemma 4 models are small adapters (about 0.5 GB), so they require accepting Google's terms for `google/gemma-4-31B-it` and a GPU with roughly 70 GB of memory.
133
+ The T5Gemma models store their full weights (about 4.4 GB).
134
+ They are invoked like the others, e.g. `dipo gen predict --hub-id larc-iu/gen-sr-t5gemma-2-1b-1b-gum-12.1.0 --text "..."`.
135
+ A document longer than a `gen` model's context window (16,384 tokens) is rejected with an error rather than silently truncated.
136
+
137
+ ## Training
138
+
139
+ To train a new top-down biaffine parser on RSTDT:
140
+
141
+ ```
142
+ dipo topdown_biaffine train configs/topdown_biaffine_rstdt.jsonnet
143
+ ```
144
+
145
+ Note that `configs/topdown_biaffine_rstdt.jsonnet` is a configuration.
146
+ You may either edit it directly or copy and modify it in a new location.
147
+
148
+ ### Training on Raw Text
149
+
150
+ Several corpora distribute their EDUs word-tokenized (`the drug trade ,`), and a parser trained on that text sees punctuation spacing at inference that real input never has.
151
+ `scripts/build_raw_text_data.py` writes untokenized copies of RST-DT, PCC, GCDT and the Persian corpus to `data/<corpus>_notok`, with identical trees, and the released models were trained on these.
152
+ RST-DT's raw text comes from the LDC release, which must be present at `data/rst_discourse_treebank`.
153
+ For unspaced Chinese, also set `split_cjk_tokens: true` in a DMRST config, so that every EDU boundary falls on a token boundary.
154
+
155
+ ### Grabbing Example Configurations
156
+
157
+ Model configurations required for training are not bundled with the package distributed via PyPI.
158
+
159
+ To get them you may visit [the associated directory](https://github.com/larc-iu/dipo/tree/master/configs) and download the configurations you're interested in manually.
160
+
161
+ If you want to grab all of them at once, you can use the command line like so:
162
+
163
+ **bash / zsh / macOS / Linux:**
164
+
165
+ ```bash
166
+ curl -fL https://github.com/larc-iu/dipo/archive/refs/heads/master.tar.gz \
167
+ | tar -xz --strip-components=1 --wildcards '*/configs'
168
+ ```
169
+
170
+ **Windows PowerShell:**
171
+
172
+ ```powershell
173
+ Invoke-WebRequest https://github.com/larc-iu/dipo/archive/refs/heads/master.zip -OutFile dipo.zip
174
+ Expand-Archive dipo.zip -DestinationPath .
175
+ Move-Item dipo-master/configs configs
176
+ Remove-Item -Recurse -Force dipo-master, dipo.zip
177
+ ```
178
+
179
+ Either leaves you with a local `configs/` directory you can edit and pass to `dipo … train configs/<name>.jsonnet`.
180
+
181
+ ### Configuration Hashes
182
+
183
+ Your configuration is used as the basis for a unique hash, which (by default) corresponds to a directory under `checkpoints/`.
184
+ This hash is used for several purposes.
185
+ For example, running the same config again resumes from the last epoch's checkpoint `last.pt` automatically if the run was interrupted.
186
+
187
+ To view all runs and their status, you may run the `runs list` subcommand:
188
+
189
+ ```
190
+ $ dipo runs list
191
+ Runs in checkpoints
192
+ ┏━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━┓
193
+ ┃ run_id ┃ run_name ┃ parser ┃ model_name ┃ train_dir ┃ best_val ┃ step ┃ modified ┃
194
+ ┡━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━┩
195
+ │ 245b1d774676 │ - │ dmrst │ xlm-roberta-base │ data/gum_12.1.0/train │ 0.3099 │ 1704 │ 2026-05-18 18:02 │
196
+ │ 41bc0fe1dd50 │ - │ topdown_biaffine │ SpanBERT/spanbert-base-cased │ data/rstdt/train │ 0.7576 │ 2149 │ 2026-05-18 13:51 │
197
+ │ 91525e48d63d │ - │ topdown_biaffine │ SpanBERT/spanbert-base-cased │ data/gum_12.1.0/train │ 0.6364 │ 1899 │ 2026-05-18 14:31 │
198
+ │ ad934ca992d4 │ - │ dmrst │ xlm-roberta-base │ data/rstdt/train │ 0.4665 │ 3090 │ 2026-05-18 16:46 │
199
+ └──────────────┴──────────┴──────────────────┴──────────────────────────────┴───────────────────────┴───────────┴──────┴──────────────────┘
200
+ ```
201
+
202
+ ### Monitoring with TensorBoard
203
+
204
+ Every run writes TensorBoard scalars (train loss, learning rate, gradient norm, and dev metrics) to `<run_dir>/tb/`. Point TensorBoard at your checkpoints directory to watch any run live or compare runs:
205
+
206
+ ```
207
+ tensorboard --logdir checkpoints/
208
+ ```
209
+
210
+ ### Pushing Models to HF Hub
211
+ You may host a trained model using each parser's `push` subcommand.
212
+ Each uploads `best_model.pt`, `config.json`, and an auto-generated `README.md` in a single commit:
213
+
214
+ ```
215
+ dipo topdown_biaffine push \
216
+ --config configs/topdown_biaffine_rstdt.jsonnet \
217
+ --repo-id larc-iu/topdown_biaffine-rstdt-coarse \
218
+ [--private] [--message "..."] [--token $HF_TOKEN]
219
+ ```
220
+
221
+ ## Citation
222
+
223
+ If you use Dipo in your research, please cite it as:
224
+
225
+ > Gessler, Luke. 2026. *Dipo: The Discourse Parsing Omnibus.* https://github.com/larc-iu/dipo.
226
+
227
+ BibTeX:
228
+
229
+ ```bibtex
230
+ @misc{gessler-dipo-2026,
231
+ author = {Gessler, Luke},
232
+ title = {{Dipo: The Discourse Parsing Omnibus}},
233
+ year = {2026},
234
+ howpublished = {\url{https://github.com/larc-iu/dipo}},
235
+ }
236
+ ```
237
+
238
+ If you use one of the included parser re-implementations, please **also** cite the original paper (see each model's Hub card for the canonical reference).
@@ -0,0 +1,22 @@
1
+ """This module declares the project's CLI surface that lives above any one
2
+ framework:
3
+
4
+ - `FRAMEWORKS`: dotted paths of framework modules (e.g. `dipo.rst`).
5
+ Each framework module exposes `PARSERS`, `PARSER_SCOPED_COMMANDS`,
6
+ and `GLOBAL_COMMANDS`. The dispatcher (`dipo/__main__.py`) imports
7
+ each and merges the three.
8
+ - `GLOBAL_COMMANDS`: `{cmd: module_path}` for project-level commands
9
+ that aren't owned by any single framework (e.g. `runs`, which walks
10
+ every framework's parser registry to tag rows by parser kind).
11
+
12
+ To add a sibling framework, append its dotted path to `FRAMEWORKS` and
13
+ give its `__init__.py` the three required attributes.
14
+ """
15
+
16
+ __version__ = "0.2.0"
17
+
18
+ FRAMEWORKS: list[str] = ["dipo.rst"]
19
+
20
+ GLOBAL_COMMANDS: dict[str, str] = {
21
+ "runs": "dipo.runs",
22
+ }
@@ -0,0 +1,103 @@
1
+ """dipo CLI dispatcher.
2
+
3
+ `dipo <parser> <cmd>` or `dipo <cmd>` for globals. Routes by merging the
4
+ registries declared by each framework in `dipo.FRAMEWORKS`. See
5
+ `dipo/__init__.py` for the framework contract.
6
+ """
7
+
8
+ import importlib
9
+ import sys
10
+
11
+ import dipo
12
+
13
+
14
+ def _merge_frameworks() -> tuple[dict, dict, dict]:
15
+ """Merge each framework's three registry dicts atop project-level
16
+ `dipo.GLOBAL_COMMANDS`. Aborts on a name collision."""
17
+ parsers: dict = {}
18
+ parser_scoped: dict = {}
19
+ global_cmds: dict = dict(dipo.GLOBAL_COMMANDS)
20
+ for fw_path in dipo.FRAMEWORKS:
21
+ fw = importlib.import_module(fw_path)
22
+ _merge_no_collide(parsers, fw.PARSERS, fw_path, "parser name")
23
+ _merge_no_collide(parser_scoped, fw.PARSER_SCOPED_COMMANDS, fw_path, "parser-scoped command")
24
+ _merge_no_collide(global_cmds, fw.GLOBAL_COMMANDS, fw_path, "global command")
25
+ return parsers, parser_scoped, global_cmds
26
+
27
+
28
+ def _merge_no_collide(dst: dict, src: dict, fw_path: str, kind: str) -> None:
29
+ for k, v in src.items():
30
+ if k in dst and dst[k] is not v:
31
+ sys.stderr.write(
32
+ f"dipo: {kind} {k!r} declared by both an earlier framework and {fw_path!r}. Rename one of them.\n"
33
+ )
34
+ sys.exit(2)
35
+ dst[k] = v
36
+
37
+
38
+ PARSERS, PARSER_SCOPED_COMMANDS, GLOBAL_COMMANDS = _merge_frameworks()
39
+
40
+
41
+ def main():
42
+ if len(sys.argv) > 1 and sys.argv[1] in ("-h", "--help"):
43
+ print(__doc__.strip())
44
+ print(f"\nKnown parsers: {', '.join(sorted(PARSERS))}")
45
+ print(f"Global commands: {', '.join(sorted(GLOBAL_COMMANDS))}")
46
+ sys.exit(0)
47
+
48
+ if len(sys.argv) < 2:
49
+ sys.stderr.write(__doc__.strip() + "\n\n")
50
+ sys.stderr.write(f"Known parsers: {', '.join(sorted(PARSERS))}\n")
51
+ sys.stderr.write(f"Global commands: {', '.join(sorted(GLOBAL_COMMANDS))}\n")
52
+ sys.exit(2)
53
+
54
+ head = sys.argv[1]
55
+
56
+ if head in GLOBAL_COMMANDS:
57
+ module = importlib.import_module(GLOBAL_COMMANDS[head])
58
+ sys.argv = [GLOBAL_COMMANDS[head]] + sys.argv[2:]
59
+ module.main()
60
+ return
61
+
62
+ if len(sys.argv) < 3:
63
+ sys.stderr.write(__doc__.strip() + "\n\n")
64
+ sys.stderr.write(f"Known parsers: {', '.join(sorted(PARSERS))}\n")
65
+ sys.exit(2)
66
+
67
+ parser_name = head
68
+ command = sys.argv[2]
69
+
70
+ if parser_name not in PARSERS:
71
+ sys.stderr.write(f"Unknown parser: {parser_name!r}\n")
72
+ sys.stderr.write(f"Known parsers: {', '.join(sorted(PARSERS))}\n")
73
+ sys.stderr.write(f"Global commands: {', '.join(sorted(GLOBAL_COMMANDS))}\n")
74
+ sys.exit(2)
75
+
76
+ if command in PARSER_SCOPED_COMMANDS:
77
+ shared_path = PARSER_SCOPED_COMMANDS[command]
78
+ module = importlib.import_module(shared_path)
79
+ sys.argv = [f"dipo {parser_name} {command}"] + sys.argv[3:]
80
+ module.main(parser_kind=parser_name)
81
+ return
82
+
83
+ module_path = f"{PARSERS[parser_name].package}.{command}_{parser_name}"
84
+ try:
85
+ module = importlib.import_module(module_path)
86
+ except ImportError as e:
87
+ sys.stderr.write(f"No such command {command!r} for parser {parser_name!r}\n")
88
+ sys.stderr.write(f" (tried to import {module_path}: {e})\n")
89
+ sys.exit(2)
90
+
91
+ sys.argv = [module_path] + sys.argv[3:]
92
+ module.main()
93
+
94
+
95
+ def main_iudex():
96
+ """Entry point of the deprecated `iudex` command, the old name of this project."""
97
+ sys.stderr.write("iudex: this command has been renamed to `dipo` and takes the same arguments. "
98
+ "`iudex` will be removed in a future release.\n")
99
+ main()
100
+
101
+
102
+ if __name__ == "__main__":
103
+ main()
File without changes