dalia_dif 0.0.16__py3-none-any.whl → 0.0.18__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.
dalia_dif/cli.py CHANGED
@@ -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:
@@ -3,35 +3,69 @@
3
3
  import csv
4
4
  from collections import Counter
5
5
  from pathlib import Path
6
+ from typing import Any, TypeAlias
7
+
8
+ from pydantic import UUID4, AnyHttpUrl, BaseModel, Field
6
9
 
7
10
  HERE = Path(__file__).parent.resolve()
8
11
  COMMUNITIES_PATH = HERE / "dalia_communities.csv"
9
12
 
10
13
 
11
- def _read_mapping() -> dict[str, str]:
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."""
12
41
  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"]
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)
18
46
  return rv
19
47
 
20
48
 
21
- LOOKUP_DICT_COMMUNITIES = _read_mapping()
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
+
22
57
 
23
- del _read_mapping
58
+ LOOKUP_DICT_COMMUNITIES: CommunityDict = get_communities_dict(COMMUNITIES_PATH)
24
59
 
25
60
  MISSING_COMMUNITIES: Counter[str] = Counter()
26
61
 
27
62
 
28
63
  def get_community_labels() -> dict[str, str]:
29
64
  """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
- }
65
+ return {
66
+ str(community.uuid): COMMUNITY_RELABELS.get(community.title, community.title)
67
+ for community in read_communities(COMMUNITIES_PATH)
68
+ }
35
69
 
36
70
 
