destiny_sdk 0.7.2__tar.gz → 0.7.4__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.
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/PKG-INFO +1 -1
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/pyproject.toml +1 -1
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/enhancements.py +84 -1
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/identifiers.py +5 -2
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_data/destiny_references.jsonl +9 -9
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_enhancements.py +52 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_references.py +1 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/.gitignore +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/LICENSE +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/README.md +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/__init__.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/auth.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/client.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/core.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/imports.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/labs/__init__.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/labs/references.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/__init__.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/eppi_parser.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/exceptions.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/py.typed +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/references.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/robots.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/search.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/src/destiny_sdk/visibility.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/__init__.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/conftest.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/labs/test_references.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/parsers/test_eppi_parser.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_auth.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_client.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import.jsonl +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import_with_annotations.jsonl +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import_with_raw.jsonl +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_report.json +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_identifiers.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/tests/unit/test_robots.py +0 -0
- {destiny_sdk-0.7.2 → destiny_sdk-0.7.4}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: destiny_sdk
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Summary: A software development kit (sdk) to support interaction with the DESTINY repository
|
|
5
5
|
Author-email: Adam Hamilton <adam@futureevidence.org>, Andrew Harvey <andrew@futureevidence.org>, Daniel Breves <daniel@futureevidence.org>, Jack Walmisley <jack@futureevidence.org>, Tim Repke <tim.repke@pik-potsdam.de>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""Enhancement classes for the Destiny Repository."""
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
|
+
import json
|
|
4
5
|
from enum import StrEnum, auto
|
|
5
6
|
from typing import Annotated, Any, Literal, Self
|
|
6
7
|
|
|
7
8
|
from pydantic import UUID4, BaseModel, Field, HttpUrl, model_validator
|
|
8
9
|
|
|
9
10
|
from destiny_sdk.core import _JsonlFileInputMixIn
|
|
11
|
+
from destiny_sdk.identifiers import Identifier
|
|
10
12
|
from destiny_sdk.visibility import Visibility
|
|
11
13
|
|
|
12
14
|
|
|
@@ -25,6 +27,8 @@ class EnhancementType(StrEnum):
|
|
|
25
27
|
"""A free-form enhancement for tagging with labels."""
|
|
26
28
|
LOCATION = auto()
|
|
27
29
|
"""Locations where the reference can be found."""
|
|
30
|
+
REFERENCE_ASSOCIATION = auto()
|
|
31
|
+
"""Associations to other references."""
|
|
28
32
|
RAW = auto()
|
|
29
33
|
"""A free form enhancement for arbitrary/unstructured data."""
|
|
30
34
|
FULL_TEXT = auto()
|
|
@@ -55,7 +59,11 @@ class Authorship(BaseModel):
|
|
|
55
59
|
for our purposes.
|
|
56
60
|
"""
|
|
57
61
|
|
|
58
|
-
display_name: str = Field(
|
|
62
|
+
display_name: str = Field(
|
|
63
|
+
description="The display name of the author. "
|
|
64
|
+
"Expected format FIRSTNAME <MIDDLENAME> LASTNAME. "
|
|
65
|
+
"Providing display_name in an unexpected format will affect search performance."
|
|
66
|
+
)
|
|
59
67
|
orcid: str | None = Field(default=None, description="The ORCid of the author.")
|
|
60
68
|
position: AuthorPosition = Field(
|
|
61
69
|
description="The position of the author within the list of authors."
|
|
@@ -87,6 +95,10 @@ other works have cited this work
|
|
|
87
95
|
created_date: datetime.date | None = Field(
|
|
88
96
|
default=None, description="The ISO8601 date this metadata record was created"
|
|
89
97
|
)
|
|
98
|
+
updated_date: datetime.date | None = Field(
|
|
99
|
+
default=None,
|
|
100
|
+
description="The ISO8601 date of the last OpenAlex update to this metadata",
|
|
101
|
+
)
|
|
90
102
|
publication_date: datetime.date | None = Field(
|
|
91
103
|
default=None, description="The date which the version of record was published."
|
|
92
104
|
)
|
|
@@ -100,6 +112,20 @@ other works have cited this work
|
|
|
100
112
|
)
|
|
101
113
|
title: str | None = Field(default=None, description="The title of the reference.")
|
|
102
114
|
|
|
115
|
+
@property
|
|
116
|
+
def fingerprint(self) -> str:
|
|
117
|
+
"""
|
|
118
|
+
The fingerprint of this bibliographic metadata enhancement.
|
|
119
|
+
|
|
120
|
+
Excludes updated_at from the fingerprint calculation, meaning
|
|
121
|
+
that two raw enhancements with identical data but different export dates
|
|
122
|
+
will be considered the same.
|
|
123
|
+
"""
|
|
124
|
+
return json.dumps(
|
|
125
|
+
self.model_dump(mode="json", exclude={"updated_date"}, exclude_none=True),
|
|
126
|
+
sort_keys=True,
|
|
127
|
+
)
|
|
128
|
+
|
|
103
129
|
|
|
104
130
|
class AbstractProcessType(StrEnum):
|
|
105
131
|
"""The process used to acquire the abstract."""
|
|
@@ -301,6 +327,43 @@ class LocationEnhancement(BaseModel):
|
|
|
301
327
|
)
|
|
302
328
|
|
|
303
329
|
|
|
330
|
+
class ReferenceAssociationType(StrEnum):
|
|
331
|
+
"""
|
|
332
|
+
The type of association between references.
|
|
333
|
+
|
|
334
|
+
Direction is important: "this reference <association_type> associated reference".
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
CITES = auto()
|
|
338
|
+
"""This reference cites the related reference."""
|
|
339
|
+
IS_CITED_BY = auto()
|
|
340
|
+
"""This reference is cited by the related reference."""
|
|
341
|
+
IS_SIMILAR_TO = auto()
|
|
342
|
+
"""This reference is similar to the related reference."""
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class ReferenceAssociationEnhancement(BaseModel):
|
|
346
|
+
"""An enhancement for storing associations between references."""
|
|
347
|
+
|
|
348
|
+
enhancement_type: Literal[EnhancementType.REFERENCE_ASSOCIATION] = (
|
|
349
|
+
EnhancementType.REFERENCE_ASSOCIATION
|
|
350
|
+
)
|
|
351
|
+
associated_reference_ids: list[Identifier] = Field(
|
|
352
|
+
min_length=1,
|
|
353
|
+
description=(
|
|
354
|
+
"A list of Identifiers which are associated to this reference. "
|
|
355
|
+
"These can either be ExternalIdentifiers or resolved repository UUID4s."
|
|
356
|
+
),
|
|
357
|
+
)
|
|
358
|
+
association_type: ReferenceAssociationType = Field(
|
|
359
|
+
description=(
|
|
360
|
+
"The type of association between this reference and the associated ones. "
|
|
361
|
+
"Direction is important: "
|
|
362
|
+
'"this reference <association_type> associated reference".'
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
|
|
304
367
|
class RawEnhancement(BaseModel):
|
|
305
368
|
"""
|
|
306
369
|
An enhancement for storing raw/arbitrary/unstructured data.
|
|
@@ -332,6 +395,25 @@ class RawEnhancement(BaseModel):
|
|
|
332
395
|
raise ValueError(msg)
|
|
333
396
|
return self
|
|
334
397
|
|
|
398
|
+
@property
|
|
399
|
+
def fingerprint(self) -> str:
|
|
400
|
+
"""
|
|
401
|
+
The unique fingerprint of this raw enhancement.
|
|
402
|
+
|
|
403
|
+
Excludes the source_export_date from the fingerprint calculation, meaning
|
|
404
|
+
that two raw enhancements with identical data but different export dates
|
|
405
|
+
will be considered the same.
|
|
406
|
+
|
|
407
|
+
Unstructured data in `data` and `metadata` is included in the fingerprint,
|
|
408
|
+
sorted by key.
|
|
409
|
+
"""
|
|
410
|
+
return json.dumps(
|
|
411
|
+
self.model_dump(
|
|
412
|
+
mode="json", exclude={"source_export_date"}, exclude_none=True
|
|
413
|
+
),
|
|
414
|
+
sort_keys=True,
|
|
415
|
+
)
|
|
416
|
+
|
|
335
417
|
|
|
336
418
|
#: Union type for all enhancement content types.
|
|
337
419
|
EnhancementContent = Annotated[
|
|
@@ -339,6 +421,7 @@ EnhancementContent = Annotated[
|
|
|
339
421
|
| AbstractContentEnhancement
|
|
340
422
|
| AnnotationEnhancement
|
|
341
423
|
| LocationEnhancement
|
|
424
|
+
| ReferenceAssociationEnhancement
|
|
342
425
|
| RawEnhancement,
|
|
343
426
|
Field(discriminator="enhancement_type"),
|
|
344
427
|
]
|
|
@@ -165,6 +165,9 @@ ExternalIdentifier = Annotated[
|
|
|
165
165
|
Field(discriminator="identifier_type"),
|
|
166
166
|
]
|
|
167
167
|
|
|
168
|
+
#: Any identifier including external identifiers and repository UUID4s.
|
|
169
|
+
Identifier = Annotated[ExternalIdentifier | UUID4, Field()]
|
|
170
|
+
|
|
168
171
|
ExternalIdentifierAdapter: TypeAdapter[ExternalIdentifier] = TypeAdapter(
|
|
169
172
|
ExternalIdentifier
|
|
170
173
|
)
|
|
@@ -245,7 +248,7 @@ class IdentifierLookup(BaseModel):
|
|
|
245
248
|
)
|
|
246
249
|
|
|
247
250
|
@classmethod
|
|
248
|
-
def from_identifier(cls, identifier:
|
|
251
|
+
def from_identifier(cls, identifier: Identifier) -> Self:
|
|
249
252
|
"""Create an IdentifierLookup from an ExternalIdentifier or UUID4."""
|
|
250
253
|
if isinstance(identifier, uuid.UUID):
|
|
251
254
|
return cls(identifier=str(identifier), identifier_type=None)
|
|
@@ -255,7 +258,7 @@ class IdentifierLookup(BaseModel):
|
|
|
255
258
|
other_identifier_name=getattr(identifier, "other_identifier_name", None),
|
|
256
259
|
)
|
|
257
260
|
|
|
258
|
-
def to_identifier(self) ->
|
|
261
|
+
def to_identifier(self) -> Identifier:
|
|
259
262
|
"""Convert into an ExternalIdentifier or UUID4 if it has no identifier_type."""
|
|
260
263
|
if self.identifier_type is None:
|
|
261
264
|
return UUID4(self.identifier)
|