commonmeta-py 0.116__py3-none-any.whl → 0.118__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.
- commonmeta/__init__.py +1 -1
- commonmeta/writers/inveniordm_writer.py +95 -71
- {commonmeta_py-0.116.dist-info → commonmeta_py-0.118.dist-info}/METADATA +1 -1
- {commonmeta_py-0.116.dist-info → commonmeta_py-0.118.dist-info}/RECORD +7 -7
- {commonmeta_py-0.116.dist-info → commonmeta_py-0.118.dist-info}/WHEEL +0 -0
- {commonmeta_py-0.116.dist-info → commonmeta_py-0.118.dist-info}/entry_points.txt +0 -0
- {commonmeta_py-0.116.dist-info → commonmeta_py-0.118.dist-info}/licenses/LICENSE +0 -0
commonmeta/__init__.py
CHANGED
@@ -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 Any, Dict, Optional, Tuple
|
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,7 +387,12 @@ def write_inveniordm_list(metalist):
|
|
384
387
|
return [write_inveniordm(item) for item in metalist.items]
|
385
388
|
|
386
389
|
|
387
|
-
def push_inveniordm(
|
390
|
+
def push_inveniordm(
|
391
|
+
metadata: Commonmeta,
|
392
|
+
host: str,
|
393
|
+
token: str,
|
394
|
+
legacy_key: str
|
395
|
+
) -> Tuple[Dict[str, Any], Optional[Exception]]:
|
388
396
|
"""Push record to InvenioRDM"""
|
389
397
|
|
390
398
|
record = {}
|
@@ -392,22 +400,22 @@ def push_inveniordm(metadata, host: str, token: str, legacy_key: str):
|
|
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
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
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
|
@@ -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
|
-
|
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
|
-
|
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,11 +517,12 @@ 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"
|
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
|
-
|
524
|
+
logger.error(f"Error searching for DOI {doi}: {str(e)}", exc_info=True)
|
525
|
+
return None
|
512
526
|
|
513
527
|
|
514
528
|
def create_draft_record(record, host, token, input):
|
@@ -525,17 +539,19 @@ def create_draft_record(record, host, token, input):
|
|
525
539
|
record["status"] = "failed_rate_limited"
|
526
540
|
return record
|
527
541
|
if response.status_code != 201:
|
528
|
-
|
542
|
+
logger.error(f"Failed to create draft record: {response.status_code} - {response.json()}")
|
529
543
|
record["status"] = "failed_create_draft"
|
530
544
|
return record
|
531
545
|
data = response.json()
|
532
|
-
record["id"]
|
546
|
+
record["id"] = data.get("id", None)
|
533
547
|
record["created"] = data.get("created", None)
|
534
548
|
record["updated"] = data.get("updated", None)
|
535
549
|
record["status"] = "draft"
|
536
550
|
return record
|
537
551
|
except requests.exceptions.RequestException as e:
|
538
|
-
|
552
|
+
logger.error(f"Error creating draft record: {str(e)}", exc_info=True)
|
553
|
+
record["status"] = "error_draft"
|
554
|
+
return record
|
539
555
|
|
540
556
|
|
541
557
|
def edit_published_record(record, host, token):
|
@@ -554,7 +570,9 @@ def edit_published_record(record, host, token):
|
|
554
570
|
record["status"] = "edited"
|
555
571
|
return record
|
556
572
|
except requests.exceptions.RequestException as e:
|
557
|
-
|
573
|
+
logger.error(f"Error creating draft from published record: {str(e)}", exc_info=True)
|
574
|
+
record["status"] = "error_edit_published_record"
|
575
|
+
return record
|
558
576
|
|
559
577
|
|
560
578
|
def update_draft_record(record, host, token, inveniordm_data):
|
@@ -576,7 +594,9 @@ def update_draft_record(record, host, token, inveniordm_data):
|
|
576
594
|
record["status"] = "updated"
|
577
595
|
return record
|
578
596
|
except requests.exceptions.RequestException as e:
|
579
|
-
|
597
|
+
logger.error(f"Error updating draft record: {str(e)}", exc_info=True)
|
598
|
+
record["status"] = "error_update_draft_record"
|
599
|
+
return record
|
580
600
|
|
581
601
|
|
582
602
|
def publish_draft_record(record, host, token):
|
@@ -585,9 +605,10 @@ def publish_draft_record(record, host, token):
|
|
585
605
|
"Authorization": f"Bearer {token}",
|
586
606
|
"Content-Type": "application/json",
|
587
607
|
}
|
588
|
-
if not record.get("id", None):
|
589
|
-
raise InvenioRDMError("Error publishing draft record")
|
590
608
|
try:
|
609
|
+
if not record.get("id", None):
|
610
|
+
raise InvenioRDMError("Missing record id")
|
611
|
+
|
591
612
|
response = requests.post(
|
592
613
|
f"https://{host}/api/records/{record['id']}/draft/actions/publish",
|
593
614
|
headers=headers,
|
@@ -596,8 +617,8 @@ def publish_draft_record(record, host, token):
|
|
596
617
|
record["status"] = "failed_rate_limited"
|
597
618
|
return record
|
598
619
|
if response.status_code != 202:
|
599
|
-
|
600
|
-
record["status"] = "
|
620
|
+
logger.error(f"Failed to publish draft record: {response.status_code} - {response.json()}")
|
621
|
+
record["status"] = "error_publish_draft_record"
|
601
622
|
return record
|
602
623
|
data = response.json()
|
603
624
|
record["uuid"] = py_.get(data, "metadata.identifiers.0.identifier")
|
@@ -606,7 +627,9 @@ def publish_draft_record(record, host, token):
|
|
606
627
|
record["status"] = "published"
|
607
628
|
return record
|
608
629
|
except requests.exceptions.RequestException as e:
|
609
|
-
|
630
|
+
logger.error(f"Error publishing draft record: {str(e)}", exc_info=True)
|
631
|
+
record["status"] = "error_publish_draft_record"
|
632
|
+
return record
|
610
633
|
|
611
634
|
|
612
635
|
def add_record_to_community(record, host, token, community_id):
|
@@ -624,49 +647,47 @@ def add_record_to_community(record, host, token, community_id):
|
|
624
647
|
response.raise_for_status()
|
625
648
|
return record
|
626
649
|
except requests.exceptions.RequestException as e:
|
627
|
-
|
650
|
+
logger.error(f"Error adding record to community: {str(e)}", exc_info=True)
|
651
|
+
return record
|
628
652
|
|
629
653
|
|
630
654
|
def update_legacy_record(record, legacy_key: str):
|
631
655
|
"""Update corresponding record in Rogue Scholar legacy database."""
|
632
656
|
|
633
657
|
legacy_host = "bosczcmeodcrajtcaddf.supabase.co"
|
634
|
-
|
635
|
-
if not legacy_key:
|
636
|
-
raise ValueError("no legacy key provided")
|
637
|
-
if not record.get("uuid", None):
|
638
|
-
raise ValueError("no UUID provided")
|
639
|
-
|
640
|
-
now = f"{int(time())}"
|
641
|
-
if record.get("id", None) is not None:
|
642
|
-
output = {
|
643
|
-
"rid": record.get("id"),
|
644
|
-
"indexed_at": now,
|
645
|
-
"indexed": "true",
|
646
|
-
"archived": "true",
|
647
|
-
}
|
648
|
-
elif record.get("doi", None) is not None:
|
649
|
-
output = {
|
650
|
-
"doi": record.get("doi"),
|
651
|
-
"indexed_at": now,
|
652
|
-
"indexed": "true",
|
653
|
-
"archived": "true",
|
654
|
-
}
|
655
|
-
else:
|
656
|
-
print(f"nothing to update for id {record.get("uuid")}")
|
657
|
-
return record # nothing to update
|
658
|
-
|
659
|
-
request_url = f"https://{legacy_host}/rest/v1/posts?id=eq.{record['uuid']}"
|
660
|
-
headers = {
|
661
|
-
"Content-Type": "application/json",
|
662
|
-
"apikey": legacy_key,
|
663
|
-
"Authorization": f"Bearer {legacy_key}",
|
664
|
-
"Prefer": "return=minimal",
|
665
|
-
}
|
666
|
-
|
667
658
|
try:
|
659
|
+
if not legacy_key:
|
660
|
+
raise ValueError("no legacy key provided")
|
661
|
+
if not record.get("uuid", None):
|
662
|
+
raise ValueError("no UUID provided")
|
663
|
+
|
664
|
+
now = f"{int(time())}"
|
665
|
+
if record.get("id", None) is not None:
|
666
|
+
output = {
|
667
|
+
"rid": record.get("id"),
|
668
|
+
"indexed_at": now,
|
669
|
+
"indexed": "true",
|
670
|
+
"archived": "true",
|
671
|
+
}
|
672
|
+
elif record.get("doi", None) is not None:
|
673
|
+
output = {
|
674
|
+
"doi": record.get("doi"),
|
675
|
+
"indexed_at": now,
|
676
|
+
"indexed": "true",
|
677
|
+
"archived": "true",
|
678
|
+
}
|
679
|
+
else:
|
680
|
+
print(f"nothing to update for id {record.get("uuid")}")
|
681
|
+
return record # nothing to update
|
682
|
+
|
683
|
+
request_url = f"https://{legacy_host}/rest/v1/posts?id=eq.{record['uuid']}"
|
684
|
+
headers = {
|
685
|
+
"Content-Type": "application/json",
|
686
|
+
"apikey": legacy_key,
|
687
|
+
"Authorization": f"Bearer {legacy_key}",
|
688
|
+
"Prefer": "return=minimal",
|
689
|
+
}
|
668
690
|
response = requests.patch(request_url, json=output, headers=headers, timeout=30)
|
669
|
-
response.raise_for_status()
|
670
691
|
if response.status_code != 204:
|
671
692
|
return Exception(f"Unexpected status code: {response.status_code}")
|
672
693
|
|
@@ -674,7 +695,9 @@ def update_legacy_record(record, legacy_key: str):
|
|
674
695
|
return record
|
675
696
|
|
676
697
|
except requests.exceptions.RequestException as e:
|
677
|
-
|
698
|
+
logger.error(f"Error updating legacy record: {str(e)}", exc_info=True)
|
699
|
+
record["status"] = "error_update_legacy_record"
|
700
|
+
return record
|
678
701
|
|
679
702
|
|
680
703
|
def search_by_slug(slug, type_value, host, token) -> Optional[str]:
|
@@ -690,15 +713,16 @@ def search_by_slug(slug, type_value, host, token) -> Optional[str]:
|
|
690
713
|
)
|
691
714
|
response.raise_for_status()
|
692
715
|
data = response.json()
|
693
|
-
if py_.get(data, "hits.total"
|
716
|
+
if py_.get(data, "hits.total", 0) > 0:
|
694
717
|
return py_.get(data, "hits.hits.0.id")
|
695
718
|
return None
|
696
719
|
except requests.exceptions.RequestException as e:
|
697
|
-
|
720
|
+
logger.error(f"Error searching for community: {str(e)}", exc_info=True)
|
721
|
+
return None
|
698
722
|
|
699
723
|
|
700
724
|
def string_to_slug(text):
|
701
|
-
"""
|
725
|
+
"""makes a string lowercase and removes non-alphanumeric characters"""
|
702
726
|
# Replace spaces with hyphens
|
703
727
|
slug = re.sub(r"\s+", "-", text.lower())
|
704
728
|
# Remove special characters
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: commonmeta-py
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.118
|
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
|
@@ -1,4 +1,4 @@
|
|
1
|
-
commonmeta/__init__.py,sha256=
|
1
|
+
commonmeta/__init__.py,sha256=RbBIG26IxRjdvGzHH77sogy-rtAEHC51It7TQ6wPjS0,2098
|
2
2
|
commonmeta/api_utils.py,sha256=y5KLfIOWOjde7LXZ36u-eneQJ-Q53yXUZg3hWpCBS2E,2685
|
3
3
|
commonmeta/author_utils.py,sha256=3lYW5s1rOUWNTKs1FP6XLfEUY3yCLOe_3L_VdJTDMp0,8585
|
4
4
|
commonmeta/base_utils.py,sha256=-MGy9q2uTiJEkPWQUYOJMdq-3tRpNnvBwlLjvllQ5g8,11164
|
@@ -80,11 +80,11 @@ commonmeta/writers/commonmeta_writer.py,sha256=QpfyhG__7o_XpsOTCPWxGymO7YKwZi2LQ
|
|
80
80
|
commonmeta/writers/crossref_xml_writer.py,sha256=d-Rb2Vd_g3UW8GM4APIT7fivSQ5GMssZ6Ubi3OykHaw,33479
|
81
81
|
commonmeta/writers/csl_writer.py,sha256=4gDYs1EzK4_L2UIRTfs25wgHmYRwdRP2zmfxF9387oU,2779
|
82
82
|
commonmeta/writers/datacite_writer.py,sha256=bcinpwhq7XnVthKHH8-sdXA34dSlvFH4ImYH768iaQU,6428
|
83
|
-
commonmeta/writers/inveniordm_writer.py,sha256=
|
83
|
+
commonmeta/writers/inveniordm_writer.py,sha256=el4Eapa9HHg1ceddHb9rd4d1MAsM1ZBZ1F4jQUV8mbI,25717
|
84
84
|
commonmeta/writers/ris_writer.py,sha256=3SdyEvMRaPRP1SV1MB-MXBlunE7x6og7RF1zuWtetPc,2094
|
85
85
|
commonmeta/writers/schema_org_writer.py,sha256=s18_x0ReXwAGBoEAwp2q-HCgFQ-h5qRg6JyAlqCoSFE,5871
|
86
|
-
commonmeta_py-0.
|
87
|
-
commonmeta_py-0.
|
88
|
-
commonmeta_py-0.
|
89
|
-
commonmeta_py-0.
|
90
|
-
commonmeta_py-0.
|
86
|
+
commonmeta_py-0.118.dist-info/METADATA,sha256=BD1a2ouuh4hYizCty5tBGQuQM3m6LWVf1zfmTQwnFPU,7652
|
87
|
+
commonmeta_py-0.118.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
88
|
+
commonmeta_py-0.118.dist-info/entry_points.txt,sha256=U4w4BoRuS3rN5t5Y-uYSyOeU5Lh_VRVMS9OIDzIgw4w,50
|
89
|
+
commonmeta_py-0.118.dist-info/licenses/LICENSE,sha256=wsIvxF9Q9GC9vA_s79zTWP3BkXJdfUNRmALlU8GbW1s,1074
|
90
|
+
commonmeta_py-0.118.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|