kernpy 1.0.0__py3-none-any.whl → 1.0.2__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 CHANGED
@@ -4,7 +4,7 @@
4
4
  =====
5
5
 
6
6
 
7
- Python Humdrum kern and mens utilities package.
7
+ Python Humdrum **kern and **mens utilities package.
8
8
 
9
9
 
10
10
 
@@ -13,191 +13,6 @@ Execute the following command to run **kernpy** as a module:
13
13
  python -m kernpy --help
14
14
  python -m kernpy <command> <options>
15
15
  ```
16
-
17
- Run `kernpy` from your script:
18
- ```python
19
- import kernpy
20
-
21
- help(kernpy)
22
- ```
23
-
24
- While the package is not published in `pip`, the `kernpy` module must be in the root directory.
25
-
26
- ## 🎯 **kern2ekern**: Convertir un solo archivo .krn a .ekern:
27
-
28
- ```bash
29
- python -m kernpy --kern2ekern --input_path <input_file> <v | --verbose [0-2]>
30
- ```
31
-
32
- The command has the following arguments:
33
- * **input_path**: Ruta del archivo .krn a convertir.
34
- * **output_path**: Ruta del archivo .ekern a generar (opcional). Si no se especifica, se generará en la misma ubicación.
35
- * **-r**: Recursivo (opcional).
36
- * **--verbose[0-2]**: Nivel de verbosidad (opcional).
37
-
38
-
39
- 📌 Basic usage running **kernpy** as a module:
40
- ```shell
41
- python -m kernpy --input_path /my/path/to/file.krn # New ekern generated in /my/path/to/file.ekern
42
- ```
43
-
44
- 📌 Generate an _ekrn_ file in specific location running **kernpy** as a module:
45
- ```shell
46
- python -m kernpy --input_path /my/path/to/file.krn --output_path /new/output.ekern
47
- ```
48
-
49
- 📌 Converting all the .krn files in a directory to .ekern files running **kernpy** as a module:
50
- * Every .krn file in the directory will be converted to .ekern in the same location.
51
- * Using, at least, one additional directory level is required.
52
- ```
53
- root
54
- ├─ kern-folder
55
- │   ├── 1.krn
56
- │   ├── 2.krn
57
- │   └── 3.krn
58
- ├── more-kerns
59
- │   ├── 1.krn
60
- │   ├── ...
61
- ```
62
- Run:
63
- ```shell
64
- python -m kernpy --input_path /my/path/to/directory/ -r
65
- ```
66
-
67
- ✏️ This function is also available as a python function:
68
- ```python
69
- # converter.py
70
- from kernpy import kern_to_ekern
71
-
72
- kern_to_ekern('/my/path/to/input.krn', '/to/my/output.ekrn')
73
-
74
- # Many files
75
- files = ['file1.krn', 'file2.krn', 'file3.krn']
76
- [kern_to_ekern(f) for f in files]
77
-
78
- # This function raises an exception if the conversion fails.
79
- # Handle the errors using try-except statement if many files are going to be converted in series.
80
- ```
81
-
82
- ****************************************************************************************
83
- ## 🎯 **ekern2kern**: Convertir un solo archivo .ekern a .krn:
84
-
85
- ```bash
86
- python -m kernpy --ekern2kern --input_path <input_file> <--verbose [0-2]>
87
- ```
88
-
89
- The command has the following arguments:
90
- * **input_path**: Ruta del archivo .ekern a convertir.
91
- * **output_path**: Ruta del archivo .krn a generar (opcional). Si no se especifica, se generará en la misma ubicación.
92
- * **-r**: Recursivo (opcional).
93
- * **--verbose[0-2]**: Nivel de verbosidad (opcional).
94
-
95
- * Basic usage running **kernpy** as a module:
96
- ```shell
97
- python -m kernpy --input_path /my/path/to/file.ekern # New krn generated in /my/path/to/file.krn
98
- ```
99
-
100
- 📌 Generate a _krn_ file in specific location running **kernpy** as a module:
101
- ```shell
102
- python -m kernpy --input_path /my/path/to/file.ekern --output_path /new/output.krn
103
- ```
104
-
105
- 📌 Converting **all** the .ekern files in a directory to .krn files running **kernpy** as a module:
106
-
107
- * Every .ekrn file in the directory will be converted to .krn in the same location.
108
- * Using, at least, one additional directory level is required.
109
- ```
110
- root
111
- ├─ ekern-folder
112
- │   ├── 1.ekrn
113
- │   ├── 2.ekrn
114
- │   └── 3.ekrn
115
- ├── more-ekerns
116
- │   ├── 1.ekrn
117
- │   ├── ...
118
- ```
119
- Run:
120
- ```shell
121
- python -m kernpy --input_path /my/path/to/directory/ -r
122
- ```
123
-
124
- ✏️ This function is also available as a python function:
125
- ```python
126
- # converter.py
127
- from kernpy import ekern_to_krn
128
-
129
- # Only one file
130
- ekern_to_krn('/my/path/to/input.ekrn', '/to/my/output.krn')
131
-
132
- # Many files
133
- files = ['file1.ekrn', 'file2.ekrn', 'file3.ekrn']
134
- [ekern_to_krn(f) for f in files]
135
-
136
- # This function raises an exception if the conversion fails.
137
- # Handle the errors using try-except statement if many files are going to be converted in series.
138
- ```
139
-
140
-
141
- ****************************************************************************************
142
- ## 🎯 **create fragments**
143
- Generate new valid _kern_ files from an original _kern_ file. Every new fragment will be a subset of the original file.
144
-
145
- Explore the documentation website for more information about the parameters.
146
-
147
-
148
- Use:
149
- - **create_fragments_from_kern** to generate using always the same measure length.
150
- - **create_fragments_from_directory** to generate using a Gaussian distribution for the measure length. Static measure is also available if the standard deviation is set to 0.
151
-
152
-
153
- 📌 Create new scores from one original _kern_ directory running **kernpy** as a module:
154
- ```shell
155
- python -m kernpy --generate_fragments --input_directory /from/my/kerns --output_directory /to/my/fragments --log_file log.csv --verbose 2 --mean 4.2 --std_dev 1.5 --offset 1 --num_processes 12
156
- ```
157
-
158
-
159
- ✏️ Create new scores from one original _kern_ file:
160
- ```python
161
- # generator.py
162
- from kernpy import create_fragments_from_kern
163
-
164
- # View docs:
165
- help(create_fragments_from_kern)
166
-
167
- create_fragments_from_kern('/my/path/to/input.krn', '/to/my/output_dir/',
168
- measure_length=4, offset=1,
169
- log_file='/dev/null')
170
- ```
171
-
172
- ✏️ Create new scores from one original _kern_ directory:
173
- - Using, at least, one additional directory level is required.
174
- ```
175
- root
176
- ├─ kern-folder
177
- │   ├── 1.krn
178
- │   ├── 2.krn
179
- │   └── 3.krn
180
- ├── more-kerns
181
- │   ├── 1.krn
182
- │   ├── ...
183
- ```
184
-
185
- Run:
186
- ```python
187
- # generator.py
188
- from kernpy import create_fragments_from_directory
189
-
190
- # View docs:
191
- help(create_fragments_from_directory)
192
-
193
- create_fragments_from_directory('/my/path/to/input_dir/', '/to/my/output_dir/',
194
- mean=4.1, std_dev=0.2, offset=2,
195
- log_file='/logs/fragments.csv',
196
- num_processes=12)
197
- ```
198
-
199
-
200
-
201
16
  """
202
17
 
203
18
 
kernpy/__main__.py CHANGED
@@ -1,217 +1,127 @@
1
1
  """
2
2
  This module contains the main function for the kernpy package.
3
3
 
4
- Use the following command to run `kernpy` as a module:
5
- ```bash
6
- python -m kernpy
7
- ```
8
-
4
+ Usage:
5
+ python -m kernpy
9
6
  """
10
7
 
11
8
  import argparse
12
9
  import sys
13
- import os
10
+ from pathlib import Path
14
11
 
15
- from kernpy import polish_scores, ekern_to_krn, kern_to_ekern, create_fragments_from_directory
12
+ from kernpy import polish_scores, ekern_to_krn, kern_to_ekern
16
13
 
17
14
 
18
15
  def create_parser() -> argparse.ArgumentParser:
19
- """
20
- Create a parser for the command line arguments.
21
-
22
- Examples:
23
- >>> parser = create_parser()
24
- >>> args = parser.parse_args()
25
- >>> print(args.verbose)
26
-
27
-
28
- Returns:
29
- argparse.ArgumentParser: The parser object
30
- """
31
- parser = argparse.ArgumentParser(description="kernpy")
32
-
33
- parser.add_argument('--verbose', default=1, help='Enable verbose mode')
34
-
35
-
36
- # ekern to kern
37
- kern_parser = parser.add_argument_group('Kern Parser options')
38
- kern_parser.add_argument('--ekern2kern', action='store_true', help='Convert file from ekern to kern. [-r]')
39
- kern_parser.add_argument('--kern2ekern', action='store_true', help='Convert file from kern to ekern. [-r]')
40
-
41
- if '--ekern2kern' in sys.argv:
42
- kern_parser.add_argument('--input_path', required=True, type=str,
43
- help='Input file or directory path. Employ -r to use recursive mode')
44
- kern_parser.add_argument('--output_path', required=False, type=str, help='Output file or directory path')
45
- kern_parser.add_argument('-r', '--recursive', required=False, action='store_true', help='Recursive mode')
46
-
47
- if '--kern2ekern' in sys.argv:
48
- kern_parser.add_argument('--input_path', required=True, type=str,
49
- help='Input file or directory path. Employ -r to use recursive mode')
50
- kern_parser.add_argument('--output_path', required=False, type=str, help='Output file or directory path')
51
- kern_parser.add_argument('-r', '--recursive', required=False, action='store_true', help='Recursive mode')
52
-
53
- # Polish operations
54
- # Create a group for optional arguments
55
- polish_args = parser.add_argument_group('Polish Exporter options')
56
- polish_args.add_argument('--polish', action='store_true', help='Enable Polish Exporter')
57
- # Add the required flags, but only if --polish exists
58
- if '--polish' in sys.argv:
59
- polish_args.add_argument('--input_directory', required=True, type=str, help='Input directory path')
60
- polish_args.add_argument('--output_directory', required=True, type=str, help='Output directory path')
61
- polish_args.add_argument('--instrument', required=False, type=str, help='Instrument name')
62
- polish_args.add_argument('--kern_type', required=False, type=str, help='Kern type: "krn" or "ekrn"')
63
- polish_args.add_argument('--kern_spines_filter', required=False, type=str, help='How many kern spines scores will be exported. A number greater than 0', default=None)
64
- polish_args.add_argument('--remove_empty_dirs', required=False, action='store_true', help='Remove empty directories after exporting the scores', default=True)
65
-
66
- # Generate fragments
67
- # Create a group for optional arguments
68
- generate_fragments = parser.add_argument_group('Generate Fragments options')
69
- generate_fragments.add_argument('--generate_fragments', action='store_true', help='Enable Generate Fragments')
70
- if '--generate_fragments' in sys.argv:
71
- generate_fragments.add_argument('--input_directory', required=True, type=str, help='Input directory path')
72
- generate_fragments.add_argument('--output_directory', required=True, type=str, help='Output directory path')
73
- generate_fragments.add_argument('--log_file', required=True, type=str, help='Log file path')
74
- generate_fragments.add_argument('--check_file_extension', required=False, action='store_true', help='Check file extension', default=True)
75
- generate_fragments.add_argument('--offset', required=True, type=int, help='Offset', default=1)
76
- generate_fragments.add_argument('--num_processes', required=True, type=int, help='Number of processes')
77
- generate_fragments.add_argument('--mean', required=True, type=float, help='Mean')
78
- generate_fragments.add_argument('--std_dev', required=True, type=float, help='Standard deviation')
16
+ parser = argparse.ArgumentParser(description="kernpy CLI tool")
79
17
 
80
- return parser
18
+ parser.add_argument('--verbose', type=int, default=1, help='Verbosity level')
81
19
 
20
+ group = parser.add_mutually_exclusive_group(required=True)
21
+ group.add_argument('--ekern2kern', action='store_true', help='Convert files from ekern to kern')
22
+ group.add_argument('--kern2ekern', action='store_true', help='Convert files from kern to ekern')
23
+ group.add_argument('--polish', action='store_true', help='Run Polish Exporter')
24
+ group.add_argument('--generate_fragments', action='store_true', help='Generate Fragments')
82
25
 
83
- def handle_polish_exporter(args) -> None:
84
- """
85
- Handle the Polish options.
26
+ parser.add_argument('--input_path', type=str, help='Input file or directory')
27
+ parser.add_argument('--output_path', type=str, help='Output file or directory')
28
+ parser.add_argument('-r', '--recursive', action='store_true', help='Enable recursive directory processing')
86
29
 
87
- Args:
88
- args: The parsed arguments
30
+ # Polish Exporter
31
+ parser.add_argument('--input_directory', type=str, help='Polish: Input directory')
32
+ parser.add_argument('--output_directory', type=str, help='Polish: Output directory')
33
+ parser.add_argument('--instrument', type=str, help='Polish: Instrument name')
34
+ parser.add_argument('--kern_type', type=str, help='Polish: "krn" or "ekrn"')
35
+ parser.add_argument('--kern_spines_filter', type=str, help='Polish: Filter for number of kern spines')
36
+ parser.add_argument('--remove_empty_dirs', action='store_true', help='Polish: Remove empty directories')
89
37
 
90
- Returns:
91
- None
92
- """
93
- # TODO: Add instrument argument to download_polish_dataset.main
94
- if args.instrument:
95
- print("Instrument:", args.instrument)
96
- else:
97
- print("Instrument: Not specified")
98
38
 
99
- polish_scores.download_polish_dataset.main(
100
- input_directory=args.input_directory,
101
- output_directory=args.output_directory,
102
- kern_spines_filter=args.kern_spines_filter,
103
- exporter_kern_type=args.kern_type,
104
- remove_empty_directories=args.remove_empty_dirs
105
- )
39
+ return parser
106
40
 
107
41
 
108
- def handle_ekern2kern(args) -> None:
109
- """
110
- Handle the ekern2kern options.
42
+ def find_files(directory: Path, patterns: list[str], recursive: bool = False) -> list[Path]:
43
+ files = []
44
+ for pattern in patterns:
45
+ if recursive:
46
+ files.extend(directory.rglob(pattern))
47
+ else:
48
+ files.extend(directory.glob(pattern))
49
+ return files
111
50
 
112
- Args:
113
- args: The parsed arguments
114
51
 
115
- Returns:
116
- None
117
- """
118
- if not args.output_path:
119
- args.output_path = args.input_path.replace("ekrn", "krn")
52
+ def handle_ekern2kern(args):
53
+ input_path = Path(args.input_path)
54
+ output_path = Path(args.output_path) if args.output_path else None
120
55
 
121
- if not args.recursive:
122
- ekern_to_krn(args.input_path, args.output_path)
123
- if int(args.verbose) > 0:
124
- print(f"New kern generated in {args.output_path}")
56
+ if input_path.is_file():
57
+ out = output_path or input_path.with_suffix(".krn")
58
+ ekern_to_krn(str(input_path), str(out))
59
+ if args.verbose:
60
+ print(f"Converted: {input_path} → {out}")
125
61
  return
126
62
 
127
- # Recursive mode
128
- for root, dirs, files in os.walk(args.input_path):
129
- for directory in dirs:
130
- files = os.listdir(os.path.join(root, directory))
131
- for filename in files:
132
- if filename.endswith(".ekrn"):
133
- if int(args.verbose) > 0:
134
- print("New kern: ", os.path.join(root, directory, filename))
135
- try:
136
- ekern_to_krn(os.path.join(root, directory, filename),
137
- os.path.join(root, directory, filename.replace(".ekrn", ".krn")))
138
- except Exception as e:
139
- if int(args.verbose) > 0:
140
- print(f"An error occurred converting:{filename}:{e}", file=sys.stderr)
141
-
142
-
143
- def handle_kern2ekern(args) -> None:
144
- """
145
- Handle the kern2ekern options.
146
-
147
- Args:
148
- args: The parsed arguments
149
-
150
- Returns:
151
- None
152
- """
153
- if not args.output_path:
154
- args.output_path = args.input_path.replace("krn", "ekrn")
155
-
156
- if not args.recursive:
157
- kern_to_ekern(args.input_path, args.output_path)
158
- if int(args.verbose) > 0:
159
- print(f"New ekern generated in {args.output_path}")
63
+ files = find_files(input_path, ["*.ekrn", "*.ekern"], recursive=args.recursive)
64
+ for file in files:
65
+ out = file.with_suffix(".krn")
66
+ try:
67
+ ekern_to_krn(str(file), str(out))
68
+ if args.verbose:
69
+ print(f"Converted: {file} → {out}")
70
+ except Exception as e:
71
+ print(f"Error converting {file}: {e}", file=sys.stderr)
72
+
73
+
74
+ def handle_kern2ekern(args):
75
+ input_path = Path(args.input_path)
76
+ output_path = Path(args.output_path) if args.output_path else None
77
+
78
+ if input_path.is_file():
79
+ out = output_path or input_path.with_suffix(".ekrn")
80
+ kern_to_ekern(str(input_path), str(out))
81
+ if args.verbose:
82
+ print(f"Converted: {input_path} → {out}")
160
83
  return
161
84
 
162
- # Recursive mode
163
- for root, dirs, files in os.walk(args.input_path):
164
- for directory in dirs:
165
- files = os.listdir(os.path.join(root, directory))
166
- for filename in files:
167
- if filename.endswith(".krn"):
168
- if int(args.verbose) > 0:
169
- print("New ekern: ", os.path.join(root, directory, filename))
170
- try:
171
- kern_to_ekern(os.path.join(root, directory, filename),
172
- os.path.join(root, directory, filename.replace(".krn", ".ekrn")))
173
- except Exception as e:
174
- if int(args.verbose) > 0:
175
- print(f"An error occurred converting:{filename}:{e}", file=sys.stderr)
176
-
177
-
178
- def handle_generate_fragments(args) -> None:
179
- """
180
- Handle the generate_fragments options.
181
-
182
- Args:
183
- args: The parsed arguments
184
-
185
- Returns:
186
- None
187
- """
188
- create_fragments_from_directory(args.input_directory, args.output_directory, args.log_file,
189
- check_file_extension=args.check_file_extension, offset=args.offset,
190
- verbose=args.verbose, num_processes=args.num_processes, mean=args.mean,
191
- std_dev=args.std_dev)
85
+ files = find_files(input_path, ["*.krn", "*.kern"], recursive=args.recursive)
86
+ for file in files:
87
+ out = file.with_suffix(".ekrn")
88
+ try:
89
+ kern_to_ekern(str(file), str(out))
90
+ if args.verbose:
91
+ print(f"Converted: {file} → {out}")
92
+ except Exception as e:
93
+ print(f"Error converting {file}: {e}", file=sys.stderr)
94
+
95
+
96
+ def handle_polish_exporter(args):
97
+ if args.verbose:
98
+ print(f"Running Polish Exporter on {args.input_directory}{args.output_directory}")
99
+
100
+ polish_scores.download_polish_dataset.main(
101
+ input_directory=args.input_directory,
102
+ output_directory=args.output_directory,
103
+ kern_spines_filter=args.kern_spines_filter,
104
+ exporter_kern_type=args.kern_type,
105
+ remove_empty_directories=args.remove_empty_dirs,
106
+ )
192
107
 
193
108
 
194
109
  def main():
195
110
  parser = create_parser()
196
111
  args = parser.parse_args()
197
112
 
198
- # Accessing the values of the options
199
- if int(args.verbose) > 2:
200
- print(f"All arguments: \n{50 * '*'}")
201
- for key, value in vars(args).items():
202
- print(key, value)
203
- print(f"{50 * '*'}\n")
113
+ if args.verbose > 2:
114
+ print("Arguments:")
115
+ for key, val in vars(args).items():
116
+ print(f" {key}: {val}")
204
117
 
205
- if args.polish:
206
- handle_polish_exporter(args)
207
118
  if args.ekern2kern:
208
119
  handle_ekern2kern(args)
209
- if args.kern2ekern:
120
+ elif args.kern2ekern:
210
121
  handle_kern2ekern(args)
211
- if args.generate_fragments:
212
- handle_generate_fragments(args)
122
+ elif args.polish:
123
+ handle_polish_exporter(args)
213
124
 
214
125
 
215
126
  if __name__ == "__main__":
216
127
  main()
217
-
kernpy/core/exporter.py CHANGED
@@ -153,7 +153,7 @@ class HeaderTokenGenerator:
153
153
  """
154
154
  HeaderTokenGenerator class.
155
155
 
156
- This class is used to translate the HeaderTokens to the specific tokenizer format.
156
+ This class is used to translate the HeaderTokens to the specific encoding format.
157
157
  """
158
158
  @classmethod
159
159
  def new(cls, *, token: HeaderToken, type: Encoding):
@@ -162,7 +162,7 @@ class HeaderTokenGenerator:
162
162
 
163
163
  Args:
164
164
  token (HeaderToken): The HeaderToken to be translated.
165
- type (Encoding): The tokenizer to be used.
165
+ type (Encoding): The encoding to be used.
166
166
 
167
167
  Examples:
168
168
  >>> header = HeaderToken('**kern', 0)
kernpy/core/tokenizers.py CHANGED
@@ -18,7 +18,7 @@ class Encoding(Enum): # TODO: Eventually, polymorphism will be used to export d
18
18
  >>> doc, _ = kp.load('path/to/file.krn')
19
19
  >>>
20
20
  >>> # Save the file using the specified encoding
21
- >>> exported_content = kp.dumps(tokenizer=kp.Encoding.normalizedKern)
21
+ >>> exported_content = kp.dumps(encoding=kp.Encoding.normalizedKern)
22
22
  """
23
23
  eKern = 'ekern'
24
24
  normalizedKern = 'kern'
kernpy/io/public.py CHANGED
@@ -12,7 +12,9 @@ from kernpy import Encoding
12
12
  from kernpy.core import (
13
13
  Document, Importer, Exporter, ExportOptions, GraphvizExporter,
14
14
  generic,
15
- TokenCategoryHierarchyMapper)
15
+ TokenCategoryHierarchyMapper,
16
+ TokenCategory,
17
+ )
16
18
 
17
19
 
18
20
  def load(fp: Union[str, Path], *, raise_on_errors: Optional[bool] = False, **kwargs) -> (Document, List[str]):
@@ -84,13 +86,13 @@ def loads(s, *, raise_on_errors: Optional[bool] = False, **kwargs) -> (Document,
84
86
 
85
87
 
86
88
  def dump(document: Document, fp: Union[str, Path], *,
87
- spine_types: [] = None,
88
- include: [] = None,
89
- exclude: [] = None,
89
+ spine_types: [str] = None,
90
+ include: [TokenCategory] = None,
91
+ exclude: [TokenCategory] = None,
90
92
  from_measure: int = None,
91
93
  to_measure: int = None,
92
- tokenizer: Encoding = None,
93
- instruments: [] = None,
94
+ encoding: Encoding = None,
95
+ instruments: [str] = None,
94
96
  show_measure_numbers: bool = None,
95
97
  spine_ids: [int] = None
96
98
  ) -> None:
@@ -104,7 +106,7 @@ def dump(document: Document, fp: Union[str, Path], *,
104
106
  exclude (Iterable): The token categories to exclude from the exported file. When None, no token categories will be excluded.
105
107
  from_measure (int): The measure to start exporting. When None, the exporter will start from the beginning of the file. The first measure is 1
106
108
  to_measure (int): The measure to end exporting. When None, the exporter will end at the end of the file.
107
- tokenizer (Encoding): The type of the **kern file to export.
109
+ encoding (Encoding): The type of the **kern file to export.
108
110
  instruments (Iterable): The instruments to export. If None, all the instruments will be exported.
109
111
  show_measure_numbers (Bool): Show the measure numbers in the exported file.
110
112
  spine_ids (Iterable): The ids of the spines to export. When None, all the spines will be exported. \
@@ -130,7 +132,7 @@ def dump(document: Document, fp: Union[str, Path], *,
130
132
  exclude=exclude,
131
133
  from_measure=from_measure,
132
134
  to_measure=to_measure,
133
- kern_type=tokenizer,
135
+ kern_type=encoding,
134
136
  instruments=instruments,
135
137
  show_measure_numbers=show_measure_numbers,
136
138
  spine_ids=spine_ids
@@ -144,13 +146,13 @@ def dump(document: Document, fp: Union[str, Path], *,
144
146
 
145
147
 
146
148
  def dumps(document: Document, *,
147
- spine_types: [] = None,
148
- include: [] = None,
149
- exclude: [] = None,
149
+ spine_types: [str] = None,
150
+ include: [TokenCategory] = None,
151
+ exclude: [TokenCategory] = None,
150
152
  from_measure: int = None,
151
153
  to_measure: int = None,
152
- tokenizer: Encoding = None,
153
- instruments: [] = None,
154
+ encoding: Encoding = None,
155
+ instruments: [str] = None,
154
156
  show_measure_numbers: bool = None,
155
157
  spine_ids: [int] = None
156
158
  ) -> str:
@@ -164,7 +166,7 @@ def dumps(document: Document, *,
164
166
  exclude (Iterable): The token categories to exclude from the exported file. When None, no token categories will be excluded.
165
167
  from_measure (int): The measure to start exporting. When None, the exporter will start from the beginning of the file. The first measure is 1
166
168
  to_measure (int): The measure to end exporting. When None, the exporter will end at the end of the file.
167
- tokenizer (Encoding): The type of the **kern file to export.
169
+ encoding (Encoding): The type of the **kern file to export.
168
170
  instruments (Iterable): The instruments to export. If None, all the instruments will be exported.
169
171
  show_measure_numbers (Bool): Show the measure numbers in the exported file.
170
172
  spine_ids (Iterable): The ids of the spines to export. When None, all the spines will be exported. \
@@ -189,7 +191,7 @@ def dumps(document: Document, *,
189
191
  exclude=exclude,
190
192
  from_measure=from_measure,
191
193
  to_measure=to_measure,
192
- kern_type=tokenizer,
194
+ kern_type=encoding,
193
195
  instruments=instruments,
194
196
  show_measure_numbers=show_measure_numbers,
195
197
  spine_ids=spine_ids
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kernpy
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Python Humdrum **kern and **mens utilities
5
5
  Project-URL: Homepage, https://github.com/OMR-PRAIG-UA-ES/kernpy
6
6
  Project-URL: Documentation, https://github.com/OMR-PRAIG-UA-ES/kernpy#readme
@@ -19,9 +19,18 @@ Description-Content-Type: text/markdown
19
19
 
20
20
  # Python Humdrum **kern and **mens utilities
21
21
 
22
- ## Documentation: <a target="_blank" href="https://kernpy.pages.dev/">https://kernpy.pages.dev/</a>
22
+ [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/agpl-3.0)
23
+ ![Python Version](https://img.shields.io/badge/Python-3.9+-3776AB?logo=python&logoColor=white&style=for-the-badge)
24
+ [![PyPI](https://img.shields.io/pypi/v/kernpy?color=brightgreen&label=PyPI&style=for-the-badge&logo=pypi)](https://pypi.org/project/kernpy/)
25
+ [![Docs](https://img.shields.io/badge/docs-available-blue?style=for-the-badge&logo=readthedocs)](https://kernpy.pages.dev)
26
+ [![Tests](https://img.shields.io/badge/tests-passing-brightgreen?style=for-the-badge&logo=pytest)](https://github.com/kernpy/kernpy/actions)
27
+ [![Contributions welcome](https://img.shields.io/badge/contributions-welcome-orange?style=for-the-badge&logo=github)](CONTRIBUTING.md)
23
28
 
24
- ![kernpy logo](https://static.wixstatic.com/media/7a8a67_90be144dbf384480908c3327b93ba97a~mv2.jpg/v1/fill/w_461,h_354,fp_0.46_0.20,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/mending-the-sail-1896_jpg!Large.jpg)
29
+
30
+ Python package that provides comprehensive tools for working with symbolic modern and mensural notations in Humdrum format. kernpy is a fully open-source project open to contributions.
31
+
32
+ ## Documentation
33
+ Visit the online website: <a target="_blank" href="https://kernpy.pages.dev/">https://kernpy.pages.dev/</a>
25
34
 
26
35
  ## Index:
27
36
  - [Code examples](#code-examples)
@@ -71,18 +80,74 @@ Only use the specified spines in `spine_types`.
71
80
  ```python
