commonmeta-py 0.117__tar.gz → 0.119__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 (90) hide show
  1. {commonmeta_py-0.117 → commonmeta_py-0.119}/PKG-INFO +2 -2
  2. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/__init__.py +1 -1
  3. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/doi_utils.py +0 -1
  4. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/file_utils.py +0 -10
  5. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/crossref_xml_writer.py +43 -38
  6. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/inveniordm_writer.py +52 -39
  7. {commonmeta_py-0.117 → commonmeta_py-0.119}/pyproject.toml +2 -2
  8. {commonmeta_py-0.117 → commonmeta_py-0.119}/.gitignore +0 -0
  9. {commonmeta_py-0.117 → commonmeta_py-0.119}/LICENSE +0 -0
  10. {commonmeta_py-0.117 → commonmeta_py-0.119}/README.md +0 -0
  11. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/api_utils.py +0 -0
  12. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/author_utils.py +0 -0
  13. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/base_utils.py +0 -0
  14. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/cli.py +0 -0
  15. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/constants.py +0 -0
  16. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/date_utils.py +0 -0
  17. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/metadata.py +0 -0
  18. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/__init__.py +0 -0
  19. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/bibtex_reader.py +0 -0
  20. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/cff_reader.py +0 -0
  21. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/codemeta_reader.py +0 -0
  22. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/commonmeta_reader.py +0 -0
  23. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/crossref_reader.py +0 -0
  24. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/crossref_xml_reader.py +0 -0
  25. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/csl_reader.py +0 -0
  26. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/datacite_reader.py +0 -0
  27. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/datacite_xml_reader.py +0 -0
  28. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/inveniordm_reader.py +0 -0
  29. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/jsonfeed_reader.py +0 -0
  30. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/kbase_reader.py +0 -0
  31. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/openalex_reader.py +0 -0
  32. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/ris_reader.py +0 -0
  33. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/readers/schema_org_reader.py +0 -0
  34. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/cff_v1.2.0.json +0 -0
  35. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/commonmeta_v0.12.json +0 -0
  36. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/commonmeta_v0.13.json +0 -0
  37. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/commonmeta_v0.14.json +0 -0
  38. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/commonmeta_v0.15.json +0 -0
  39. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/commonmeta_v0.16.json +0 -0
  40. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/AccessIndicators.xsd +0 -0
  41. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1-3d2-mathml3-elements.xsd +0 -0
  42. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1-3d2-mathml3.xsd +0 -0
  43. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1-elements.xsd +0 -0
  44. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1-mathml3-elements.xsd +0 -0
  45. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1-mathml3.xsd +0 -0
  46. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/JATS-journalpublishing1.xsd +0 -0
  47. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/clinicaltrials.xsd +0 -0
  48. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/common5.4.0.xsd +0 -0
  49. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/crossref5.4.0.xsd +0 -0
  50. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/crossref_query_output3.0.xsd +0 -0
  51. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/doi_resources5.4.0.xsd +0 -0
  52. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/fundingdata5.4.0.xsd +0 -0
  53. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/fundref.xsd +0 -0
  54. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/languages5.4.0.xsd +0 -0
  55. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/mediatypes5.4.0.xsd +0 -0
  56. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/module-ali.xsd +0 -0
  57. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/relations.xsd +0 -0
  58. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/mathml3-common.xsd +0 -0
  59. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/mathml3-content.xsd +0 -0
  60. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/mathml3-presentation.xsd +0 -0
  61. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/mathml3-strict-content.xsd +0 -0
  62. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/mathml3.xsd +0 -0
  63. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/mathml3/module-ali.xsd +0 -0
  64. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/module-ali.xsd +0 -0
  65. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/xlink.xsd +0 -0
  66. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/standard-modules/xml.xsd +0 -0
  67. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref/xml.xsd +0 -0
  68. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/crossref-v0.2.json +0 -0
  69. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/csl-data.json +0 -0
  70. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/datacite-v4.5.json +0 -0
  71. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/datacite-v4.5pr.json +0 -0
  72. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/spdx/licenses.json +0 -0
  73. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/spdx-schema.json +0 -0
  74. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/apa.csl +0 -0
  75. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/chicago-author-date.csl +0 -0
  76. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/harvard-cite-them-right.csl +0 -0
  77. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/ieee.csl +0 -0
  78. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/modern-language-association.csl +0 -0
  79. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/resources/styles/vancouver.csl +0 -0
  80. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/schema_utils.py +0 -0
  81. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/translators.py +0 -0
  82. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/utils.py +0 -0
  83. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/__init__.py +0 -0
  84. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/bibtex_writer.py +0 -0
  85. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/citation_writer.py +0 -0
  86. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/commonmeta_writer.py +0 -0
  87. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/csl_writer.py +0 -0
  88. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/datacite_writer.py +0 -0
  89. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/ris_writer.py +0 -0
  90. {commonmeta_py-0.117 → commonmeta_py-0.119}/commonmeta/writers/schema_org_writer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commonmeta-py
