kernpy 0.0.2__py3-none-any.whl → 1.0.1__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.
- kernpy/__init__.py +30 -0
- kernpy/__main__.py +127 -0
- kernpy/core/__init__.py +119 -0
- kernpy/core/_io.py +48 -0
- kernpy/core/base_antlr_importer.py +61 -0
- kernpy/core/base_antlr_spine_parser_listener.py +196 -0
- kernpy/core/basic_spine_importer.py +43 -0
- kernpy/core/document.py +965 -0
- kernpy/core/dyn_importer.py +30 -0
- kernpy/core/dynam_spine_importer.py +42 -0
- kernpy/core/error_listener.py +51 -0
- kernpy/core/exporter.py +535 -0
- kernpy/core/fing_spine_importer.py +42 -0
- kernpy/core/generated/kernSpineLexer.interp +444 -0
- kernpy/core/generated/kernSpineLexer.py +535 -0
- kernpy/core/generated/kernSpineLexer.tokens +236 -0
- kernpy/core/generated/kernSpineParser.interp +425 -0
- kernpy/core/generated/kernSpineParser.py +9954 -0
- kernpy/core/generated/kernSpineParser.tokens +236 -0
- kernpy/core/generated/kernSpineParserListener.py +1200 -0
- kernpy/core/generated/kernSpineParserVisitor.py +673 -0
- kernpy/core/generic.py +426 -0
- kernpy/core/gkern.py +526 -0
- kernpy/core/graphviz_exporter.py +89 -0
- kernpy/core/harm_spine_importer.py +41 -0
- kernpy/core/import_humdrum_old.py +853 -0
- kernpy/core/importer.py +285 -0
- kernpy/core/importer_factory.py +43 -0
- kernpy/core/kern_spine_importer.py +73 -0
- kernpy/core/mens_spine_importer.py +23 -0
- kernpy/core/mhxm_spine_importer.py +44 -0
- kernpy/core/pitch_models.py +338 -0
- kernpy/core/root_spine_importer.py +58 -0
- kernpy/core/spine_importer.py +45 -0
- kernpy/core/text_spine_importer.py +43 -0
- kernpy/core/tokenizers.py +239 -0
- kernpy/core/tokens.py +2011 -0
- kernpy/core/transposer.py +300 -0
- kernpy/io/__init__.py +14 -0
- kernpy/io/public.py +355 -0
- kernpy/polish_scores/__init__.py +13 -0
- kernpy/polish_scores/download_polish_dataset.py +357 -0
- kernpy/polish_scores/iiif.py +47 -0
- kernpy/test_grammar.sh +22 -0
- kernpy/util/__init__.py +14 -0
- kernpy/util/helpers.py +55 -0
- kernpy/util/store_cache.py +35 -0
- kernpy/visualize_analysis.sh +23 -0
- kernpy-1.0.1.dist-info/METADATA +497 -0
- kernpy-1.0.1.dist-info/RECORD +51 -0
- {kernpy-0.0.2.dist-info → kernpy-1.0.1.dist-info}/WHEEL +1 -2
- kernpy/example.py +0 -1
- kernpy-0.0.2.dist-info/LICENSE +0 -19
- kernpy-0.0.2.dist-info/METADATA +0 -19
- kernpy-0.0.2.dist-info/RECORD +0 -7
- kernpy-0.0.2.dist-info/top_level.txt +0 -1
kernpy/core/generic.py
ADDED
@@ -0,0 +1,426 @@
|
|
1
|
+
"""
|
2
|
+
Public API for KernPy.
|
3
|
+
|
4
|
+
The main functions for handling the input and output of **kern files are provided here.
|
5
|
+
"""
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import List, Optional, Any, Union, Tuple
|
10
|
+
from collections.abc import Sequence
|
11
|
+
|
12
|
+
from kernpy.core import Importer, Document, Exporter, ExportOptions, GraphvizExporter, TokenCategoryHierarchyMapper
|
13
|
+
from kernpy.core._io import _write
|
14
|
+
from kernpy.util.helpers import deprecated
|
15
|
+
|
16
|
+
|
17
|
+
class Generic:
|
18
|
+
"""
|
19
|
+
Generic class.
|
20
|
+
|
21
|
+
This class provides support to the public API for KernPy.
|
22
|
+
|
23
|
+
The main functions implementation are provided here.
|
24
|
+
"""
|
25
|
+
|
26
|
+
@classmethod
|
27
|
+
def read(
|
28
|
+
cls,
|
29
|
+
path: Path,
|
30
|
+
strict: Optional[bool] = False
|
31
|
+
) -> (Document, List[str]):
|
32
|
+
"""
|
33
|
+
|
34
|
+
Args:
|
35
|
+
path:
|
36
|
+
strict:
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
|
40
|
+
"""
|
41
|
+
importer = Importer()
|
42
|
+
document = importer.import_file(path)
|
43
|
+
errors = importer.errors
|
44
|
+
|
45
|
+
if strict and len(errors) > 0:
|
46
|
+
raise Exception(importer.get_error_messages())
|
47
|
+
|
48
|
+
return document, errors
|
49
|
+
|
50
|
+
@classmethod
|
51
|
+
def create(
|
52
|
+
cls,
|
53
|
+
content: str,
|
54
|
+
strict: Optional[bool] = False
|
55
|
+
) -> (Document, List[str]):
|
56
|
+
"""
|
57
|
+
|
58
|
+
Args:
|
59
|
+
content:
|
60
|
+
strict:
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
|
64
|
+
"""
|
65
|
+
importer = Importer()
|
66
|
+
document = importer.import_string(content)
|
67
|
+
errors = importer.errors
|
68
|
+
|
69
|
+
if strict and len(errors) > 0:
|
70
|
+
raise Exception(importer.get_error_messages())
|
71
|
+
|
72
|
+
return document, errors
|
73
|
+
|
74
|
+
@classmethod
|
75
|
+
def export(
|
76
|
+
cls,
|
77
|
+
document: Document,
|
78
|
+
options: ExportOptions
|
79
|
+
) -> str:
|
80
|
+
"""
|
81
|
+
|
82
|
+
Args:
|
83
|
+
document:
|
84
|
+
options:
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
|
88
|
+
"""
|
89
|
+
exporter = Exporter()
|
90
|
+
return exporter.export_string(document, options)
|
91
|
+
|
92
|
+
@classmethod
|
93
|
+
def store(
|
94
|
+
cls,
|
95
|
+
document: Document,
|
96
|
+
path: Path,
|
97
|
+
options: ExportOptions
|
98
|
+
) -> None:
|
99
|
+
"""
|
100
|
+
|
101
|
+
Args:
|
102
|
+
document:
|
103
|
+
path:
|
104
|
+
options:
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
"""
|
108
|
+
content = cls.export(document, options)
|
109
|
+
_write(path, content)
|
110
|
+
|
111
|
+
@classmethod
|
112
|
+
def store_graph(
|
113
|
+
cls,
|
114
|
+
document: Document,
|
115
|
+
path: Path
|
116
|
+
) -> None:
|
117
|
+
"""
|
118
|
+
|
119
|
+
Args:
|
120
|
+
document:
|
121
|
+
path:
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
"""
|
125
|
+
graph_exporter = GraphvizExporter()
|
126
|
+
graph_exporter.export_to_dot(document.tree, path)
|
127
|
+
|
128
|
+
@classmethod
|
129
|
+
def get_spine_types(
|
130
|
+
cls,
|
131
|
+
document: Document,
|
132
|
+
spine_types: Optional[Sequence[str]] = None
|
133
|
+
) -> List[str]:
|
134
|
+
"""
|
135
|
+
|
136
|
+
Args:
|
137
|
+
document:
|
138
|
+
spine_types:
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
|
142
|
+
"""
|
143
|
+
exporter = Exporter()
|
144
|
+
return exporter.get_spine_types(document, spine_types)
|
145
|
+
|
146
|
+
@classmethod
|
147
|
+
def merge(
|
148
|
+
cls,
|
149
|
+
contents: Sequence[str],
|
150
|
+
strict: Optional[bool] = False
|
151
|
+
) -> Tuple[Document, List[Tuple[int, int]]]:
|
152
|
+
"""
|
153
|
+
|
154
|
+
Args:
|
155
|
+
contents:
|
156
|
+
strict:
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
|
160
|
+
"""
|
161
|
+
if len(contents) < 2:
|
162
|
+
raise ValueError(f"Concatenation action requires at least two documents to concatenate."
|
163
|
+
f"But {len(contents)} was given.")
|
164
|
+
|
165
|
+
raise NotImplementedError("The merge function is not implemented yet.")
|
166
|
+
|
167
|
+
doc_a, err_a = cls.create(contents[0], strict=strict)
|
168
|
+
for i, content in enumerate(contents[1:]):
|
169
|
+
doc_b, err_b = cls.create(content, strict=strict)
|
170
|
+
|
171
|
+
if strict and (len(err_a) > 0 or len(err_b) > 0):
|
172
|
+
raise Exception(f"Errors were found during the creation of the documents "
|
173
|
+
f"while using the strict=True option. "
|
174
|
+
f"Description: concatenating: {err_a if len(err_a) > 0 else err_b}")
|
175
|
+
|
176
|
+
doc_a.add(doc_b)
|
177
|
+
return cls.export(
|
178
|
+
document=doc_a,
|
179
|
+
options=options
|
180
|
+
)
|
181
|
+
|
182
|
+
@classmethod
|
183
|
+
def concat(
|
184
|
+
cls,
|
185
|
+
contents: Sequence[str],
|
186
|
+
separator: Optional[str] = None
|
187
|
+
) -> Tuple[Document, List[Tuple[int, int]]]:
|
188
|
+
"""
|
189
|
+
|
190
|
+
Args:
|
191
|
+
contents:
|
192
|
+
separator:
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
|
196
|
+
"""
|
197
|
+
# Raw kern content
|
198
|
+
if separator is None:
|
199
|
+
separator = '\n'
|
200
|
+
|
201
|
+
if len(contents) == 0:
|
202
|
+
raise ValueError("No contents to merge. At least one content is required.")
|
203
|
+
|
204
|
+
raw_kern = ''
|
205
|
+
document = None
|
206
|
+
indexes = []
|
207
|
+
low_index = 0
|
208
|
+
high_index = 0
|
209
|
+
|
210
|
+
# Merge all fragments
|
211
|
+
for content in contents:
|
212
|
+
raw_kern += separator + content
|
213
|
+
document, _ = create(raw_kern)
|
214
|
+
high_index = document.measures_count()
|
215
|
+
indexes.append((low_index, high_index))
|
216
|
+
|
217
|
+
low_index = high_index + 1 # Next fragment start is the previous fragment end + 1
|
218
|
+
|
219
|
+
if document is None:
|
220
|
+
raise Exception("Failed to merge the contents. The document is None.")
|
221
|
+
|
222
|
+
return document, indexes
|
223
|
+
|
224
|
+
@classmethod
|
225
|
+
def parse_options_to_ExportOptions(
|
226
|
+
cls,
|
227
|
+
**kwargs: Any
|
228
|
+
) -> ExportOptions:
|
229
|
+
"""
|
230
|
+
|
231
|
+
Args:
|
232
|
+
**kwargs:
|
233
|
+
|
234
|
+
Returns:
|
235
|
+
|
236
|
+
"""
|
237
|
+
options = ExportOptions.default()
|
238
|
+
|
239
|
+
# Compute the valid token categories
|
240
|
+
options.token_categories = TokenCategoryHierarchyMapper.valid(
|
241
|
+
include=kwargs.get('include', None),
|
242
|
+
exclude=kwargs.get('exclude', None)
|
243
|
+
)
|
244
|
+
|
245
|
+
# Use kwargs to update the ExportOptions object
|
246
|
+
for key, value in kwargs.items():
|
247
|
+
if key in ['include', 'exclude', 'token_categories']: # Skip these keys: generated manually
|
248
|
+
continue
|
249
|
+
|
250
|
+
if value is not None:
|
251
|
+
setattr(options, key, value)
|
252
|
+
|
253
|
+
return options
|
254
|
+
|
255
|
+
|
256
|
+
@deprecated("Use 'load' instead.")
|
257
|
+
def read(
|
258
|
+
path: Union[str, Path],
|
259
|
+
strict: Optional[bool] = False
|
260
|
+
) -> (Document, List[str]):
|
261
|
+
"""
|
262
|
+
Read a Humdrum **kern file.
|
263
|
+
|
264
|
+
Args:
|
265
|
+
path (Union[str, Path]): File path to read
|
266
|
+
strict (Optional[bool]): If True, raise an error if the **kern file has any errors. Otherwise, return a list of errors.
|
267
|
+
|
268
|
+
Returns (Document, List[str]): Document object and list of error messages. Empty list if no errors.
|
269
|
+
|
270
|
+
Examples:
|
271
|
+
>>> import kernpy as kp
|
272
|
+
>>> document, _ = kp.read('path/to/file.krn')
|
273
|
+
|
274
|
+
>>> document, errors = kp.read('path/to/file.krn')
|
275
|
+
>>> if len(errors) > 0:
|
276
|
+
>>> print(errors)
|
277
|
+
['Error: Invalid **kern spine: 1', 'Error: Invalid **kern spine: 2']
|
278
|
+
"""
|
279
|
+
return Generic.read(
|
280
|
+
path=Path(path),
|
281
|
+
strict=strict
|
282
|
+
)
|
283
|
+
|
284
|
+
|
285
|
+
@deprecated("Use 'loads' instead.")
|
286
|
+
def create(
|
287
|
+
content: str,
|
288
|
+
strict=False
|
289
|
+
) -> (Document, []):
|
290
|
+
"""
|
291
|
+
Create a Document object from a string encoded in Humdrum **kern format.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
content: String encoded in Humdrum **kern format
|
295
|
+
strict: If True, raise an error if the **kern file has any errors. Otherwise, return a list of errors.
|
296
|
+
|
297
|
+
Returns (Document, list): Document object and list of error messages. Empty list if no errors.
|
298
|
+
|
299
|
+
Examples:
|
300
|
+
>>> import kernpy as kp
|
301
|
+
>>> document, errors = kp.create('**kern\n4e\n4f\n4g\n*-\n')
|
302
|
+
>>> if len(errors) > 0:
|
303
|
+
>>> print(errors)
|
304
|
+
['Error: Invalid **kern spine: 1', 'Error: Invalid **kern spine: 2']
|
305
|
+
"""
|
306
|
+
return Generic.create(
|
307
|
+
content=content,
|
308
|
+
strict=strict
|
309
|
+
)
|
310
|
+
|
311
|
+
|
312
|
+
@deprecated("Use 'dumps' instead.")
|
313
|
+
def export(
|
314
|
+
document: Document,
|
315
|
+
options: ExportOptions
|
316
|
+
) -> str:
|
317
|
+
"""
|
318
|
+
Export a Document object to a string.
|
319
|
+
|
320
|
+
Args:
|
321
|
+
document: Document object to export
|
322
|
+
options: Export options
|
323
|
+
|
324
|
+
Returns: Exported string
|
325
|
+
|
326
|
+
Examples:
|
327
|
+
>>> import kernpy as kp
|
328
|
+
>>> document, errors = kp.read('path/to/file.krn')
|
329
|
+
>>> options = kp.ExportOptions()
|
330
|
+
>>> content = kp.export(document, options)
|
331
|
+
"""
|
332
|
+
return Generic.export(
|
333
|
+
document=document,
|
334
|
+
options=options
|
335
|
+
)
|
336
|
+
|
337
|
+
|
338
|
+
@deprecated("Use 'dump' instead.")
|
339
|
+
def store(
|
340
|
+
document: Document,
|
341
|
+
path: Union[str, Path],
|
342
|
+
options: ExportOptions
|
343
|
+
) -> None:
|
344
|
+
"""
|
345
|
+
Store a Document object to a file.
|
346
|
+
|
347
|
+
Args:
|
348
|
+
document (Document): Document object to store
|
349
|
+
path (Union[str, Path]): File path to store
|
350
|
+
options (ExportOptions): Export options
|
351
|
+
|
352
|
+
Returns: None
|
353
|
+
|
354
|
+
Examples:
|
355
|
+
>>> import kernpy as kp
|
356
|
+
>>> document, errors = kp.read('path/to/file.krn')
|
357
|
+
>>> options = kp.ExportOptions()
|
358
|
+
>>> kp.store(document, 'path/to/store.krn', options)
|
359
|
+
|
360
|
+
"""
|
361
|
+
Generic.store(
|
362
|
+
document=document,
|
363
|
+
path=Path(path),
|
364
|
+
options=options
|
365
|
+
)
|
366
|
+
|
367
|
+
|
368
|
+
@deprecated("Use 'graph' instead.")
|
369
|
+
def store_graph(
|
370
|
+
document: Document,
|
371
|
+
path: Union[str, Path]
|
372
|
+
) -> None:
|
373
|
+
"""
|
374
|
+
Create a graph representation of a Document object using Graphviz. Save the graph to a file.
|
375
|
+
|
376
|
+
Args:
|
377
|
+
document (Document): Document object to create graph from
|
378
|
+
path (str): File path to save the graph
|
379
|
+
|
380
|
+
Returns (None): None
|
381
|
+
|
382
|
+
Examples:
|
383
|
+
>>> import kernpy as kp
|
384
|
+
>>> document, errors = kp.read('path/to/file.krn')
|
385
|
+
>>> kp.store_graph(document, 'path/to/graph.dot')
|
386
|
+
"""
|
387
|
+
return Generic.store_graph(
|
388
|
+
document=document,
|
389
|
+
path=Path(path)
|
390
|
+
)
|
391
|
+
|
392
|
+
|
393
|
+
@deprecated("Use 'spine_types' instead.")
|
394
|
+
def get_spine_types(
|
395
|
+
document: Document,
|
396
|
+
spine_types: Optional[Sequence[str]] = None
|
397
|
+
) -> List[str]:
|
398
|
+
"""
|
399
|
+
Get the spines of a Document object.
|
400
|
+
|
401
|
+
Args:
|
402
|
+
document (Document): Document object to get spines from
|
403
|
+
spine_types (Optional[Sequence[str]]): List of spine types to get. If None, all spines are returned.
|
404
|
+
|
405
|
+
Returns (List[str]): List of spines
|
406
|
+
|
407
|
+
Examples:
|
408
|
+
>>> import kernpy as kp
|
409
|
+
>>> document, _ = kp.read('path/to/file.krn')
|
410
|
+
>>> kp.get_spine_types(document)
|
411
|
+
['**kern', '**kern', '**kern', '**kern', '**root', '**harm']
|
412
|
+
>>> kp.get_spine_types(document, None)
|
413
|
+
['**kern', '**kern', '**kern', '**kern', '**root', '**harm']
|
414
|
+
>>> kp.get_spine_types(document, ['**kern'])
|
415
|
+
['**kern', '**kern', '**kern', '**kern']
|
416
|
+
>>> kp.get_spine_types(document, ['**kern', '**root'])
|
417
|
+
['**kern', '**kern', '**kern', '**kern', '**root']
|
418
|
+
>>> kp.get_spine_types(document, ['**kern', '**root', '**harm'])
|
419
|
+
['**kern', '**kern', '**kern', '**kern', '**root', '**harm']
|
420
|
+
>>> kp.get_spine_types(document, [])
|
421
|
+
[]
|
422
|
+
"""
|
423
|
+
return Generic.get_spine_types(
|
424
|
+
document=document,
|
425
|
+
spine_types=spine_types
|
426
|
+
)
|