libmorpheus 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,398 @@
1
+ Metadata-Version: 2.4
2
+ Name: libmorpheus
3
+ Version: 0.1.0
4
+ Summary: Python binding for Ancient Greek and Latin morphology with libmorpheus
5
+ Author: Défense des humanités
6
+ Maintainer: Antoine Boquet
7
+ License-Expression: AGPL-3.0-or-later
8
+ Project-URL: Documentation, https://github.com/defense-humanites/libmorpheus/tree/main/bindings/python
9
+ Project-URL: Issues, https://github.com/defense-humanites/libmorpheus/issues
10
+ Project-URL: Repository, https://github.com/defense-humanites/libmorpheus
11
+ Keywords: ancient-greek,classics,digital-humanities,latin,morphology
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Education
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Text Processing :: Linguistic
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ License-File: NOTICE
29
+ Dynamic: license-file
30
+
31
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
32
+
33
+ # libmorpheus for Python
34
+
35
+ `libmorpheus` modernizes the [Morpheus](https://github.com/PerseusDL/morpheus)
36
+ morphological analyzer for Ancient Greek and Latin. It turns the historical C
37
+ programs into an installable C17 shared library with a stable, opaque ABI and a
38
+ typed Python binding.
39
+
40
+ This package loads the
41
+ [`libmorpheus`](https://github.com/defense-humanites/libmorpheus) shared library
42
+ with the standard-library `ctypes` module. It exposes normalized Greek and Latin
43
+ analysis plus experimental Greek lemma generation. Native results are copied
44
+ into immutable Python objects before their C allocations are released.
45
+
46
+ ## Summary
47
+
48
+ 1. [Quick start (using the PyPI package)](#quick-start-using-the-pypi-package)
49
+ 2. [In-depth overview](#in-depth-overview)
50
+ 1. [Analyze a form](#analyze-a-form)
51
+ 2. [Generate forms from a lemma](#generate-forms-from-a-lemma)
52
+ 3. [Use parallel contexts](#use-parallel-contexts)
53
+ 4. [Raw access and cleanup](#raw-access-and-cleanup)
54
+ 3. [Other installation options](#other-installation-options)
55
+ 1. [Install from a source checkout](#install-from-a-source-checkout)
56
+ 2. [Build the native runtime](#build-the-native-runtime)
57
+ 4. [Native library and runtime data](#native-library-and-runtime-data)
58
+ 1. [Acquire stem data](#acquire-stem-data)
59
+ 2. [Acquire the native library](#acquire-the-native-library)
60
+ 3. [Language and data coverage](#language-and-data-coverage)
61
+ 5. [Python and platform support](#python-and-platform-support)
62
+ 6. [Documentation](#documentation)
63
+ 7. [Local checks](#local-checks)
64
+ 8. [License](#license)
65
+
66
+ ## Quick start (using the PyPI package)
67
+
68
+ The Python package requires Python 3.11 or later and has no third-party runtime
69
+ dependencies. Install the typed, universal wheel:
70
+
71
+ ```sh
72
+ python -m pip install libmorpheus
73
+ ```
74
+
75
+ The wheel contains neither the native library nor linguistic stem data. Install
76
+ a compatible native `libmorpheus` release and stemlib as described below, then
77
+ create `app.py`:
78
+
79
+ ```python
80
+ from libmorpheus import Language, Library, Option
81
+
82
+ with Library("/path/to/libmorpheus.so") as library:
83
+ with library.context("/path/to/stemlib", Language.GREEK) as context:
84
+ analyses = context.analyze(
85
+ "a)/nqrwpos",
86
+ Option.STRICT_CASE,
87
+ )
88
+
89
+ for analysis in analyses:
90
+ print(analysis.lemma, analysis.part_of_speech)
91
+ ```
92
+
93
+ Run it normally:
94
+
95
+ ```sh
96
+ python app.py
97
+ ```
98
+
99
+ The binding itself performs no network access and reads no environment
100
+ variables. Applications may pass paths from their own configuration:
101
+
102
+ ```python
103
+ import os
104
+
105
+ library_path = os.environ["MORPHEUS_LIBRARY"]
106
+ stemlib_path = os.environ["MORPHEUS_STEMLIB"]
107
+ ```
108
+
109
+ Version `0.1.0` deliberately leaves runtime and data acquisition outside the
110
+ Python package. The [native releases](https://github.com/defense-humanites/libmorpheus/releases)
111
+ and [runtime-data guide](https://github.com/defense-humanites/libmorpheus/blob/main/docs/runtime-data.md)
112
+ provide the required components; a complete source-checkout recipe appears
113
+ below.
114
+
115
+ ## In-depth overview
116
+
117
+ ### Analyze a form
118
+
119
+ ```python
120
+ from libmorpheus import Language, Library, MorpheusError, Option
121
+
122
+ try:
123
+ with Library("/usr/local/lib/libmorpheus.so") as library:
124
+ with library.context(
125
+ "/path/to/stemlib", Language.GREEK
126
+ ) as context:
127
+ analyses = context.analyze(
128
+ "a)/nqrwpos", Option.STRICT_CASE
129
+ )
130
+ print(analyses[0].part_of_speech) # "noun"
131
+ print(analyses[0].grammatical_number) # "singular"
132
+ print(analyses[0].grammatical_cases) # ("nominative",)
133
+ except MorpheusError as error:
134
+ print(f"Morpheus status {error.status}: {error}")
135
+ ```
136
+
137
+ `analyze()` returns stable English identifiers, tuples for combinable masks, and
138
+ `None` for inapplicable scalar values. It preserves all analyses. A generic
139
+ stemlib `indecl` class remains `"unknown"` because it does not identify a
140
+ lexical category. An empty dialect tuple means no recorded restriction.
141
+
142
+ Options are `IntFlag` values and may be combined with `|`. For example, strict
143
+ case plus accent-insensitive fallback is:
144
+
145
+ ```python
146
+ options = Option.STRICT_CASE | Option.IGNORE_ACCENTS
147
+ analyses = context.analyze("a)/nqrwpos", options)
148
+ ```
149
+
150
+ Passing no option uses the binding's default analysis behavior. See the
151
+ [native option table](https://github.com/defense-humanites/libmorpheus/blob/main/docs/public-api.md#request-options)
152
+ before enabling specialized modes.
153
+
154
+ `Option.HQ_DICTIONARY` requires both HQ index files. If they are absent,
155
+ `analyze()` raises `MorpheusError` with `Status.STEMLIB_ERROR` before native
156
+ analysis.
157
+
158
+ ### Generate forms from a lemma
159
+
160
+ > [!WARNING]
161
+ > `generate()` and `generate_raw()` are experimental. Their automated
162
+ > differential, isolation, failure, portability, and sanitizer coverage is
163
+ > extensive, but sufficient real-world use is still required before this
164
+ > qualification can be removed.
165
+
166
+ ```python
167
+ from libmorpheus import (
168
+ Dialect,
169
+ GenerationOptions,
170
+ Language,
171
+ Library,
172
+ MorpheusError,
173
+ Number,
174
+ Status,
175
+ )
176
+
177
+ try:
178
+ with Library("/usr/local/lib/libmorpheus.so") as library:
179
+ with library.context(
180
+ "/path/to/stemlib", Language.GREEK
181
+ ) as context:
182
+ duals = context.generate(
183
+ "lo/gos",
184
+ GenerationOptions(
185
+ number=Number.DUAL,
186
+ dialect=Dialect.ATTIC,
187
+ result_limit=256,
188
+ ),
189
+ )
190
+ for form in duals:
191
+ print(form.surface, form.grammatical_cases)
192
+ except MorpheusError as error:
193
+ if error.status == Status.RESULT_LIMIT_EXCEEDED:
194
+ print("Increase the explicit result limit for this paradigm")
195
+ else:
196
+ raise
197
+ ```
198
+
199
+ `generate()` accepts typed filters for part of speech, dialect, region, person,
200
+ number, gender, case, tense, mood, voice, and degree. It preserves dialect
201
+ masks, duals, duplicate surfaces, and multiple indexed interpretations unless
202
+ filters remove them. Set `exclude_duals=True` when dual forms are unwanted.
203
+ `result_limit=0` uses the native default of 4,096; a nonzero value is a hard
204
+ safety ceiling, not a truncation request. The explicit maximum is 65,536.
205
+
206
+ ### Use parallel contexts
207
+
208
+ Calls are synchronous at the Python surface. One context deliberately
209
+ serializes its native operations because the underlying state is mutable.
210
+ Create separate contexts and submit them to separate threads for independent
211
+ work:
212
+
213
+ ```python
214
+ from concurrent.futures import ThreadPoolExecutor
215
+
216
+ with Library("/usr/local/lib/libmorpheus.so") as library:
217
+ with (
218
+ library.context(stemlib, Language.GREEK) as first,
219
+ library.context(stemlib, Language.GREEK) as second,
220
+ ThreadPoolExecutor(max_workers=2) as executor,
221
+ ):
222
+ analysis_future = executor.submit(first.analyze, "a)/nqrwpos")
223
+ generation_future = executor.submit(second.generate, "lo/gos")
224
+ analyses = analysis_future.result()
225
+ forms = generation_future.result()
226
+ ```
227
+
228
+ `ctypes.CDLL` releases the GIL during native calls, so distinct contexts can
229
+ execute concurrently. The actual speedup depends on the workload and machine.
230
+ Reuse warm contexts; the generation index is loaded lazily once per context.
231
+
232
+ ### Raw access and cleanup
233
+
234
+ Use `analyze_raw()` and `generate_raw()` for ABI inspection and low-level
235
+ tools. They return numeric normalized traits, `struct_size`, the complete
236
+ 11-byte public morphology vector, and a numeric truncation mask. The semantic
237
+ methods return named morphology flags and truncated fields.
238
+
239
+ Close contexts before their parent library. Both objects support context
240
+ managers and idempotent `close()` methods. `Library.close()` raises while any
241
+ child context remains open. Context managers provide deterministic cleanup,
242
+ including when an operation raises.
243
+
244
+ ## Other installation options
245
+
246
+ ### Install from a source checkout
247
+
248
+ For binding development, install the Python package from a checkout in editable
249
+ mode:
250
+
251
+ ```sh
252
+ python -m pip install -e bindings/python
253
+ ```
254
+
255
+ This installs only the pure-Python facade. It does not compile or install the
256
+ native runtime and does not copy stem data.
257
+
258
+ ### Build the native runtime
259
+
260
+ A recursive checkout can supply all three development components: the Python
261
+ facade, native library, and Perseids stemlib.
262
+
263
+ ```sh
264
+ git clone --recurse-submodules \
265
+ https://github.com/defense-humanites/libmorpheus.git
266
+ cd libmorpheus
267
+ cmake --preset dev
268
+ cmake --build --preset dev --target morpheus
269
+ python -m pip install ./bindings/python
270
+ ```
271
+
272
+ Use `build/dev/libmorpheus.so` on Linux or
273
+ `build/dev/libmorpheus.dylib` on macOS, and use the checkout's `stemlib/`
274
+ directory for Greek and Latin analysis.
275
+
276
+ ## Native library and runtime data
277
+
278
+ The binding needs both a native `libmorpheus` library and a compatible stemlib.
279
+ Neither is part of the Python wheel or source distribution.
280
+
281
+ | Distribution | Native library | Stem data | What to do |
282
+ | --- | --- | --- | --- |
283
+ | PyPI wheel or source distribution | Not included | Not included | Install a compatible native release and acquire a stemlib. |
284
+ | Recursive project checkout | Build with CMake | Perseids submodule | Pass the build output and `stemlib/` paths explicitly. |
285
+
286
+ Binding and runtime versions are independent. Python binding `0.1.0` targets
287
+ native runtime `0.3.2` and requires C ABI `2`. The package exports
288
+ `MORPHEUS_PYTHON_VERSION`, `MORPHEUS_NATIVE_VERSION`, and
289
+ `MORPHEUS_NATIVE_ABI_VERSION`; `__version__` is the conventional alias for the
290
+ Python package version.
291
+
292
+ ### Acquire stem data
293
+
294
+ For analysis from a source checkout, use its recursively initialized
295
+ `stemlib/` directory. It contains the Perseids dataset for Ancient Greek and
296
+ Latin. The Alpheios dataset is a Greek-only alternative under
297
+ `vendor/alpheios-morpheus/dist/stemlib`.
298
+
299
+ Experimental generation requires a prepared Alpheios directory containing a
300
+ validated `gener.index`:
301
+
302
+ ```sh
303
+ sh tools/prepare-runtime-data.sh "$PWD/morpheus-greek-data"
304
+ ```
305
+
306
+ The output directory must not already exist. Pass its absolute path to
307
+ `Library.context()`. See the complete
308
+ [runtime-data guide](https://github.com/defense-humanites/libmorpheus/blob/main/docs/runtime-data.md)
309
+ for pinned sources, validation, and redistribution boundaries.
310
+
311
+ ### Acquire the native library
312
+
313
+ Version `0.1.0` does not download native code during `pip install` and provides
314
+ no Python acquisition command. Install the compatible `v0.3.2` native archive
315
+ from the [GitHub releases page](https://github.com/defense-humanites/libmorpheus/releases),
316
+ or build the runtime from a matching source checkout as shown above. Pass the
317
+ actual `.so` or `.dylib` path to `Library`; the binding does not search system
318
+ paths or environment variables implicitly.
319
+
320
+ ### Language and data coverage
321
+
322
+ The operation and selected dataset together determine language coverage:
323
+
324
+ | Operation or dataset | Ancient Greek | Latin | Additional requirement |
325
+ | --- | :---: | :---: | --- |
326
+ | `analyze()` | Yes | Yes | A stemlib for the selected language. |
327
+ | `generate()` | Yes | No | Alpheios data prepared with `gener.index`. |
328
+ | Perseids | Yes | Yes | No |
329
+ | Alpheios | Yes | No | Prepare `gener.index` for generation. |
330
+
331
+ See the [stem-library inventory](https://github.com/defense-humanites/libmorpheus/blob/main/docs/stem-libraries.md)
332
+ for dataset origins and repository locations.
333
+
334
+ ## Python and platform support
335
+
336
+ The package requires Python 3.11 or later, ships a `py.typed` marker, and has no
337
+ third-party runtime dependencies. Its wheel is `py3-none-any` because the FFI
338
+ layer is pure Python; execution still requires a compatible separately
339
+ installed native library.
340
+
341
+ The release qualification matrix covers Python 3.11 and 3.14 on Linux with the
342
+ real runtime and an ABI fixture. The native release currently provides Linux
343
+ x86-64 glibc, Linux aarch64 glibc, and macOS arm64 archives. Windows is not
344
+ supported by native runtime `0.3.2`.
345
+
346
+ ## Documentation
347
+
348
+ Public classes, enums, immutable result dataclasses, and version constants are
349
+ exported directly from `libmorpheus`. The package includes a `py.typed` marker
350
+ for static type checkers.
351
+
352
+ | Topic | Document |
353
+ | --- | --- |
354
+ | Native ABI, ownership, and options | [Public API](https://github.com/defense-humanites/libmorpheus/blob/main/docs/public-api.md) |
355
+ | Runtime and dataset acquisition | [Runtime data](https://github.com/defense-humanites/libmorpheus/blob/main/docs/runtime-data.md) |
356
+ | AGPL/MPL file boundary | [Licensing guide](https://github.com/defense-humanites/libmorpheus/blob/main/docs/licensing.md) |
357
+ | Source and dataset lineage | [Provenance](https://github.com/defense-humanites/libmorpheus/blob/main/docs/provenance.md) |
358
+ | Available stem libraries | [Stem libraries](https://github.com/defense-humanites/libmorpheus/blob/main/docs/stem-libraries.md) |
359
+ | Supported platforms | [Portability](https://github.com/defense-humanites/libmorpheus/blob/main/docs/portability.md) |
360
+ | Release archives and qualification | [Releasing](https://github.com/defense-humanites/libmorpheus/blob/main/docs/releasing.md) |
361
+
362
+ ## Local checks
363
+
364
+ Build the library and small differential generation index before running the
365
+ binding tests:
366
+
367
+ ```sh
368
+ cmake --preset dev
369
+ cmake --build --preset dev --target \
370
+ morpheus morpheus_gener_index_builder
371
+ build/dev/morpheus_gener_index_builder \
372
+ stemlib/gener.index test/generation-service-source.txt
373
+ PYTHONDONTWRITEBYTECODE=1 \
374
+ PYTHONPATH=bindings/python/src \
375
+ python -B -m unittest discover -s bindings/python/test -v
376
+ PYTHONDONTWRITEBYTECODE=1 \
377
+ PYTHONPATH=bindings/python/src \
378
+ python -B bindings/python/test/runtime_smoke.py \
379
+ build/dev/libmorpheus.so stemlib
380
+ ```
381
+
382
+ Build and inspect the universal distributions with:
383
+
384
+ ```sh
385
+ python -m build bindings/python
386
+ python -m pip install --no-deps bindings/python/dist/*.whl
387
+ ```
388
+
389
+ ## License
390
+
391
+ The Python binding itself is licensed under
392
+ [AGPL-3.0-or-later](LICENSE). Its pure-Python `ctypes` facade does not inherit
393
+ the mixed licensing of the separately installed native runtime and contains no
394
+ linguistic stem data.
395
+
396
+ See the [package notice](NOTICE) and the project's
397
+ [licensing guide](https://github.com/defense-humanites/libmorpheus/blob/main/docs/licensing.md)
398
+ for the precise file-level boundary and redistribution considerations.
@@ -0,0 +1,12 @@
1
+ libmorpheus/__init__.py,sha256=DUxkWutTID22hqJO1P2oBCpw2NxmfDpFnVHzA37kjf0,1187
2
+ libmorpheus/_abi.py,sha256=wczXUXV00JAqsNeuho9fuO1h4_VMg8tidTaV8x037bI,7853
3
+ libmorpheus/_library.py,sha256=fmxYgc1CTVkWUylqqIUuPlQlAX7A1XxgC6lD5hfhPDg,11377
4
+ libmorpheus/_types.py,sha256=PwMzbne70t_A1rxGbOve2L2v3PYd2jfuM9uqGZXh8us,13503
5
+ libmorpheus/_version.py,sha256=dgX5CM_fqv5udjQQaRIUTfWO-wjeLbcbY1Z_XbK8g3o,219
6
+ libmorpheus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ libmorpheus-0.1.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
8
+ libmorpheus-0.1.0.dist-info/licenses/NOTICE,sha256=XT8KbCeuSIgpMaE70MolfkiWHjioV_QKf-_ebxKcgWs,493
9
+ libmorpheus-0.1.0.dist-info/METADATA,sha256=6AcnCPRUsw4dq-T8hx6luIXjScAQgoz_Wtf_xkjzlXA,15540
10
+ libmorpheus-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
11
+ libmorpheus-0.1.0.dist-info/top_level.txt,sha256=pFAeRJY34DmArrDRLzoCPFkYF4yBzIKbdd1wHfihuo4,12
12
+ libmorpheus-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+