3
- Version: 0.117
3
+ Version: 0.119
4
4
  Summary: Library for conversions to/from the Commonmeta scholarly metadata format
5
5
  Project-URL: Homepage, https://python.commonmeta.org
6
6
  Project-URL: Repository, https://github.com/front-matter/commonmeta-py
@@ -36,7 +36,7 @@ Requires-Dist: pyyaml>=5.4
36
36
  Requires-Dist: requests-toolbelt>=1.0.0
37
37
  Requires-Dist: requests>=2.31.0
38
38
  Requires-Dist: requests>=2.32.3
39
- Requires-Dist: setuptools>=70.3.0
39
+ Requires-Dist: setuptools<81,>=70.3.0
40
40
  Requires-Dist: simplejson~=3.18
41
41
  Requires-Dist: types-beautifulsoup4<5,>=4.11
42
42
  Requires-Dist: types-dateparser~=1.1
@@ -10,7 +10,7 @@ commonmeta-py is a Python library to convert scholarly metadata
10
10
  """
11
11
 
12
12
  __title__ = "commonmeta-py"
13
- __version__ = "0.117"
13
+ __version__ = "0.119"
14
14
  __author__ = "Martin Fenner"
15
15
  __license__ = "MIT"
16
16
 
@@ -342,7 +342,6 @@ def is_rogue_scholar_doi(doi: str, ra: str = "crossref") -> bool:
342
342
 
343
343
  def generate_wordpress_doi(prefix: str, slug: str, guid: str) -> str:
344
344
  """Generate a DOI from a WordPress GUID and slug"""
345
- import re
346
345
 
347
346
  if not prefix or not guid:
348
347
  return ""
@@ -44,16 +44,6 @@ def download_file(url: str) -> bytes:
44
44
  resp = requests.get(url, stream=True)
45
45
  resp.raise_for_status()
46
46
  return resp.content
47
- # # Progress bar
48
- # total = int(resp.headers.get("content-length", 0))
49
-
50
- # buf = io.BytesIO()
51
- # with tqdm(total=total, unit="B", unit_scale=True, desc="downloading") as bar:
52
- # for chunk in resp.iter_content(chunk_size=8192):
53
- # if chunk:
54
- # buf.write(chunk)
55
- # bar.update(len(chunk))
56
- # return buf.getvalue()
57
47
 
58
48
 
59
49
  def write_file(filename: str, output: bytes) -> None:
@@ -1,6 +1,7 @@
1
1
  """Crossref XML writer for commonmeta-py"""
2
2
 
3
3
  import io
4
+ import logging
4
5
  from datetime import datetime
5
6
  from time import time
6
7
  from typing import Optional
@@ -18,6 +19,8 @@ from ..constants import Commonmeta
18
19
  from ..doi_utils import doi_from_url, validate_doi
19
20
  from ..utils import validate_url
20
21
 
22
+ logger = logging.getLogger(__name__)
23
+
21
24
  POSTED_CONTENT_TYPES = [
22
25
  "preprint",
23
26
  "working_paper",
@@ -342,20 +345,25 @@ def write_crossref_xml(metadata: Commonmeta) -> Optional[str]:
342
345
 
343
346
  data = convert_crossref_xml(metadata)
344
347
  if data is None:
348
+ logger.error(f"Could not convert metadata to Crossref XML: {metadata.id}")
345
349
  return None
350
+
351
+ # Use the marshmallow schema to dump the data
346
352
  schema = CrossrefXMLSchema()
347
353
  crossref_xml = schema.dump(data)
348
354
 
349
- # Ensure the order of fields in the XML matches the expected order
355
+ # Ensure consistent field ordering through the defined mapping
350
356
  field_order = [MARSHMALLOW_MAP.get(k, k) for k in list(data.keys())]
351
357
  crossref_xml = {k: crossref_xml[k] for k in field_order if k in crossref_xml}
358
+
352
359
  # Convert to XML
353
360
  return unparse_xml(crossref_xml, dialect="crossref")
354
361
 
355
362
 
356
- def write_crossref_xml_list(metalist):
363
+ def write_crossref_xml_list(metalist) -> Optional[str]:
357
364
  """Write crossref_xml list"""
358
365
  if metalist is None or not metalist.is_valid:
366
+ logger.error("Invalid metalist provided for Crossref XML generation")
359
367
  return None
360
368
 
361
369
  schema = CrossrefXMLSchema()
@@ -380,15 +388,17 @@ def push_crossref_xml_list(metalist, login_id: str, login_passwd: str) -> bytes:
380
388
  """Push crossref_xml list to Crossref API, returns the API response."""
381
389
 
382
390
  input = write_crossref_xml_list(metalist)
391
+ if not input:
392
+ logger.error("Failed to generate XML for upload")
393
+ return "{}"
383
394
 
384
395
  # Convert string to bytes if necessary
385
396
  if isinstance(input, str):
386
397
  input = input.encode("utf-8")
387
398
 
388
- # The filename displayed in the Crossref admin interface, using the current UNIX timestamp
399
+ # The filename displayed in the Crossref admin interface
389
400
  filename = f"{int(time())}"
390
401
 
391
- # Create multipart form data
392
402
  multipart_data = MultipartEncoder(
393
403
  fields={
394
404
  "fname": (filename, io.BytesIO(input), "application/xml"),
@@ -398,38 +408,32 @@ def push_crossref_xml_list(metalist, login_id: str, login_passwd: str) -> bytes:
398
408
  }
399
409
  )
400
410
 
401
- # Set up the request
402
411
  post_url = "https://doi.crossref.org/servlet/deposit"
403
412
  headers = {"Content-Type": multipart_data.content_type}
413
+ resp = requests.post(post_url, data=multipart_data, headers=headers, timeout=10)
414
+ resp.raise_for_status()
415
+
416
+ # Parse the response
417
+ response = parse_xml(resp.content)
418
+ status = py_.get(response, "html.body.h2")
419
+ if status == "SUCCESS":
420
+ items = []
421
+ for item in metalist.items:
422
+ items.append(
423
+ {
424
+ "doi": item.id,
425
+ "updated": datetime.now().isoformat("T", "seconds"),
426
+ "status": "submitted",
427
+ }
428
+ )
404
429
 
405
- try:
406
- # Send the request
407
- resp = requests.post(post_url, data=multipart_data, headers=headers, timeout=10)
408
- resp.raise_for_status()
409
-
410
- # Parse the response
411
- response = parse_xml(resp.content)
412
- status = py_.get(response, "html.body.h2")
413
- if status == "SUCCESS":
414
- items = []
415
- for item in metalist.items:
416
- items.append(
417
- {
418
- "doi": item.id,
419
- "updated": datetime.now().isoformat("T", "seconds"),
420
- "status": "submitted",
421
- }
422
- )
423
-
424
- # orjson has different options
425
- return json.dumps(items, option=json.OPT_INDENT_2)
426
-
427
- # if there is an error
428
- message = py_.get(response, "html.body.p")
429
- raise CrossrefError(f"Error uploading batch: {message}")
430
+ # Return JSON response
431
+ return json.dumps(items, option=json.OPT_INDENT_2)
430
432
 
431
- except requests.exceptions.RequestException as e:
432
- raise CrossrefError(f"Error uploading batch: {str(e)}") from e
433
+ # Handle error response
434
+ message = py_.get(response, "html.body.p")
435
+ logger.error(f"Crossref API error: {message}")
436
+ return "{}"
433
437
 
434
438
 
435
439
  def get_attributes(obj, **kwargs) -> dict:
@@ -539,15 +543,16 @@ def get_institution(obj) -> Optional[dict]:
539
543
  def get_titles(obj) -> Optional[dict]:
540
544
  """get titles"""
541
545
 
542
- title = {}
546
+ titles = {}
543
547
  for t in wrap(py_.get(obj, "titles", [])):
544
548
  if isinstance(t, str):
545
- title["title"] = t
549
+ titles["title"] = t
546
550
  elif isinstance(t, dict) and t.get("titleType", None) == "Subtitle":
547
- title["subtitle"] = t.get("title", None)
548
- elif isinstance(title, dict):
549
- title["title"] = t.get("title", None)
550
- return title
551
+ titles["subtitle"] = t.get("title", None)
552
+ elif isinstance(t, dict):
553
+ titles["title"] = t.get("title", None)
554
+
555
+ return titles if titles else None
551
556
 
552
557
 
553
558
  def get_contributors(obj) -> Optional[dict]:
@@ -1,8 +1,9 @@
1
1
  """InvenioRDM writer for commonmeta-py"""
2
2
 
3
+ import logging
3
4
  import re
4
5
  from time import time
5
- from typing import Optional
6
+ from typing import Dict, Optional
6
7
  from urllib.parse import urlparse
7
8
 
8
9
  import orjson as json
@@ -15,6 +16,7 @@ from ..constants import (
15
16
  COMMUNITY_TRANSLATIONS,
16
17
  CROSSREF_FUNDER_ID_TO_ROR_TRANSLATIONS,
17
18
  INVENIORDM_IDENTIFIER_TYPES,
19
+ Commonmeta,
18
20
  )
19
21
  from ..date_utils import get_iso8601_date
20
22
  from ..doi_utils import doi_from_url, normalize_doi
@@ -28,6 +30,7 @@ from ..utils import (
28
30
  validate_ror,
29
31
  )
30
32
 
33
+ logger = logging.getLogger(__name__)
31
34
 
32
35
  def write_inveniordm(metadata):
33
36
  """Write inveniordm"""
@@ -384,30 +387,35 @@ def write_inveniordm_list(metalist):
384
387
  return [write_inveniordm(item) for item in metalist.items]
385
388
 
386
389
 
387
- def push_inveniordm(metadata, host: str, token: str, legacy_key: str):
390
+ def push_inveniordm(
391
+ metadata: Commonmeta,
392
+ host: str,
393
+ token: str,
394
+ legacy_key: str
395
+ ) -> Dict:
388
396
  """Push record to InvenioRDM"""
389
397
 
390
398
  record = {}
391
- input = write_inveniordm(metadata)
399
+ output = write_inveniordm(metadata)
392
400
 
393
401
  try:
394
402
  # Remove IsPartOf relation with InvenioRDM community identifier after storing it
395
- community_index = None
396
- if hasattr(metadata, "relations") and metadata.relations:
397
- for i, relation in enumerate(metadata.relations):
398
- if relation.get("type") == "IsPartOf" and relation.get(
399
- "id", ""
400
- ).startswith("https://rogue-scholar.org/api/communities/"):
401
- slug = relation.get("id").split("/")[5]
402
- community_id, _ = search_by_slug(slug, "blog", host, token)
403
- if community_id:
404
- record["community"] = slug
405
- record["community_id"] = community_id
406
- community_index = i
407
-
408
- # Remove the relation if we found and processed it
409
- if community_index is not None and hasattr(metadata, "relations"):
410
- metadata.relations.pop(community_index)
403
+ # community_index = None
404
+ # if hasattr(metadata, "relations") and metadata.relations:
405
+ # for i, relation in enumerate(metadata.relations):
406
+ # if relation.get("type") == "IsPartOf" and relation.get(
407
+ # "id", ""
408
+ # ).startswith("https://rogue-scholar.org/api/communities/"):
409
+ # slug = relation.get("id").split("/")[5]
410
+ # community_id, _ = search_by_slug(slug, "blog", host, token)
411
+ # if community_id:
412
+ # record["community"] = slug
413
+ # record["community_id"] = community_id
414
+ # community_index = i
415
+
416
+ # # Remove the relation if we found and processed it
417
+ # if community_index is not None and hasattr(metadata, "relations"):
418
+ # metadata.relations.pop(community_index)
411
419
 
412
420
  # Remove InvenioRDM rid after storing it
413
421
  # rid_index = None
@@ -431,10 +439,10 @@ def push_inveniordm(metadata, host: str, token: str, legacy_key: str):
431
439
  record = edit_published_record(record, host, token)
432
440
 
433
441
  # Update draft record
434
- record = update_draft_record(record, host, token, input)
442
+ record = update_draft_record(record, host, token, output)
435
443
  else:
436
444
  # Create draft record
437
- record = create_draft_record(record, host, token, input)
445
+ record = create_draft_record(record, host, token, output)
438
446
 
439
447
  # Publish draft record
440
448
  record = publish_draft_record(record, host, token)
@@ -450,7 +458,8 @@ def push_inveniordm(metadata, host: str, token: str, legacy_key: str):
450
458
 
451
459
  if hasattr(metadata, "subjects"):
452
460
  for subject in metadata.subjects:
453
- slug = string_to_slug(subject.get("subject", ""))
461
+ subject_name = subject.get("subject", "")
462
+ slug = string_to_slug(subject_name)
454
463
  if slug in COMMUNITY_TRANSLATIONS:
455
464
  slug = COMMUNITY_TRANSLATIONS[slug]
456
465
 
@@ -477,7 +486,11 @@ def push_inveniordm(metadata, host: str, token: str, legacy_key: str):
477
486
  if host == "rogue-scholar.org" and legacy_key is not None:
478
487
  record = update_legacy_record(record, legacy_key)
479
488
  except Exception as e:
480
- print(f"Unexpected error: {str(e)}")
489
+ logger.error(f"Unexpected error in push_inveniordm: {str(e)}", exc_info=True, extra={
490
+ "host": host,
491
+ "record_id": record.get("id")
492
+ })
493
+ record["status"] = "error"
481
494
 
482
495
  return record
483
496
 
@@ -504,15 +517,15 @@ def search_by_doi(doi, host, token) -> Optional[str]:
504
517
  )
505
518
  response.raise_for_status()
506
519
  data = response.json()
507
- if py_.get(data, "hits.total") or 0 > 0:
520
+ if py_.get(data, "hits.total", 0) > 0:
508
521
  return py_.get(data, "hits.hits.0.id")
509
522
  return None
510
523
  except requests.exceptions.RequestException as e:
511
- print(f"Error searching for DOI: {str(e)}")
524
+ logger.error(f"Error searching for DOI {doi}: {str(e)}", exc_info=True)
512
525
  return None
513
526
 
514
527
 
515
- def create_draft_record(record, host, token, input):
528
+ def create_draft_record(record, host, token, output):
516
529
  """Create a new draft record in InvenioRDM"""
517
530
  headers = {
518
531
  "Authorization": f"Bearer {token}",
@@ -520,23 +533,23 @@ def create_draft_record(record, host, token, input):
520
533
  }
521
534
  try:
522
535
  response = requests.post(
523
- f"https://{host}/api/records", headers=headers, json=input
536
+ f"https://{host}/api/records", headers=headers, json=output
524
537
  )
525
538
  if response.status_code == 429:
526
539
  record["status"] = "failed_rate_limited"
527
540
  return record
528
541
  if response.status_code != 201:
529
- print(response.json())
542
+ logger.error(f"Failed to create draft record: {response.status_code} - {response.json()}")
530
543
  record["status"] = "failed_create_draft"
531
544
  return record
532
545
  data = response.json()
533
- record["id"]: data.get("id", None)
546
+ record["id"] = data.get("id", None)
534
547
  record["created"] = data.get("created", None)
535
548
  record["updated"] = data.get("updated", None)
536
549
  record["status"] = "draft"
537
550
  return record
538
551
  except requests.exceptions.RequestException as e:
539
- print(f"Error creating draft record: {str(e)}")
552
+ logger.error(f"Error creating draft record: {str(e)}", exc_info=True)
540
553
  record["status"] = "error_draft"
541
554
  return record
542
555
 
@@ -557,7 +570,7 @@ def edit_published_record(record, host, token):
557
570
  record["status"] = "edited"
558
571
  return record
559
572
  except requests.exceptions.RequestException as e:
560
- print(f"Error creating draft from published record: {str(e)}")
573
+ logger.error(f"Error creating draft from published record: {str(e)}", exc_info=True)
561
574
  record["status"] = "error_edit_published_record"
562
575
  return record
563
576
 
@@ -581,7 +594,7 @@ def update_draft_record(record, host, token, inveniordm_data):
581
594
  record["status"] = "updated"
582
595
  return record
583
596
  except requests.exceptions.RequestException as e:
584
- print(f"Error updating draft record: {str(e)}")
597
+ logger.error(f"Error updating draft record: {str(e)}", exc_info=True)
585
598
  record["status"] = "error_update_draft_record"
586
599
  return record
587
600
 
@@ -604,8 +617,8 @@ def publish_draft_record(record, host, token):
604
617
  record["status"] = "failed_rate_limited"
605
618
  return record
606
619
  if response.status_code != 202:
607
- print(response.json())
608
- record["status"] = "failed_publish_draft"
620
+ logger.error(f"Failed to publish draft record: {response.status_code} - {response.json()}")
621
+ record["status"] = "error_publish_draft_record"
609
622
  return record
610
623
  data = response.json()
611
624
  record["uuid"] = py_.get(data, "metadata.identifiers.0.identifier")
@@ -614,7 +627,7 @@ def publish_draft_record(record, host, token):
614
627
  record["status"] = "published"
615
628
  return record
616
629
  except requests.exceptions.RequestException as e:
617
- print(f"Error publishing draft record: {str(e)}")
630
+ logger.error(f"Error publishing draft record: {str(e)}", exc_info=True)
618
631
  record["status"] = "error_publish_draft_record"
619
632
  return record
620
633
 
@@ -634,7 +647,7 @@ def add_record_to_community(record, host, token, community_id):
634
647
  response.raise_for_status()
635
648
  return record
636
649
  except requests.exceptions.RequestException as e:
637
- print(f"Error adding record to community: {str(e)}")
650
+ logger.error(f"Error adding record to community: {str(e)}", exc_info=True)
638
651
  return record
639
652
 
640
653
 
@@ -682,7 +695,7 @@ def update_legacy_record(record, legacy_key: str):
682
695
  return record
683
696
 
684
697
  except requests.exceptions.RequestException as e:
685
- print(f"Error updating legacy record: {str(e)}")
698
+ logger.error(f"Error updating legacy record: {str(e)}", exc_info=True)
686
699
  record["status"] = "error_update_legacy_record"
687
700
  return record
688
701
 
@@ -700,11 +713,11 @@ def search_by_slug(slug, type_value, host, token) -> Optional[str]:
700
713
  )
701
714
  response.raise_for_status()
702
715
  data = response.json()
703
- if py_.get(data, "hits.total") or 0 > 0:
716
+ if py_.get(data, "hits.total", 0) > 0:
704
717
  return py_.get(data, "hits.hits.0.id")
705
718
  return None
706
719
  except requests.exceptions.RequestException as e:
707
- print(f"Error searching for community: {str(e)}")
720
+ logger.error(f"Error searching for community: {str(e)}", exc_info=True)
708
721
  return None
709
722
 
710
723
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "commonmeta-py"
3
- version = "0.117"
3
+ version = "0.119"
4
4
  description = "Library for conversions to/from the Commonmeta scholarly metadata format"
5
5
  authors = [{ name = "Martin Fenner", email = "martin@front-matter.io" }]
6
6
  requires-python = ">=3.9,<4.0"
@@ -52,7 +52,7 @@ dependencies = [
52
52
  "marshmallow-utils>=0.10.0",
53
53
  "xmlschema>=4.0.1",
54
54
  "requests-toolbelt>=1.0.0",
55
- "setuptools>=70.3.0",
55
+ "setuptools>=70.3.0,<81",
56
56
  ]
57
57
 
58
58
  [project.urls]
File without changes
File without changes
File without changes