dalia_dif 0.0.16__tar.gz → 0.0.18__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 (39) hide show
  1. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/PKG-INFO +2 -2
  2. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/pyproject.toml +3 -3
  3. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/cli.py +17 -2
  4. dalia_dif-0.0.18/src/dalia_dif/dif13/community/__init__.py +74 -0
  5. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/community/dalia_communities.csv +1 -1
  6. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/reader.py +27 -6
  7. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/version.py +1 -1
  8. dalia_dif-0.0.16/src/dalia_dif/dif13/community/__init__.py +0 -40
  9. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/LICENSE +0 -0
  10. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/README.md +0 -0
  11. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/.DS_Store +0 -0
  12. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/__init__.py +0 -0
  13. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/__main__.py +0 -0
  14. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/__init__.py +0 -0
  15. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/constants.py +0 -0
  16. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/export/__init__.py +0 -0
  17. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/export/charts.py +0 -0
  18. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/export/fti.py +0 -0
  19. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/legacy/__init__.py +0 -0
  20. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/legacy/authors.py +0 -0
  21. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/legacy/components.py +0 -0
  22. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/legacy/learning_resource.py +0 -0
  23. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/model.py +0 -0
  24. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/picklists.py +0 -0
  25. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/predicates.py +0 -0
  26. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/rdf.py +0 -0
  27. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/dif13/utils.py +0 -0
  28. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/__init__.py +0 -0
  29. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/bibframe_lite_relation.py +0 -0
  30. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/bibo.py +0 -0
  31. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/citedcat.py +0 -0
  32. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/educor.py +0 -0
  33. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/fabio.py +0 -0
  34. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/hcrt.py +0 -0
  35. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/metadata4ing.py +0 -0
  36. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/modalia.py +0 -0
  37. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/namespace/rec.py +0 -0
  38. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/py.typed +0 -0
  39. {dalia_dif-0.0.16 → dalia_dif-0.0.18}/src/dalia_dif/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dalia_dif
3
- Version: 0.0.16
3
+ Version: 0.0.18
4
4
  Summary: Tools for DALIA's data model for open educational resources
5
5
  Keywords: snekpack,cookiecutter,open educational resources,educational resources,training
6
6
  Author: Charles Tapley Hoyt
@@ -39,9 +39,9 @@ Maintainer: Charles Tapley Hoyt
39
39
  Maintainer-email: Charles Tapley Hoyt <cthoyt@gmail.com>
40
40
  Requires-Python: >=3.10
41
41
  Project-URL: Bug Tracker, https://github.com/data-literacy-alliance/dalia-dif/issues
42
- Project-URL: Documentation, https://dalia-dif.readthedocs.io
43
42
  Project-URL: Homepage, https://github.com/data-literacy-alliance/dalia-dif
44
43
  Project-URL: Repository, https://github.com/data-literacy-alliance/dalia-dif.git
44
+ Project-URL: Documentation, https://dalia-dif.readthedocs.io
45
45
  Provides-Extra: export
46
46
  Provides-Extra: fti
47
47
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "dalia_dif"
7
- version = "0.0.16"
7
+ version = "0.0.18"
8
8
  description = "Tools for DALIA's data model for open educational resources"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -82,7 +82,7 @@ typing = [
82
82
  { include-group = "tests" },
83
83
  "mypy",
84
84
  "pydantic",
85
- "click-types",
85
+ "types-click",
86
86
  "types-requests",
87
87
  ]
