pyrekordbox 0.2.1__py3-none-any.whl → 0.2.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.
Files changed (71) hide show
  1. docs/source/formats/anlz.md +178 -7
  2. docs/source/formats/db6.md +1 -1
  3. docs/source/index.md +2 -6
  4. docs/source/quickstart.md +68 -45
  5. docs/source/tutorial/index.md +1 -1
  6. pyrekordbox/__init__.py +1 -1
  7. pyrekordbox/_version.py +2 -2
  8. pyrekordbox/anlz/file.py +39 -0
  9. pyrekordbox/anlz/structs.py +3 -5
  10. pyrekordbox/config.py +71 -27
  11. pyrekordbox/db6/database.py +260 -33
  12. pyrekordbox/db6/registry.py +22 -0
  13. pyrekordbox/db6/tables.py +3 -4
  14. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/METADATA +12 -11
  15. pyrekordbox-0.2.2.dist-info/RECORD +80 -0
  16. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/top_level.txt +0 -2
  17. tests/test_config.py +175 -0
  18. tests/test_db6.py +78 -0
  19. build/lib/build/lib/docs/source/conf.py +0 -178
  20. build/lib/build/lib/pyrekordbox/__init__.py +0 -22
  21. build/lib/build/lib/pyrekordbox/__main__.py +0 -204
  22. build/lib/build/lib/pyrekordbox/_version.py +0 -16
  23. build/lib/build/lib/pyrekordbox/anlz/__init__.py +0 -127
  24. build/lib/build/lib/pyrekordbox/anlz/file.py +0 -186
  25. build/lib/build/lib/pyrekordbox/anlz/structs.py +0 -299
  26. build/lib/build/lib/pyrekordbox/anlz/tags.py +0 -508
  27. build/lib/build/lib/pyrekordbox/config.py +0 -596
  28. build/lib/build/lib/pyrekordbox/db6/__init__.py +0 -45
  29. build/lib/build/lib/pyrekordbox/db6/aux_files.py +0 -213
  30. build/lib/build/lib/pyrekordbox/db6/database.py +0 -1808
  31. build/lib/build/lib/pyrekordbox/db6/registry.py +0 -304
  32. build/lib/build/lib/pyrekordbox/db6/tables.py +0 -1618
  33. build/lib/build/lib/pyrekordbox/logger.py +0 -23
  34. build/lib/build/lib/pyrekordbox/mysettings/__init__.py +0 -32
  35. build/lib/build/lib/pyrekordbox/mysettings/file.py +0 -369
  36. build/lib/build/lib/pyrekordbox/mysettings/structs.py +0 -282
  37. build/lib/build/lib/pyrekordbox/utils.py +0 -162
  38. build/lib/build/lib/pyrekordbox/xml.py +0 -1294
  39. build/lib/build/lib/tests/__init__.py +0 -3
  40. build/lib/build/lib/tests/test_anlz.py +0 -206
  41. build/lib/build/lib/tests/test_db6.py +0 -1039
  42. build/lib/build/lib/tests/test_mysetting.py +0 -203
  43. build/lib/build/lib/tests/test_xml.py +0 -629
  44. build/lib/docs/source/conf.py +0 -178
  45. build/lib/pyrekordbox/__init__.py +0 -22
  46. build/lib/pyrekordbox/__main__.py +0 -204
  47. build/lib/pyrekordbox/_version.py +0 -16
  48. build/lib/pyrekordbox/anlz/__init__.py +0 -127
  49. build/lib/pyrekordbox/anlz/file.py +0 -186
  50. build/lib/pyrekordbox/anlz/structs.py +0 -299
  51. build/lib/pyrekordbox/anlz/tags.py +0 -508
  52. build/lib/pyrekordbox/config.py +0 -596
  53. build/lib/pyrekordbox/db6/__init__.py +0 -45
  54. build/lib/pyrekordbox/db6/aux_files.py +0 -213
  55. build/lib/pyrekordbox/db6/database.py +0 -1808
  56. build/lib/pyrekordbox/db6/registry.py +0 -304
  57. build/lib/pyrekordbox/db6/tables.py +0 -1618
  58. build/lib/pyrekordbox/logger.py +0 -23
  59. build/lib/pyrekordbox/mysettings/__init__.py +0 -32
  60. build/lib/pyrekordbox/mysettings/file.py +0 -369
  61. build/lib/pyrekordbox/mysettings/structs.py +0 -282
  62. build/lib/pyrekordbox/utils.py +0 -162
  63. build/lib/pyrekordbox/xml.py +0 -1294
  64. build/lib/tests/__init__.py +0 -3
  65. build/lib/tests/test_anlz.py +0 -206
  66. build/lib/tests/test_db6.py +0 -1039
  67. build/lib/tests/test_mysetting.py +0 -203
  68. build/lib/tests/test_xml.py +0 -629
  69. pyrekordbox-0.2.1.dist-info/RECORD +0 -129
  70. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/LICENSE +0 -0
  71. {pyrekordbox-0.2.1.dist-info → pyrekordbox-0.2.2.dist-info}/WHEEL +0 -0