37
71
  COMMUNITY_RELABELS = {
@@ -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,
dalia_dif/dif13/reader.py CHANGED
@@ -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(
dalia_dif/version.py CHANGED
@@ -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,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
@@ -1,10 +1,10 @@
1
1
  dalia_dif/.DS_Store,sha256=MtnD5ThzFbk9R7gZVWNniR_qnre6YMJscVWWkkQW8AM,6148
2
2
  dalia_dif/__init__.py,sha256=uyO7jo0cu-99M2a87I7XeOH6c9ZPqRH46YgTdfXLOWg,66
3
3
  dalia_dif/__main__.py,sha256=dlPNI11KSS49DY4SoTA1l8gQZr6iR9N1JJsySTjicUg,126
4
- dalia_dif/cli.py,sha256=pdmO-y0wCZW7XkQywltnCpzpxdzC99I9m2OrKq6cXrU,2951
4
+ dalia_dif/cli.py,sha256=yvV0YeBSJ9cGlmcsuTaVqGw6-zokjLvoQ8xYHjPzoq8,3504
5
5
  dalia_dif/dif13/__init__.py,sha256=tMaSW0hhnuO_Mt8CM_d0cTT6j_FSTGFY99crUawWa4w,457
6
- dalia_dif/dif13/community/__init__.py,sha256=y8RnUSR1-d0oU02ZJA6z1hmDIJlUTJ66Yb51JGcp0JE,1051
7
- dalia_dif/dif13/community/dalia_communities.csv,sha256=Tcpo310kOtn1zNMKu183GjqcM8XlsubGrLSvbvotJxI,6191
6
+ dalia_dif/dif13/community/__init__.py,sha256=IwHOubp6bc6peW2vVgaYuA7JNJ07py60bUZowKDttvs,2107
7
+ dalia_dif/dif13/community/dalia_communities.csv,sha256=Dg4rGox0ykZ-2HFFgVF8hDZIxcX2VgeKUle2W4PHD0c,6193
8
8
  dalia_dif/dif13/constants.py,sha256=NLNutj5AYok_WY1t1iE01dOCKK2eCnkezzN4TUgT-SA,6797
9
9
  dalia_dif/dif13/export/__init__.py,sha256=-HXO3x8soeYPFg5vIggJcZihGbyeVn_DO42cqWwNAuA,28
10
10
  dalia_dif/dif13/export/charts.py,sha256=8cXrq2UMnQUFi_Bda5L5sbZJRu2DnfUftj8zPe5c8ik,13695
@@ -17,7 +17,7 @@ dalia_dif/dif13/model.py,sha256=GIfzAnT0Blh7Qe-wk3w_lxZld-B4VbfH2ahyaDdpuR4,6935
17
17
  dalia_dif/dif13/picklists.py,sha256=FapSFANJZ_u432RtGyOq7v8FpKfR4X9C7n3bAAXbrNI,4933
18
18
  dalia_dif/dif13/predicates.py,sha256=rrWVPMnMPvMelS4i2hOEWGhL11t-KR8yRrDArhGvYPE,1700
19
19
  dalia_dif/dif13/rdf.py,sha256=ZPdGB1hM2zNuxe6gidNwOn0LJB00Zs-mj2fHOYNm_qU,5908
20
- dalia_dif/dif13/reader.py,sha256=vdHUawwDx1ohdldGbXtJDaAysEKdOmBUkP_sNhf1YJo,16853
20
+ dalia_dif/dif13/reader.py,sha256=SinQMN_cimwihpsM3kJwom-MD8Om_WPTTi5Bo5EOKxQ,17611
21
21
  dalia_dif/dif13/utils.py,sha256=-r5ezhD7AkaJUAsUtZl1sHG_P76fz2Q_ULXgXLyDNII,814
22
22
  dalia_dif/namespace/__init__.py,sha256=kJGpIXZzeUdVhM_Pj465XlMkVqMB2Uc9aAZeFKQp5IQ,3105
23
23
  dalia_dif/namespace/bibframe_lite_relation.py,sha256=2trFP98s1wCPUfiAjHg-EK09yjWXC6ePLNJIVqgZvd8,255
@@ -31,9 +31,9 @@ dalia_dif/namespace/modalia.py,sha256=pSL-G9ib0E--Jwrbu9PvMMRjMe2FzzxoSjEv-0ank2
31
31
  dalia_dif/namespace/rec.py,sha256=c2Ce5IEhnM_BcZJUCXiMQEZ2GLFcC_76hfkKE16-zLc,241
32
32
  dalia_dif/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
33
33
  dalia_dif/utils.py,sha256=AA19Bw0vv8-ODZzDy_VR57WwndRccaQIepVS8tvodDo,761
34
- dalia_dif/version.py,sha256=P0HhClGD_f2DxANB1sjaKV-SnG74QwaGHI6c9mzq30k,962
35
- dalia_dif-0.0.16.dist-info/licenses/LICENSE,sha256=S-DsND478R_VQyGmtXbVYW67fRiJj3QfY8UXIJ4zvLI,1076
36
- dalia_dif-0.0.16.dist-info/WHEEL,sha256=z-mOpxbJHqy3cq6SvUThBZdaLGFZzdZPtgWLcP2NKjQ,79
37
- dalia_dif-0.0.16.dist-info/entry_points.txt,sha256=GmBz8JVyUD6m4v2QIxa7gm3sHIVNjTl5KTPP7L3FCGI,50
38
- dalia_dif-0.0.16.dist-info/METADATA,sha256=KGz1zzlomjuz7BA_lKnVrsL-Y-vgY62wkbn4RVUP3GA,17760
39
- dalia_dif-0.0.16.dist-info/RECORD,,
34
+ dalia_dif/version.py,sha256=7L891_Jrr5liLFWnZMCce8I-vBl683ocjoLsHlmjYGY,962
35
+ dalia_dif-0.0.18.dist-info/licenses/LICENSE,sha256=S-DsND478R_VQyGmtXbVYW67fRiJj3QfY8UXIJ4zvLI,1076
36
+ dalia_dif-0.0.18.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
37
+ dalia_dif-0.0.18.dist-info/entry_points.txt,sha256=GmBz8JVyUD6m4v2QIxa7gm3sHIVNjTl5KTPP7L3FCGI,50
38
+ dalia_dif-0.0.18.dist-info/METADATA,sha256=rqYxck75cMrF7PtSj4xMR9NeaPe9YySdUEVrW8Cs4Sw,17760
39
+ dalia_dif-0.0.18.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.15
2
+ Generator: uv 0.9.28
3
3
  Root-Is-Purelib: true
4
- Tag: py3-none-any
4
+ Tag: py3-none-any