pycldf 2.0.2__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. {pycldf-2.0.2 → pycldf-2.1.1}/CHANGELOG.md +12 -0
  2. {pycldf-2.0.2 → pycldf-2.1.1}/PKG-INFO +3 -2
  3. {pycldf-2.0.2 → pycldf-2.1.1}/RELEASING.md +1 -1
  4. {pycldf-2.0.2 → pycldf-2.1.1}/setup.cfg +3 -2
  5. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/__init__.py +1 -1
  6. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/ext/discovery.py +7 -3
  7. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/media.py +11 -4
  8. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/PKG-INFO +3 -2
  9. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/requires.txt +6 -1
  10. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_ext_discovery.py +2 -0
  11. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_media.py +8 -0
  12. {pycldf-2.0.2 → pycldf-2.1.1}/CONTRIBUTING.md +0 -0
  13. {pycldf-2.0.2 → pycldf-2.1.1}/LICENSE +0 -0
  14. {pycldf-2.0.2 → pycldf-2.1.1}/MANIFEST.in +0 -0
  15. {pycldf-2.0.2 → pycldf-2.1.1}/README.md +0 -0
  16. {pycldf-2.0.2 → pycldf-2.1.1}/pyproject.toml +0 -0
  17. {pycldf-2.0.2 → pycldf-2.1.1}/setup.py +0 -0
  18. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/__main__.py +0 -0
  19. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/_compat.py +0 -0
  20. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/cli_util.py +0 -0
  21. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/__init__.py +0 -0
  22. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/catmedia.py +0 -0
  23. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/check.py +0 -0
  24. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/createdb.py +0 -0
  25. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/downloadmedia.py +0 -0
  26. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/dumpdb.py +0 -0
  27. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/markdown.py +0 -0
  28. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/splitmedia.py +0 -0
  29. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/stats.py +0 -0
  30. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/commands/validate.py +0 -0
  31. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/BorrowingTable-metadata.json +0 -0
  32. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/CodeTable-metadata.json +0 -0
  33. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/CognateTable-metadata.json +0 -0
  34. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/CognatesetTable-metadata.json +0 -0
  35. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/ContributionTable-metadata.json +0 -0
  36. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/EntryTable-metadata.json +0 -0
  37. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/ExampleTable-metadata.json +0 -0
  38. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/FormTable-metadata.json +0 -0
  39. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/FunctionalEquivalentTable-metadata.json +0 -0
  40. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/FunctionalEquivalentsetTable-metadata.json +0 -0
  41. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/LanguageTable-metadata.json +0 -0
  42. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/MediaTable-metadata.json +0 -0
  43. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/ParameterNetwork-metadata.json +0 -0
  44. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/ParameterTable-metadata.json +0 -0
  45. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/SenseTable-metadata.json +0 -0
  46. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/TreeTable-metadata.json +0 -0
  47. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/components/ValueTable-metadata.json +0 -0
  48. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/constraints.py +0 -0
  49. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/dataset.py +0 -0
  50. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/db.py +0 -0
  51. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/ext/__init__.py +0 -0
  52. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/ext/markdown.py +0 -0
  53. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/ext/sql.py +0 -0
  54. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/fileutil.py +0 -0
  55. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/markdown.py +0 -0
  56. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/module.py +0 -0
  57. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/Dictionary-metadata.json +0 -0
  58. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/Generic-metadata.json +0 -0
  59. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/ParallelText-metadata.json +0 -0
  60. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/StructureDataset-metadata.json +0 -0
  61. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/TextCorpus-metadata.json +0 -0
  62. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/modules/Wordlist-metadata.json +0 -0
  63. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/orm.py +0 -0
  64. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/schemautil.py +0 -0
  65. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/sliceutil.py +0 -0
  66. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/sources.py +0 -0
  67. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/stats.py +0 -0
  68. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/terms.py +0 -0
  69. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/terms.rdf +0 -0
  70. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/trees.py +0 -0
  71. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/urlutil.py +0 -0
  72. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/util.py +0 -0
  73. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf/validators.py +0 -0
  74. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/SOURCES.txt +0 -0
  75. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/dependency_links.txt +0 -0
  76. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/entry_points.txt +0 -0
  77. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/not-zip-safe +0 -0
  78. {pycldf-2.0.2 → pycldf-2.1.1}/src/pycldf.egg-info/top_level.txt +0 -0
  79. {pycldf-2.0.2 → pycldf-2.1.1}/test.md +0 -0
  80. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_cli.py +0 -0
  81. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_cli_util.py +0 -0
  82. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_dataset.py +0 -0
  83. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_db.py +0 -0
  84. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_ext_markdown.py +0 -0
  85. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_ext_sql.py +0 -0
  86. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_misc.py +0 -0
  87. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_orm.py +0 -0
  88. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_paralleltext.py +0 -0
  89. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_sources.py +0 -0
  90. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_terms.py +0 -0
  91. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_trees.py +0 -0
  92. {pycldf-2.0.2 → pycldf-2.1.1}/tests/test_util.py +0 -0
@@ -3,6 +3,18 @@
3
3
  The `pycldf` package adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