@@ -1,178 +0,0 @@
1
- # Configuration file for the Sphinx documentation builder.
2
- #
3
- # This file only contains a selection of the most common options. For a full
4
- # list see the documentation:
5
- # https://www.sphinx-doc.org/en/master/usage/configuration.html
6
-
7
- # -- Path setup --------------------------------------------------------------
8
-
9
- # If extensions (or modules to document with autodoc) are in another directory,
10
- # add these directories to sys.path here. If the directory is relative to the
11
- # documentation root, use os.path.abspath to make it absolute, like shown here.
12
- #
13
- import os
14
- import sys
15
-
16
- sys.path.insert(0, os.path.abspath("../.."))
17
-
18
- import pyrekordbox
19
-
20
-
21
- # -- Project information -----------------------------------------------------
22
-
23
- project = "pyrekordbox"
24
- copyright = "2022-2023, Dylan Jones"
25
- author = "Dylan L. Jones"
26
- release = pyrekordbox.__version__
27
- version = release
28
- for sp in "abcfr":
29
- version = version.split(sp)[0]
30
-
31
- # -- General configuration ---------------------------------------------------
32
-
33
- # If your documentation needs a minimal Sphinx version, state it here.
34
- needs_sphinx = "4.4"
35
-
36
- # Add any Sphinx extension module names here, as strings. They can be
37
- # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
38
- # ones.
39
- extensions = [
40
- "sphinx.ext.autodoc",
41
- "numpydoc",
42
- "myst_parser",
43
- "numpydoc",
44
- "sphinx_copybutton",
45
- "sphinx.ext.napoleon",
46
- "sphinx.ext.autosummary",
47
- "sphinx.ext.autosectionlabel",
48
- "matplotlib.sphinxext.plot_directive",
49
- "sphinx.ext.intersphinx", # links to numpy, scipy ... docs
50
- "sphinx.ext.coverage",
51
- "sphinx.ext.extlinks", # define roles for links
52
- "sphinx.ext.viewcode",
53
- ]
54
-
55
- # If you need extensions of a certain version or higher, list them here.
56
- needs_extensions = {"myst_parser": "0.13.7"}
57
-
58
- # Add any paths that contain templates here, relative to this directory.
59
- templates_path = ["_templates"]
60
-
61
- # List of patterns, relative to source directory, that match files and
62
- # directories to ignore when looking for source files.
63
- # This pattern also affects html_static_path and html_extra_path.
64
-
65
- exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "tests"]
66
-
67
- # The suffix(es) of source filenames.
68
- # You can specify multiple suffix as a list of string:
69
- source_suffix = [".rst", ".md"]
70
-
71
- # Add any paths that contain custom static files (such as style sheets) here,
72
- # relative to this directory. They are copied after the builtin static files,
73
- # so a file named "default.css" will overwrite the builtin "default.css".
74
- html_static_path = ["_static"]
75
-
76
- html_theme_options = {
77
- "light_logo": "logos/dark/logo_primary.svg",
78
- "dark_logo": "logos/light/logo_primary.svg",
79
- "sidebar_hide_name": True,
80
- "footer_icons": [
81
- {
82
- "name": "GitHub",
83
- "url": "https://github.com/dylanljones/pyrekordbox",
84
- "html": """
85
- <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
86
- <path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
87
- </svg>
88
- """,
89
- "class": "",
90
- },
91
- ],
92
- }
93
-
94
- # html_title = f"{release} documentation"
95
-
96
- # -- Options for HTML output -------------------------------------------------
97
-
98
- # The theme to use for HTML and HTML Help pages. See the documentation for
99
- # a list of builtin themes.
100
- html_theme = "furo"
101
-
102
- # The name of the Pygments (syntax highlighting) style to use.
103
- # pygments_style = "sphinx"
104
- # pygments_dark_style = "monokai"
105
-
106
- # We need headers to be linkable to so ask MyST-Parser to autogenerate anchor IDs for
107
- # headers up to and including level 3.
108
- myst_heading_anchors = 3
109
-
110
- # Prettier support formatting some MyST syntax but not all, so let's disable the
111
- # unsupported yet still enabled by default ones.
112
- myst_disable_syntax = [
113
- "colon_fence",
114
- "myst_block_break",
115
- "myst_line_comment",
116
- "math_block",
117
- ]
118
-
119
-
120
- # Don't show type hints
121
- autodoc_typehints = "none"
122
-
123
- # Preserve order
124
- autodoc_member_order = "bysource"
125
-
126
-
127
- # -- Apidoc ------------------------------------------------------------------
128
-
129
- add_module_names = True
130
-
131
-
132
- # -- Autosummary -------------------------------------------------------------
133
-
134
- autosummary_generate = True
135
- # autosummary_imported_members = True
136
-
137
-
138
- # -- Numpy extension ---------------------------------------------------------
139
-
140
- numpydoc_use_plots = True
141
- # numpydoc_xref_param_type = True
142
- # numpydoc_xref_ignore = "all" # not working...
143
- numpydoc_show_class_members = False
144
-
145
-
146
- # -- Intersphinx -------------------------------------------------------------
147
-
148
- # taken from https://gist.github.com/bskinn/0e164963428d4b51017cebdb6cda5209
149
- intersphinx_mapping = {
150
- "python": (r"https://docs.python.org", None),
151
- "numpy": (r"https://docs.scipy.org/doc/numpy/", None),
152
- "np": (r"https://docs.scipy.org/doc/numpy/", None),
153
- "matplotlib": (r"https://matplotlib.org/", None),
154
- "<name>": ("https://docs.python.org/3/", None),
155
- }
156
-
157
-
158
- # -- Auto-run sphinx-apidoc --------------------------------------------------
159
-
160
-
161
- def run_apidoc(_):
162
- from sphinx.ext.apidoc import main
163
- import os
164
- import sys
165
-
166
- sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
167
- cur_dir = os.path.abspath(os.path.dirname(__file__))
168
- proj_dir = os.path.dirname(os.path.dirname(cur_dir))
169
- doc_dir = os.path.join(proj_dir, "docs")
170
- output_path = os.path.join(doc_dir, "source", "generated")
171
- module = os.path.join(proj_dir, "pyrekordbox")
172
- exclude = os.path.join(module, "tests")
173
- template_dir = os.path.join(doc_dir, "source", "_templates", "apidoc")
174
- main(["-fMeT", "-o", output_path, module, exclude, "--templatedir", template_dir])
175
-
176
-
177
- def setup(app):
178
- app.connect("builder-inited", run_apidoc)
@@ -1,22 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2022-04-10
4
-
5
- from .logger import logger
6
- from .config import show_config, get_config
7
- from .xml import RekordboxXml, XmlDuplicateError, XmlAttributeKeyError
8
- from .anlz import get_anlz_paths, walk_anlz_paths, read_anlz_files, AnlzFile
9
- from .mysettings import (
10
- get_mysetting_paths,
11
- read_mysetting_file,
12
- MySettingFile,
13
- MySetting2File,
14
- DjmMySettingFile,
15
- DevSettingFile,
16
- )
17
- from .db6 import Rekordbox6Database, open_rekordbox_database
18
-
19
- try:
20
- from ._version import version as __version__
21
- except ImportError: # pragma: no cover
22
- __version__ = "unknown"
@@ -1,204 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2023-08-15
4
-
5
- import os
6
- import re
7
- import sys
8
- import shutil
9
- import urllib.request
10
- from pathlib import Path
11
- from pyrekordbox.config import write_db6_key_cache, _cache_file
12
-
13
- KEY_SOURCES = [
14
- {
15
- "url": r"https://raw.githubusercontent.com/mganss/CueGen/19878e6eb3f586dee0eb3eb4f2ce3ef18309de9d/CueGen/Generator.cs", # noqa: E501
16
- "regex": re.compile(
17
- r'((.|\n)*)Config\.UseSqlCipher.*\?.*"(?P<dp>.*)".*:.*null',
18
- flags=re.IGNORECASE | re.MULTILINE,
19
- ),
20
- },
21
- {
22
- "url": r"https://raw.githubusercontent.com/dvcrn/go-rekordbox/8be6191ba198ed7abd4ad6406d177ed7b4f749b5/cmd/getencryptionkey/main.go", # noqa: E501
23
- "regex": re.compile(
24
- r'((.|\n)*)fmt\.Print\("(?P<dp>.*)"\)', flags=re.IGNORECASE | re.MULTILINE
25
- ),
26
- },
27
- ]
28
-
29
-
30
- class WorkingDir:
31
- def __init__(self, path):
32
- self._prev = Path.cwd()
33
- self.path = Path(path)
34
-
35
- def __enter__(self):
36
- if self.path != self._prev:
37
- self.path.mkdir(parents=True, exist_ok=True)
38
- os.chdir(self.path)
39
-
40
- def __exit__(self, exc_type, exc_val, exc_tb):
41
- if self.path != self._prev:
42
- os.chdir(self._prev)
43
-
44
-
45
- def clone_repo(https_url: str) -> Path:
46
- path = Path.cwd() / https_url.split("/")[-1]
47
- if not path.exists():
48
- os.system(f"git clone {https_url}")
49
- assert path.exists()
50
- else:
51
- print(f"Repository {https_url} already cloned")
52
- return path
53
-
54
-
55
- def clone_pysqlcipher3() -> Path:
56
- return clone_repo(r"https://github.com/coleifer/sqlcipher3")
57
-
58
-
59
- def clone_sqlcipher_amalgamation() -> Path:
60
- return clone_repo(r"https://github.com/geekbrother/sqlcipher-amalgamation")
61
-
62
-
63
- def patch_pysqlcipher_setup(pysqlcipher_dir, cryptolib="libcrypto.lib"):
64
- path = Path(pysqlcipher_dir, "setup.py")
65
-
66
- with open(path, "r") as fh:
67
- text = fh.read()
68
-
69
- if cryptolib:
70
- lib_old = "os.environ.get('OPENSSL_LIBNAME') or 'libeay32.lib'"
71
- lib_new = f"os.environ.get('OPENSSL_LIBNAME') or '{cryptolib}'"
72
- text = text.replace(lib_old, lib_new)
73
-
74
- with open(path, "w") as fh:
75
- fh.write(text)
76
-
77
-
78
- def prepare_pysqlcipher(pysqlcipher_dir: Path, amalgamation_src: Path):
79
- # Copy amalgamation files to pysqlcipher directory
80
- root = pysqlcipher_dir
81
- root.mkdir(parents=True, exist_ok=True)
82
- shutil.copy2(amalgamation_src / "sqlite3.c", root / "sqlite3.c")
83
- shutil.copy2(amalgamation_src / "sqlite3.h", root / "sqlite3.h")
84
-
85
-
86
- def install_pysqlcipher(
87
- tmpdir="pysqlcipher3",
88
- crypto_lib="libcrypto.lib",
89
- pyexecutable="",
90
- build=True,
91
- install=True,
92
- cleanup=True,
93
- ):
94
- if sys.platform != "win32":
95
- print("Not on Windows, aborting...")
96
- return
97
-
98
- tmpdir = Path(tmpdir)
99
- # Download pysqlcipher3 and prepare amalgamation build
100
- with WorkingDir(tmpdir):
101
- pysqlcipher_dir = clone_pysqlcipher3()
102
- amalgamation_dir = clone_sqlcipher_amalgamation()
103
- amalgamation_src = amalgamation_dir / "src"
104
-
105
- prepare_pysqlcipher(pysqlcipher_dir, amalgamation_src)
106
- if os.getenv("OPENSSL_LIBNAME") is None:
107
- print("No OPENSSL_LIBNAME environment variable found, updating `setup.py`!")
108
- patch_pysqlcipher_setup(pysqlcipher_dir, crypto_lib)
109
-
110
- # Build amalgamation and install pysqlcipher
111
- if not pyexecutable:
112
- pyexecutable = sys.executable
113
-
114
- with WorkingDir(pysqlcipher_dir):
115
- if build:
116
- # Build amalgamation
117
- print()
118
- os.system(f"{pyexecutable} setup.py build_static build")
119
- if install:
120
- # Install pysqlcipher package
121
- print()
122
- os.system(f"{pyexecutable} setup.py install")
123
-
124
- # Remove temporary files
125
- if cleanup:
126
- try:
127
- print()
128
- print("Cleaning up")
129
- tmpdir.unlink(missing_ok=True)
130
- except PermissionError as e:
131
- print()
132
- print(e)
133
- print(f"Could not remove temporary directory '{tmpdir}'!")
134
-
135
-
136
- def download_db6_key():
137
- dp = ""
138
- for source in KEY_SOURCES:
139
- url = source["url"]
140
- regex = source["regex"]
141
- print(f"Looking for key: {url}")
142
-
143
- res = urllib.request.urlopen(url)
144
- data = res.read().decode("utf-8")
145
- match = regex.match(data)
146
- if match:
147
- dp = match.group("dp")
148
- break
149
- if dp:
150
- print(f"Found key, updating cache file {_cache_file}")
151
- write_db6_key_cache(dp)
152
- else:
153
- print("No key found in the online sources.")
154
-
155
-
156
- def main():
157
- from argparse import ArgumentParser
158
-
159
- parser = ArgumentParser("pyrekordbox")
160
- subparsers = parser.add_subparsers(dest="command")
161
-
162
- # Download Rekordbx 6 database key command
163
- subparsers.add_parser(
164
- "download-key",
165
- help="Download the Rekordbox 6 database key from the internet "
166
- "and write it to the cache file.",
167
- )
168
-
169
- # Install pysqlcipher3 command (Windows only)
170
- install_parser = subparsers.add_parser(
171
- "install-sqlcipher",
172
- help="Build sqlcipher against amalgamation and install pysqlcipher3",
173
- )
174
- install_parser.add_argument(
175
- "-t",
176
- "--tmpdir",
177
- type=str,
178
- default=".tmp",
179
- help="Path for storing temporary data (default: '.tmp')",
180
- )
181
- install_parser.add_argument(
182
- "-l",
183
- "--cryptolib",
184
- type=str,
185
- default="libcrypto.lib",
186
- help="The name of the OpenSSl crypto libary (default: 'libcrypto.lib')",
187
- )
188
- install_parser.add_argument(
189
- "-b",
190
- "--buildonly",
191
- action="store_true",
192
- help="Don't install sqlcipher3, only build the amalgamation",
193
- )
194
-
195
- # Parse args and handle command
196
- args = parser.parse_args(sys.argv[1:])
197
- if args.command == "download-key":
198
- download_db6_key()
199
- elif args.command == "install-sqlcipher":
200
- install_pysqlcipher(args.tmpdir, args.cryptolib, install=not args.buildonly)
201
-
202
-
203
- if __name__ == "__main__":
204
- main()
@@ -1,16 +0,0 @@
1
- # file generated by setuptools_scm
2
- # don't change, don't track in version control
3
- TYPE_CHECKING = False
4
- if TYPE_CHECKING:
5
- from typing import Tuple, Union
6
- VERSION_TUPLE = Tuple[Union[int, str], ...]
7
- else:
8
- VERSION_TUPLE = object
9
-
10
- version: str
11
- __version__: str
12
- __version_tuple__: VERSION_TUPLE
13
- version_tuple: VERSION_TUPLE
14
-
15
- __version__ = version = '0.2.1'
16
- __version_tuple__ = version_tuple = (0, 2, 1)
@@ -1,127 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Author: Dylan Jones
3
- # Date: 2023-02-01
4
-
5
- import re
6
- from pathlib import Path
7
- from typing import Union
8
- from . import structs
9
- from .file import AnlzFile
10
-
11
- RE_ANLZ = re.compile("ANLZ[0-9]{4}.(DAT|EXT|2EX)")
12
-
13
-
14
- def is_anlz_file(path: Union[str, Path]) -> bool:
15
- """Checks if the name of a file matches the ANLZ file name pattern.
16
-
17
- Parameters
18
- ----------
19
- path : str or Path
20
- The file path to check
21
-
22
- Returns
23
- -------
24
- is_anlz : bool
25
- True if the file is an ANLZ file.
26
-
27
- Examples
28
- --------
29
- >>> is_anlz_file("ANLZ0000.DAT")
30
- True
31
-
32
- >>> is_anlz_file("/path/to/ANLZ0000.DAT")
33
- False
34
-
35
- >>> is_anlz_file("ANLZ.DAT")
36
- False
37
- """
38
- path = Path(path)
39
- if not path.exists() or not path.is_file():
40
- return False
41
- return bool(RE_ANLZ.match(path.name))
42
-
43
-
44
- def get_anlz_paths(root: Union[str, Path]) -> dict:
45
- """Returns the paths of all existing ANLZ files in a directory.
46
-
47
- Parameters
48
- ----------
49
- root : str or Path
50
- The path of the directory containing ANLZ files.
51
-
52
- Returns
53
- -------
54
- anlz_paths : dict[str, Path]
55
- The file paths stored as dictionary with the type of ANLZ file as keys
56
- ("DAT", "EXT", "EX2")
57
-
58
- Examples
59
- --------
60
- >>> p = get_anlz_paths("directory/")
61
- >>> p["DAT"]
62
- directory/ANLZ0000.DAT
63
- """
64
- paths = {"DAT": None, "EXT": None, "2EX": None}
65
- for path in Path(root).iterdir():
66
- if RE_ANLZ.match(path.name):
67
- paths[path.suffix[1:].upper()] = path
68
- return paths
69
-
70
-
71
- def walk_anlz_dirs(root_dir: Union[str, Path]):
72
- """Finds all ANLZ directory paths recursively.
73
-
74
- Parameters
75
- ----------
76
- root_dir : str or Path
77
- The path of the root directory.
78
-
79
- Yields
80
- -------
81
- anlz_dir : str
82
- The path of a directory containing ANLZ files
83
- """
84
- for path in Path(root_dir).rglob("*"):
85
- if path.is_dir():
86
- if any(is_anlz_file(f) for f in path.iterdir()):
87
- yield path
88
-
89
-
90
- def walk_anlz_paths(root_dir: Union[str, Path]):
91
- """Finds all ANLZ directory paths and the containing file paths recursively.
92
-
93
- Parameters
94
- ----------
95
- root_dir : str or Path
96
- The path of the root directory.
97
-
98
- Yields
99
- -------
100
- anlz_dir : str
101
- The path of a directory containing ANLZ files.
102
- anlz_files : Sequence of str
103
- The file paths of the ANLZ files in `anlz_dir`.
104
- """
105
- root_dir = Path(root_dir)
106
- assert root_dir.exists()
107
- for anlz_dir in walk_anlz_dirs(root_dir):
108
- files = {k: path for k, path in get_anlz_paths(anlz_dir).items() if path}
109
- yield anlz_dir, files
110
-
111
-
112
- def read_anlz_files(root: Union[str, Path] = "") -> dict:
113
- """Open all ANLZ files in the given root directory.
114
-
115
- Parameters
116
- ----------
117
- root : str or Path, optional
118
- The root directory of the ANLZ files to open.
119
-
120
- Returns
121
- -------
122
- anlz_files : dict
123
- The opened ANLZ files stored in a dict with the corresponding file paths
124
- as keys.
125
- """
126
- paths = get_anlz_paths(root)
127
- return {path: AnlzFile.parse_file(path) for path in paths.values() if path}