88
88
  docs-lint = [
@@ -250,7 +250,7 @@ known-first-party = [
250
250
  docstring-code-format = true
251
251
 
252
252
  [tool.bumpversion]
253
- current_version = "0.0.16"
253
+ current_version = "0.0.18"
254
254
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(?:-(?P<release>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+(?P<build>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"
255
255
  serialize = [
256
256
  "{major}.{minor}.{patch}-{release}+{build}",
@@ -17,10 +17,20 @@ def main() -> None:
17
17
 
18
18
  @main.command()
19
19
  @click.option("--dif-version", type=click.Choice(["1.3"]), default="1.3")
20
+ @click.option("--ignore-missing-description", is_flag=True)
21
+ @click.option("--communities-path", type=Path)
20
22
  @click.argument("location")
21
- def validate(location: str, dif_version: str) -> None:
23
+ def validate(
24
+ location: str, dif_version: str, ignore_missing_description: bool, communities_path: Path | None
25
+ ) -> None:
22
26
  """Validate a local/remote file or local folder of DIF-encoded CSVs."""
23
27
  from dalia_dif.dif13 import read_dif13
28
+ from dalia_dif.dif13.community import get_communities_dict
29
+
30
+ if communities_path is not None:
31
+ community_dict = get_communities_dict(communities_path)
32
+ else:
33
+ community_dict = {}
24
34
 
25
35
  fail = False
26
36
  p = Path(location)
@@ -31,7 +41,12 @@ def validate(location: str, dif_version: str) -> None:
31
41
  for path in p.glob("*.csv"):
32
42
  click.secho(f"\n> {path.relative_to(p)}", fg="green")
33
43
  errors: list[str] = []
34
- read_dif13(path, error_accumulator=errors)
44
+ read_dif13(
45
+ path,
46
+ error_accumulator=errors,
47
+ ignore_missing_description=ignore_missing_description,
48
+ custom_community_dict=community_dict,
49
+ )
35
50
  if errors:
36
51
  fail = True
37
52
  for error in errors:
@@ -0,0 +1,74 @@
1
+ """Code for curated DALIA communities."""
2
+
3
+ import csv
4
+ from collections import Counter
5
+ from pathlib import Path
6
+ from typing import Any, TypeAlias
7
+
8
+ from pydantic import UUID4, AnyHttpUrl, BaseModel, Field
9
+
10
+ HERE = Path(__file__).parent.resolve()
11
+ COMMUNITIES_PATH = HERE / "dalia_communities.csv"
12
+
13
+
14
+ class Community(BaseModel):
15
+ """A data model for communities."""
16
+
17
+ uuid: UUID4
18
+ title: str
19
+ ror: str | None = None
20
+ website: AnyHttpUrl | None = None
21
+ synonyms: list[str] = Field(default_factory=list)
22
+
23
+
24
+ def _process(row: dict[str, Any]) -> Community:
25
+ if synonyms_raw := row.pop("synonyms"):
26
+ row["synonyms"] = [s.strip() for s in synonyms_raw.split("|")]
27
+ return Community.model_validate({k: v for k, v in row.items() if v})
28
+
29
+
30
+ def read_communities(path: Path) -> list[Community]:
31
+ """Read communities."""
32
+ with open(path, newline="") as csvfile:
33
+ return [_process(row) for row in csv.DictReader(csvfile)]
34
+
35
+
36
+ CommunityDict: TypeAlias = dict[str, str]
37
+
38
+
39
+ def get_communities_dict(path: Path) -> CommunityDict:
40
+ """Get a mapping from names/synonyms to UUID strings."""
41
+ rv = {}
42
+ for community in read_communities(path):
43
+ rv[community.title] = str(community.uuid)
44
+ for synonym in community.synonyms:
45
+ rv[synonym] = str(community.uuid)
46
+ return rv
47
+
48
+
49
+ def _read_mapping() -> dict[str, str]:
50
+ rv = {}
51
+ for community in read_communities(COMMUNITIES_PATH):
52
+ rv[community.title] = str(community.uuid)
53
+ for synonym in community.synonyms:
54
+ rv[synonym] = str(community.uuid)
55
+ return rv
56
+
57
+
58
+ LOOKUP_DICT_COMMUNITIES: CommunityDict = get_communities_dict(COMMUNITIES_PATH)
59
+
60
+ MISSING_COMMUNITIES: Counter[str] = Counter()
61
+
62
+
63
+ def get_community_labels() -> dict[str, str]:
64
+ """Get community labels."""
65
+ return {
66
+ str(community.uuid): COMMUNITY_RELABELS.get(community.title, community.title)
67
+ for community in read_communities(COMMUNITIES_PATH)
68
+ }
69
+
70
+
71
+ COMMUNITY_RELABELS = {
72
+ "Nationale Forschungsdateninfrastruktur (NFDI)": "NFDI",
73
+ "HeFDI - Hessische Forschungsdateninfrastrukturen": "HeFDI",
74
+ }
@@ -1,4 +1,4 @@
1
- ID,ROR,Website,Title,Synonyms
1
+ uuid,ror,website,title,synonyms
2
2
  8cd01866-7560-4701-ba4a-da3c939b9061,,,Base4NFDI,
3
3
  7ecf1a3e-e377-4f5c-ac70-78d498951843,,,BERD@NFDI,
4
4
  0393d642-340d-4641-8c1f-e9c8b27199bf,,,DAPHNE4NFDI,
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  import re
7
- from collections import Counter
7
+ from collections import ChainMap, Counter
8
8
  from pathlib import Path
9
9
  from typing import TextIO
10
10
 
@@ -17,7 +17,7 @@ from pystow.utils import safe_open_dict_reader
17
17
  from rdflib import URIRef
18
18
  from tqdm import tqdm
19
19
 
20
- from .community import LOOKUP_DICT_COMMUNITIES
20
+ from .community import LOOKUP_DICT_COMMUNITIES, CommunityDict
21
21
  from .model import (
22
22
  AuthorDIF13,
23
23
  EducationalResourceDIF13,
@@ -101,6 +101,8 @@ def read_dif13(
101
101
  *,
102
102
  error_accumulator: list[str] | None = None,
103
103
  converter: curies.Converter | None = None,
104
+ ignore_missing_description: bool = False,
105
+ custom_community_dict: CommunityDict | None = None,
104
106
  ) -> list[EducationalResourceDIF13]:
105
107
  """Parse DALIA records."""
106
108
  if isinstance(path, str) and (path.startswith("http://") or path.startswith("https://")):
@@ -132,7 +134,13 @@ def read_dif13(
132
134
  for idx, record in enumerate(reader, start=2)
133
135
  if (
134
136
  oer := parse_dif13_row(
135
- file_name, idx, record, error_accumulator=error_accumulator, converter=converter
137
+ file_name,
138
+ idx,
139
+ record,
140
+ error_accumulator=error_accumulator,
141
+ converter=converter,
142
+ ignore_missing_description=ignore_missing_description,
143
+ custom_community_dict=custom_community_dict,
136
144
  )
137
145
  )
138
146
  is not None
@@ -157,13 +165,19 @@ def parse_dif13_row( # noqa:C901
157
165
  future: bool = False,
158
166
  error_accumulator: list[str] | None = None,
159
167
  converter: curies.Converter | None = None,
168
+ ignore_missing_description: bool = False,
169
+ custom_community_dict: CommunityDict | None = None,
160
170
  ) -> EducationalResourceDIF13 | None:
161
171
  """Convert a row in a DALIA curation file to a resource, or return none if unable."""
162
172
  if isinstance(file_name, Path):
163
173
  file_name = file_name.name
164
174
 
165
175
  supporting_communities, recommending_communities = _process_communities(
166
- file_name, idx, row, error_accumulator=error_accumulator
176
+ file_name,
177
+ idx,
178
+ row,
179
+ error_accumulator=error_accumulator,
180
+ custom_community_dict=custom_community_dict,
167
181
  )
168
182
 
169
183
  external_uris = _pop_split(row, "Link")
@@ -193,7 +207,12 @@ def parse_dif13_row( # noqa:C901
193
207
 
194
208
  description = row.pop("Description").strip()
195
209
  if not description:
196
- _log(file_name, idx, "no description given", error_accumulator=error_accumulator)
210
+ _log(
211
+ file_name,
212
+ idx,
213
+ "no description given",
214
+ error_accumulator=None if ignore_missing_description else error_accumulator,
215
+ )
197
216
  return None
198
217
 
199
218
  try:
@@ -461,8 +480,10 @@ def _process_communities(
461
480
  row: dict[str, str],
462
481
  *,
463
482
  error_accumulator: list[str] | None = None,
483
+ custom_community_dict: CommunityDict | None = None,
464
484
  ) -> tuple[list[URIRef], list[URIRef]]:
465
485
  supporting, recommending = [], []
486
+ community_dict = ChainMap(custom_community_dict or {}, LOOKUP_DICT_COMMUNITIES)
466
487
  for community in _pop_split(row, "Community"):
467
488
  match = COMMUNITY_RELATION_RE.search(community)
468
489
  if not match:
@@ -477,7 +498,7 @@ def _process_communities(
477
498
  name = match.group("name").strip()
478
499
  relation = match.group("relation")
479
500
 
480
- community_uuid = LOOKUP_DICT_COMMUNITIES.get(name, None)
501
+ community_uuid = community_dict.get(name, None)
481
502
  if not community_uuid:
482
503
  if not MISSING_COMMUNITIES[name]:
483
504
  _log(
@@ -12,7 +12,7 @@ __all__ = [
12
12
  "get_version",
13
13
  ]
14
14
 
15
- VERSION = "0.0.16"
15
+ VERSION = "0.0.18"
16
16
 
17
17
 
18
18
  def get_git_hash() -> str:
@@ -1,40 +0,0 @@
1
- """Code for curated DALIA communities."""
2
-
3
- import csv
4
- from collections import Counter
5
- from pathlib import Path
6
-
7
- HERE = Path(__file__).parent.resolve()
8
- COMMUNITIES_PATH = HERE / "dalia_communities.csv"
9
-
10
-
11
- def _read_mapping() -> dict[str, str]:
12
- rv = {}
13
- with open(COMMUNITIES_PATH, newline="") as csvfile:
14
- for row in csv.DictReader(csvfile):
15
- rv[row["Title"]] = row["ID"]
16
- for synonym in row["Synonyms"].split("|"):
17
- rv[synonym] = row["ID"]
18
- return rv
19
-
20
-
21
- LOOKUP_DICT_COMMUNITIES = _read_mapping()
22
-
23
- del _read_mapping
24
-
25
- MISSING_COMMUNITIES: Counter[str] = Counter()
26
-
27
-
28
- def get_community_labels() -> dict[str, str]:
29
- """Get community labels."""
30
- with open(COMMUNITIES_PATH, newline="") as csvfile:
31
- return {
32
- row["ID"]: COMMUNITY_RELABELS.get(row["Title"], row["Title"])
33
- for row in csv.DictReader(csvfile)
34
- }
35
-
36
-
37
- COMMUNITY_RELABELS = {
38
- "Nationale Forschungsdateninfrastruktur (NFDI)": "NFDI",
39
- "HeFDI - Hessische Forschungsdateninfrastrukturen": "HeFDI",
40
- }
File without changes
File without changes