72
81
  import kernpy as kp
73
82
 
83
+ # only export the **kern spines
74
84
  kp.dump(document, "newfile_core.krn",
75
85
  spine_types=['**kern'])
86
+
87
+ # only export the **text spines
76
88
  kp.dump(document, "newfile_lyrics.krn",
77
89
  spine_types=['**text])
90
+
91
+ # only export **kern and **text spines
78
92
  kp.dump(document, "newfile_core_and_lyrics.krn",
79
93
  spine_types=['*+text'])
80
94
  ```
81
95
 
96
+ - The categories are hierarchically defined in the `TokenCategory` class.
97
+ See the hierarchy as a tree
98
+ ```python
99
+ import kernpy as kp
100
+
101
+
102
+ print(kp.TokenCategory.tree())
103
+ ```
104
+ Tree:
105
+ ```txt
106
+ .
107
+ ├── STRUCTURAL
108
+ │ ├── HEADER
109
+ │ └── SPINE_OPERATION
110
+ ├── CORE
111
+ │ ├── NOTE_REST
112
+ │ │ ├── DURATION
113
+ │ │ ├── NOTE
114
+ │ │ │ ├── PITCH
115
+ │ │ │ ├── DECORATION
116
+ │ │ │ └── ALTERATION
117
+ │ │ └── REST
118
+ │ ├── CHORD
119
+ │ ├── EMPTY
120
+ │ └── ERROR
121
+ ├── SIGNATURES
122
+ │ ├── CLEF
123
+ │ ├── TIME_SIGNATURE
124
+ │ ├── METER_SYMBOL
125
+ │ ├── KEY_SIGNATURE
126
+ │ └── KEY_TOKEN
127
+ ├── ENGRAVED_SYMBOLS
128
+ ├── OTHER_CONTEXTUAL
129
+ ├── BARLINES
130
+ ├── COMMENTS
131
+ │ ├── FIELD_COMMENTS
132
+ │ └── LINE_COMMENTS
133
+ ├── DYNAMICS
134
+ ├── HARMONY
135
+ ├── FINGERING
136
+ ├── LYRICS
137
+ ├── INSTRUMENTS
138
+ ├── IMAGE_ANNOTATIONS
139
+ │ ├── BOUNDING_BOXES
140
+ │ └── LINE_BREAK
141
+ ├── OTHER
142
+ ├── MHXM
143
+ └── ROOT
144
+ ```
145
+
82
146
  - Use `include` for selecting the **kern semantic categories **to use**. The output only contains what is passed. By default, all the categories are included.
83
147
  ```python
84
148
  import kernpy as kp
85
149
 
150
+
86
151
  kp.dump(document, "newfile_only_clefs.krn",
87
152
  include={kp.TokenCategory.CLEF})
88
153
  kp.dump(document, "newfile_only_durations_and_bounding_boxes.krn",
@@ -104,34 +169,37 @@ import kernpy as kp
104
169
  kp.dump(document, "newfile_custom.krn",
105
170
  include=kp.BEKERN_CATEGORIES, # Preloaded set of simple categories
106
171
  exclude={kp.TokenCategory.PITCH})
172
+
173
+ # Inspect the BEKERN preloaded categories
174
+ print(kp.BEKERN_CATEGORIES)
107
175
  ```
108
176
 
109
- - Use `tokenizer` to select how the categories are split. By default, the `normalizedKern` tokenizer is used.
177
+ - Use `encoding` to select how the categories are split. By default, the `normalizedKern` encoding is used.
110
178
 
111
179
  ```python
112
180
  import kernpy as kp
113
181
 
114
182
  kp.dump(document, "newfile_normalized.krn",
115
- tokenizer=kp.Encoding.normalizedKern) # Default tokenizer
183
+ encoding=kp.Encoding.normalizedKern) # Default encoding
116
184
  ```
117
- Select the proper Humdrum **kern tokenizer:
185
+ Select the proper Humdrum **kern encoding:
118
186
 
119
- `kernpy` provides different tokenizers to export the content each symbol in different formats.
187
+ `kernpy` provides different encodings to export the content each symbol in different formats.
120
188
 
121
- | Encoding | Tokenized | Description |
189
+ | Encoding | Output | Description |
122
190
  |----------|--------------|----------------------------------------|
123
191
  | kern | 2.bb-_L | Traditional Humdrum **kern encoding |
124
192
  | ekern | 2@.@bb@-·_·L | Extended Humdrum **kern encoding |
125
193
 
126
- Use the `Encoding` enum class to select the tokenizer:
194
+ Use the `Encoding` enum class to select the encoding:
127
195
 
128
196
  ```python
129
197
  import kernpy as kp
130
198
 
131
199
  doc, _ = kp.load('resource_dir/legacy/chor048.krn')
132
200
 
133
- kern_content = kp.dumps(doc, tokenizer=kp.Encoding.normalizedKern)
134
- ekern_content = kp.dumps(doc, tokenizer=kp.Encoding.eKern)
201
+ kern_content = kp.dumps(doc, encoding=kp.Encoding.normalizedKern)
202
+ ekern_content = kp.dumps(doc, encoding=kp.Encoding.eKern)
135
203
  ```
136
204
 
137
205
  - Use `from_measure` and `to_measure` to select the measures to export. By default, all the measures are exported.
@@ -168,7 +236,7 @@ kp.dump(document, "newfile.krn",
168
236
  spine_types=['**kern'], # Export only the **kern spines
169
237
  include=kp.BEKERN_CATEGORIES, # Token categories to include
170
238
  exclude={kp.TokenCategory.PITCH}, # Token categories to exclude
171
- tokenizer=kp.Encoding.eKern, # Kern encoding
239
+ encoding=kp.Encoding.eKern, # Kern encoding
172
240
  from_measure=1, # First from measure 1
173
241
  to_measure=10, # Last measure exported
174
242
  spine_ids=[0, 1], # Export only the first and the second spine
@@ -271,7 +339,7 @@ for page_label, bounding_box_measure in doc.page_bounding_boxes.items():
271
339
  kp.dump(doc, f"foo_{page_label}.ekrn",
272
340
  spine_types=['**kern'],
273
341
  token_categories=kp.BEKERN_CATEGORIES,
274
- tokenizer=kp.Encoding.eKern,
342
+ encoding=kp.Encoding.eKern,
275
343
  from_measure=bounding_box_measure.from_measure,
276
344
  to_measure=bounding_box_measure.to_measure - 1 # TODO: Check bounds
277
345
  )
@@ -382,8 +450,10 @@ kp.graph(document, '/tmp/graph.dot')
382
450
  ### Production version:
383
451
  Just install the last version of **kernpy** using pip:
384
452
  ```shell
385
- pip3 uninstall kernpy # Uninstall the previous version before installing the new one
386
- pip3 install git+https://github.com/OMR-PRAIG-UA-ES/kernpy.git
453
+ pip3 install kernpy
454
+
455
+ # ensure you have the latest version
456
+ pip3 install kernpy --upgrade
387
457
  ```
388
458
 
389
459
  > [!NOTE]
@@ -391,55 +461,6 @@ pip3 install git+https://github.com/OMR-PRAIG-UA-ES/kernpy.git
391
461
 
392
462
  <hr>
393
463
 
394
- ### Development version:
395
-
396
- > [!IMPORTANT]
397
- > - Add the development dependencies to the `requirements.txt` file.
398
- > - Add the production dependencies to the `pyproject.toml` file.
399
- > - After every change in the grammar, the next steps are mandatory:
400
- > - - Run the `antlr4.sh` script (JAVA required).
401
- > - - Commit & push the changes to the repository.
402
-
403
-
404
- - Generate antrl4 grammar:
405
- - For generating the Python code required for parsing the **kern files, the shell script `antlr4.sh` inside the `kernpy` package must be run.
406
-
407
- ```shell
408
- ./antlr4.sh
409
- ```
410
-
411
- Install all the dependencies using the `requirements.txt` file:
412
- ```shell
413
- pip install -r requirements.txt
414
- ```
415
-
416
- Otherwise, install the required packages manually:
417
-
418
-
419
- - It requires the `antlr4` package to be installed using:
420
- ```shell
421
- pip install antlr4-python3-runtime
422
- ```
423
-
424
-
425
- - For visualizing the bounding boxes, the library, the `Pillow` library is required:
426
- ```shell
427
- pip install Pillow
428
- ```
429
-
430
- - To parse a IIIF (International Image Interoperability Framework) manifest in Python, we use the `requests` library to fetch the manifest file:
431
- ```shell
432
- pip install requests
433
- ```
434
-
435
- - If fetching data from `https` fails, install the following version of `urllib`:
436
- ```shell
437
- pip install urllib3==1.26.6
438
- ```
439
-
440
- It has been tested with version 4.13.1 of the package.
441
-
442
-
443
464
  ## Documentation
444
465
  Documentation available at [https://kernpy.pages.dev/](https://kernpy.pages.dev/)
445
466
 
@@ -461,32 +482,7 @@ cd tests && python -m pytest
461
482
 
462
483
  We welcome contributions from the community! If you'd like to contribute to the project, please follow these steps:
463
484
 
464
- 1. Fork the Repository from GitHub.
465
- 2. Clone your own fork repository.
466
- ```bash
467
- git clone ...
468
- cd ...
469
- ```
470
- 3. Create a Branch:
471
- 4. Create a new branch for your feature or bug fix:
472
- ```bash
473
- git checkout -b feature/your-feature-name
474
- ```
475
- 5. Commit Your Changes:
476
- Commit your changes with a descriptive message:
477
- ```bash
478
- git commit -m "feat: add your feature or fix"
479
- ```
480
-
481
- 6. Push to Your Branch:
482
- Push your changes to your forked repository:
483
- ```bash
484
- git push origin feature/your-feature-name
485
- ```
486
-
487
- 7. Create a Pull Request:
488
- Open a pull request to the main repository, describing your changes.
489
-
485
+ Go to the file [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to contribute.
490
486
 
491
487
  ## Citation:
492
488
  ```bibtex
@@ -1,5 +1,5 @@
1
- kernpy/__init__.py,sha256=h1o3Z_Xk7nZdE4fBu7uLx6V6nR4M3LySi36ONj73sOo,5998
2
- kernpy/__main__.py,sha256=ayuovsnyTaTrhcyOM1kFBoSXGjT1QALwIMcJ_NOqVkM,8495
1
+ kernpy/__init__.py,sha256=HdHS0T3se8qIU0d2mULhwhgJRfgGmNA4Zhxl4YvjeVA,313
2
+ kernpy/__main__.py,sha256=ZxsPlyfgzpZjU8TdNBc1SrMyTTr-Osu4j08DXHAgpVQ,4437
3
3
  kernpy/test_grammar.sh,sha256=MP9Hav9nPxTbHeofFEuunwDsLcBoeFRtzPp4bbPnqBU,520
4
4
  kernpy/visualize_analysis.sh,sha256=z68jyZ8zj4w7v5CoC8-J7PGh7dYA_iQbuFL5T63X6qY,526
5
5
  kernpy/core/__init__.py,sha256=gIbOKMWcPcQc4c6QpslWnAw9XkcMJ6OvedHANyDABbs,2581
@@ -11,7 +11,7 @@ kernpy/core/document.py,sha256=Y_Wpwc-t1GkaGr2QVU0hqLRFJv9wJ_Nm6UitgwAlT8w,34892
11
11
  kernpy/core/dyn_importer.py,sha256=dKgZqVIdEELUu8HY63ClLJAMQXXItjHmaYxxOwFZRiY,1025
12
12
  kernpy/core/dynam_spine_importer.py,sha256=crg4LwsWr56VZ6GLYAO1CDnLuum9f1tlX_pXCqKemEc,1450
13
13
  kernpy/core/error_listener.py,sha256=bTlAZvVIQx_6BLZ3oRut_pn24JnV8_7GnNONiwoMMPU,1516
14
- kernpy/core/exporter.py,sha256=5MWOk1JmPtpXfjN_VBv5jxUhYu8hhAZwt9eB5u9f1eM,21371
14
+ kernpy/core/exporter.py,sha256=t2Ep-qe_r1CvEmPb3KoMpzHd2W3SfEcjY8XhFOUqGxs,21369
15
15
  kernpy/core/fing_spine_importer.py,sha256=5GLPPakmZVRcNbbaoCn1p1cQdat5QttflbpKu3AytQU,1382
16
16
  kernpy/core/generic.py,sha256=9OTDE2t49laVk6fgtydK5yZh7SCfZwViP_dZUJlskA8,10967
17
17
  kernpy/core/gkern.py,sha256=nRYFLFJ0uOLJwio0DKxQ0YIqLixy6-qCM-eY8DNdxfM,16332
@@ -27,7 +27,7 @@ kernpy/core/pitch_models.py,sha256=TpSt1uxGYhbhXs0viB1dNo4jiGxyCOHWseyRHTpfH-0,9
27
27
  kernpy/core/root_spine_importer.py,sha256=w7oFbMeXakHF9OAlgKWm_HaGJoNq6u7BE_JUnvLiLnU,1893
28
28
  kernpy/core/spine_importer.py,sha256=_VoWcVGfDMhxDn-hCu18g_29Aw2c2bjLnaXuvW2Fbsc,1430
29
29
  kernpy/core/text_spine_importer.py,sha256=mz1qX2nviJs0VsGsN87jk6BVWCIE7mmB9IxEx4RdhT8,1522
30
- kernpy/core/tokenizers.py,sha256=dJsaCdPStruzToaYA-RyM9beJ9tQyZRjM4qKLK0d0k4,7899
30
+ kernpy/core/tokenizers.py,sha256=-m-isPSvWbikTLj5pfzG-4UCLrjxPfqHJD7s4znLHCo,7898
31
31
  kernpy/core/tokens.py,sha256=0XhbYm6F9NDfYpP5gbrgzZL3qB_xWs74faTwAZghpyM,66515
32
32
  kernpy/core/transposer.py,sha256=EqsEy7Z3bWIXdxUTruBrg8z9sWdJ3Cd_KIzo_6ZuNNA,9352
33
33
  kernpy/core/generated/kernSpineLexer.interp,sha256=Y3_seqmHQu3czO9fHE8XtRwTrk8g4Txf0IKiMaHBqeg,28801
@@ -39,13 +39,13 @@ kernpy/core/generated/kernSpineParser.tokens,sha256=ciGB91o4t7VM-tgSLtGB-BUFzHNo
39
39
  kernpy/core/generated/kernSpineParserListener.py,sha256=fcOPxYkGbNbIw8Qk9aqYXnuTB48WWJCn_ZYxTdoFtpY,40015
40
40
  kernpy/core/generated/kernSpineParserVisitor.py,sha256=YSEdcb4kuIi-E4rAFhDKsCVu0lyPdlqrCMtQAeVDhZY,23821
41
41
  kernpy/io/__init__.py,sha256=9103cE_Ao1tu2mi4EaFni-YmnCnwtJqQqFqgeFuT7rA,147
42
- kernpy/io/public.py,sha256=p5f22Vse54vU3QYDBn5Z5iJXhRLrF9OTG1MYD8QhdGc,13782
42
+ kernpy/io/public.py,sha256=ge7A2N77efVG5dMpLDH2jxtkVi_2EOq-TnhDggyg9vQ,13861
43
43
  kernpy/polish_scores/__init__.py,sha256=EjILt5N5T9cKKdhWwflS_MU4TXuLhdHOYhW8txaicrI,217
44
44
  kernpy/polish_scores/download_polish_dataset.py,sha256=VqACpxDiM1yQYDs4QHHlZ87ZW2gkjl6R_bxYh5E67K4,14633
45
45
  kernpy/polish_scores/iiif.py,sha256=yITdrQbMsGmm8qag8TSousjCjS2io148Jk9xwEKa3B4,1526
46
46
  kernpy/util/__init__.py,sha256=dfW3nRSMkGQS7p7YebM271_0H8_pVw4IiDKeINs_LI8,152
47
47
  kernpy/util/helpers.py,sha256=Xbj3nWNyErdOpLHYd4uVyfwleXvmC5_FlYEhxaeTtS8,1549
48
48
  kernpy/util/store_cache.py,sha256=AA7SFCGQ6ryy-c02wbLy8gIQ2C-VdM1JSWFoWIK_KLA,1186
49
- kernpy-1.0.0.dist-info/METADATA,sha256=D2maG9kcRvqxzIO02G6gjx4IecAZtUlfZDoT58rQJOo,14888
50
- kernpy-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- kernpy-1.0.0.dist-info/RECORD,,
49
+ kernpy-1.0.2.dist-info/METADATA,sha256=Uj7S-i6JIAMSEA4eyc-PTACGQX-hch51Ze2fnOJH1C4,15085
50
+ kernpy-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
+ kernpy-1.0.2.dist-info/RECORD,,
File without changes