4
 
5
5
 
6
+ ## [2.1.1] - 2026-07-17
7
+
8
+ Fixed incomplete requirements.
9
+
10
+
11
+ ## [2.1.0] - 2026-07-17
12
+
13
+ - Added support for reading media file data from locally downloaded zip archives. This helps with the
14
+ use case of datasets linking to media in separate Zenodo deposits.
15
+ - Added support for discovering multiple datasets from the same locator.
16
+
17
+
6
18
  ## [2.0.2] - 2026-05-14
7
19
 
8
20
  - Fix bug whereby pipes in regular expression patterns would screw up table
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycldf
3
- Version: 2.0.2
3
+ Version: 2.1.1
4
4
  Summary: A python library to read and write CLDF datasets
5
5
  Home-page: https://github.com/cldf/pycldf
6
6
  Author: Robert Forkel
@@ -27,6 +27,8 @@ Classifier: License :: OSI Approved :: Apache Software License
27
27
  Requires-Python: >=3.9
28
28
  Description-Content-Type: text/markdown
29
29
  License-File: LICENSE
30
+ Requires-Dist: python-frontmatter<1.2; python_version < "3.10"
31
+ Requires-Dist: python-frontmatter; python_version >= "3.10"
30
32
  Requires-Dist: csvw>=4.0
31
33
  Requires-Dist: clldutils>=4.0
32
34
  Requires-Dist: uritemplate>=3.0
@@ -34,7 +36,6 @@ Requires-Dist: python-dateutil
34
36
  Requires-Dist: simplepybtex
35
37
  Requires-Dist: newick
36
38
  Requires-Dist: commonnexus>=1.2.0
37
- Requires-Dist: python-frontmatter
38
39
  Requires-Dist: termcolor
39
40
  Requires-Dist: PyYAML
40
41
  Requires-Dist: jmespath
@@ -12,7 +12,7 @@ Releasing pycldf
12
12
  ```shell
13
13
  flake8 src
14
14
  ```
15
- - Make sure pylint passes with a score of 10:
15
+ - Make sure pylint passes with a score >= 9.99:
16
16
  ```shell
17
17
  pylint src
18
18
  ```
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = pycldf
3
- version = 2.0.2
3
+ version = 2.1.1
4
4
  author = Robert Forkel
5
5
  author_email = robert_forkel@eva.mpg.de
6
6
  description = A python library to read and write CLDF datasets
@@ -37,6 +37,8 @@ package_dir =
37
37
  = src
38
38
  python_requires = >=3.9
39
39
  install_requires =
40
+ python-frontmatter<1.2;python_version<"3.10"
41
+ python-frontmatter;python_version>="3.10"
40
42
  csvw>=4.0
41
43
  clldutils>=4.0
42
44
  uritemplate>=3.0
@@ -44,7 +46,6 @@ install_requires =
44
46
  simplepybtex
45
47
  newick
46
48
  commonnexus>=1.2.0
47
- python-frontmatter
48
49
  termcolor
49
50
  PyYAML
50
51
  jmespath
@@ -9,4 +9,4 @@ from pycldf.sources import *
9
9
  from pycldf.terms import *
10
10
 
11
11
  # flake8: noqa
12
- __version__ = "2.0.2"
12
+ __version__ = "2.1.1"
@@ -157,13 +157,16 @@ def get_resolvers() -> list[type]:
157
157
  def _get_dataset(
158
158
  locator: DatasetLocator,
159
159
  location: Union[None, Dataset, pathlib.Path],
160
- ) -> Optional[Dataset]:
160
+ get_all: bool = False,
161
+ ) -> Optional[Union[Dataset, list[Dataset]]]:
161
162
  """Determine whether locator matches location and if so, resolve to a Dataset instance."""
162
163
  if isinstance(location, Dataset):
163
164
  if locator.match(location):
164
165
  return location
165
166
  return None
166
167
  if location.is_dir():
168
+ if get_all:
169
+ return [ds for ds in iter_datasets(location) if locator.match(ds)]
167
170
  for ds in iter_datasets(location):
168
171
  if locator.match(ds):
169
172
  return ds
@@ -176,7 +179,8 @@ def _get_dataset(
176
179
 
177
180
  def get_dataset(locator: str,
178
181
  download_dir: pathlib.Path,
179
- base: Optional[pathlib.Path] = None) -> Dataset:
182
+ base: Optional[pathlib.Path] = None,
183
+ get_all: bool = False) -> Union[Dataset, list[Dataset]]:
180
184
  """
181
185
  :param locator: Dataset locator as specified in "Dataset discovery".
182
186
  :param download_dir: Directory to which to download remote data if necessary.
@@ -191,7 +195,7 @@ def get_dataset(locator: str,
191
195
  else:
192
196
  res = resolver(locator.url_without_fragment, download_dir)
193
197
  if res:
194
- res = _get_dataset(locator, res)
198
+ res = _get_dataset(locator, res, get_all=get_all)
195
199
  if res:
196
200
  return res
197
201
  raise ValueError(f'Could not resolve dataset locator {locator}')
@@ -139,12 +139,19 @@ class File: # pylint: disable=too-many-instance-attributes
139
139
 
140
140
  def local_path(self, d: pathlib.Path = None) -> Optional[pathlib.Path]:
141
141
  """
142
- :return: The expected path of the file in the directory `d`.
142
+ :return: The expected path of the file in the directory `d` in the case of files \
143
+ downloaded using the `downloadmedia` command. If `d` is a file it is accepted as full \
144
+ local path if it has the same name as the filename in the URL.
143
145
  """
144
146
  if d is None:
145
147
  if self.scheme == 'file':
146
148
  return self._dsdir / urllib.parse.unquote(self.relpath)
147
149
  return None
150
+ if d.is_file() and self.parsed_url:
151
+ if d.name == pathlib.Path(self.parsed_url.path).name:
152
+ # Support the use case of files in zip archives, where the archives are available
153
+ # locally, e.g. as download of a separate media file deposit from Zenodo.
154
+ return d
148
155
  zip_ext = '.zip' if self.path_in_zip else (self.mimetype.extension or '')
149
156
  return d.joinpath(f'{self.id}{zip_ext}')
150
157
 
@@ -155,14 +162,14 @@ class File: # pylint: disable=too-many-instance-attributes
155
162
 
156
163
  def read(self, d: Optional[pathlib.Path] = None) -> Optional[StrOrBytes]:
157
164
  """
158
- :param d: A local directory where the file has been saved before. If `None`, the content \
159
- will be read from the file's URL.
165
+ :param d: A local path where the file has been saved before - as expected by `local_path`. \
166
+ If `None`, the content will be read from the file's URL.
160
167
  """
161
168
  if self.path_in_zip:
162
169
  zipcontent = None
163
170
  if d:
164
171
  zipcontent = self.local_path(d).read_bytes()
165
- if self.url:
172
+ if zipcontent is None and self.url:
166
173
  zipcontent = self.url_reader[self.scheme](
167
174
  self.parsed_url, Mimetype('application/zip'))
168
175
  if zipcontent:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycldf
3
- Version: 2.0.2
3
+ Version: 2.1.1
4
4
  Summary: A python library to read and write CLDF datasets
5
5
  Home-page: https://github.com/cldf/pycldf
6
6
  Author: Robert Forkel
@@ -27,6 +27,8 @@ Classifier: License :: OSI Approved :: Apache Software License
27
27
  Requires-Python: >=3.9
28
28
  Description-Content-Type: text/markdown
29
29
  License-File: LICENSE
30
+ Requires-Dist: python-frontmatter<1.2; python_version < "3.10"
31
+ Requires-Dist: python-frontmatter; python_version >= "3.10"
30
32
  Requires-Dist: csvw>=4.0
31
33
  Requires-Dist: clldutils>=4.0
32
34
  Requires-Dist: uritemplate>=3.0
@@ -34,7 +36,6 @@ Requires-Dist: python-dateutil
34
36
  Requires-Dist: simplepybtex
35
37
  Requires-Dist: newick
36
38
  Requires-Dist: commonnexus>=1.2.0
37
- Requires-Dist: python-frontmatter
38
39
  Requires-Dist: termcolor
39
40
  Requires-Dist: PyYAML
40
41
  Requires-Dist: jmespath
@@ -5,11 +5,16 @@ python-dateutil
5
5
  simplepybtex
6
6
  newick
7
7
  commonnexus>=1.2.0
8
- python-frontmatter
9
8
  termcolor
10
9
  PyYAML
11
10
  jmespath
12
11
 
12
+ [:python_version < "3.10"]
13
+ python-frontmatter<1.2
14
+
15
+ [:python_version >= "3.10"]
16
+ python-frontmatter
17
+
13
18
  [catalogs]
14
19
  cldfcatalog
15
20
  pyglottolog>=4.0
@@ -10,6 +10,8 @@ from pycldf.ext.discovery import *
10
10
 
11
11
  def test_get_dataset_local(data, tmp_path):
12
12
  assert get_dataset('structuredataset_with_examples', tmp_path, base=data)
13
+ res = get_dataset('structuredataset_with_examples', tmp_path, base=data, get_all=True)
14
+ assert isinstance(res, list) and isinstance(res[0], Dataset)
13
15
 
14
16
 
15
17
  def test_get_dataset_github(data, tmp_path, mocker):
@@ -194,6 +194,14 @@ def test_Media(tmp_path, ds_factory):
194
194
  assert list(MediaTable(ds))[0].read() == 'äöü'
195
195
  assert list(MediaTable(ds))[0].read(d=tmp_path) == 'äöü'
196
196
 
197
+ ds = ds_factory(dict(
198
+ ID='x',
199
+ Download_URL="http://example.com/path/123.zip",
200
+ Media_Type='text/plain',
201
+ Path_In_Zip='arc/name',
202
+ ))
203
+ assert list(MediaTable(ds))[0].read(d=tmp_path / '123.zip') == 'äöü'
204
+
197
205
 
198
206
  def test_save_read_zipped_media(dataset_with_trees, tmp_path):
199
207
  zipped = None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes