destiny_sdk 0.7.3__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.
Files changed (38) hide show
  1. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/PKG-INFO +1 -1
  2. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/pyproject.toml +1 -1
  3. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/enhancements.py +46 -1
  4. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/identifiers.py +5 -2
  5. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_enhancements.py +51 -0
  6. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/.gitignore +0 -0
  7. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/LICENSE +0 -0
  8. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/README.md +0 -0
  9. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/__init__.py +0 -0
  10. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/auth.py +0 -0
  11. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/client.py +0 -0
  12. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/core.py +0 -0
  13. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/imports.py +0 -0
  14. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/labs/__init__.py +0 -0
  15. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/labs/references.py +0 -0
  16. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/__init__.py +0 -0
  17. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/eppi_parser.py +0 -0
  18. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/parsers/exceptions.py +0 -0
  19. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/py.typed +0 -0
  20. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/references.py +0 -0
  21. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/robots.py +0 -0
  22. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/search.py +0 -0
  23. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/src/destiny_sdk/visibility.py +0 -0
  24. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/__init__.py +0 -0
  25. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/conftest.py +0 -0
  26. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/labs/test_references.py +0 -0
  27. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/parsers/test_eppi_parser.py +0 -0
  28. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_auth.py +0 -0
  29. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_client.py +0 -0
  30. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_data/destiny_references.jsonl +0 -0
  31. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import.jsonl +0 -0
  32. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import_with_annotations.jsonl +0 -0
  33. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_import_with_raw.jsonl +0 -0
  34. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_data/eppi_report.json +0 -0
  35. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_identifiers.py +0 -0
  36. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_references.py +0 -0
  37. {destiny_sdk-0.7.3 → destiny_sdk-0.7.4}/tests/unit/test_robots.py +0 -0
  38. {destiny_sdk-0.7.3 → 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
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
@@ -35,7 +35,7 @@ license = "Apache-2.0"
35
35
  name = "destiny_sdk"
36
36
  readme = "README.md"
37
37
  requires-python = "~=3.12"
38
- version = "0.7.3"
38
+ version = "0.7.4"
39
39
 
40
40
  [project.optional-dependencies]
41
41
  labs = []
@@ -8,6 +8,7 @@ from typing import Annotated, Any, Literal, Self
8
8
  from pydantic import UUID4, BaseModel, Field, HttpUrl, model_validator
9
9
 
10
10
  from destiny_sdk.core import _JsonlFileInputMixIn
11
+ from destiny_sdk.identifiers import Identifier
11
12
  from destiny_sdk.visibility import Visibility
12
13
 
13
14
 
@@ -26,6 +27,8 @@ class EnhancementType(StrEnum):
26
27
  """A free-form enhancement for tagging with labels."""
27
28
  LOCATION = auto()
28
29
  """Locations where the reference can be found."""
30
+ REFERENCE_ASSOCIATION = auto()
31
+ """Associations to other references."""
29
32
  RAW = auto()
30
33
  """A free form enhancement for arbitrary/unstructured data."""
31
34
  FULL_TEXT = auto()
@@ -56,7 +59,11 @@ class Authorship(BaseModel):
56
59
  for our purposes.
57
60
  """
58
61
 
59
- display_name: str = Field(description="The display name of the author.")
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
+ )
60
67
  orcid: str | None = Field(default=None, description="The ORCid of the author.")
61
68
  position: AuthorPosition = Field(
62
69
  description="The position of the author within the list of authors."
@@ -320,6 +327,43 @@ class LocationEnhancement(BaseModel):
320
327
  )
321
328
 
322
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
+
323
367
  class RawEnhancement(BaseModel):
324
368
  """
325
369
  An enhancement for storing raw/arbitrary/unstructured data.
@@ -377,6 +421,7 @@ EnhancementContent = Annotated[
377
421
  | AbstractContentEnhancement
378
422
  | AnnotationEnhancement
379
423
  | LocationEnhancement
424
+ | ReferenceAssociationEnhancement
380
425
  | RawEnhancement,
381
426
  Field(discriminator="enhancement_type"),
382
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: ExternalIdentifier | UUID4) -> Self:
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) -> ExternalIdentifier | UUID4:
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)
@@ -173,3 +173,54 @@ def test_empty_location_enhancement_errors():
173
173
  enhancement_type=destiny_sdk.enhancements.EnhancementType.LOCATION,
174
174
  locations=[],
175
175
  )
176
+
177
+
178
+ def test_association_enhancement_valid():
179
+ # Create valid association content
180
+ association_content = destiny_sdk.enhancements.ReferenceAssociationEnhancement(
181
+ enhancement_type=destiny_sdk.enhancements.EnhancementType.REFERENCE_ASSOCIATION,
182
+ associated_reference_ids=[
183
+ uuid.uuid4(),
184
+ destiny_sdk.identifiers.OpenAlexIdentifier(
185
+ identifier="https://openalex.org/W1234567890",
186
+ identifier_type=destiny_sdk.identifiers.ExternalIdentifierType.OPEN_ALEX,
187
+ ),
188
+ ],
189
+ association_type=destiny_sdk.enhancements.ReferenceAssociationType.CITES,
190
+ )
191
+ enhancement = destiny_sdk.enhancements.Enhancement(
192
+ id=uuid.uuid4(),
193
+ source="test_source",
194
+ visibility="public",
195
+ robot_version="1.0",
196
+ enhancement_type=destiny_sdk.enhancements.EnhancementType.REFERENCE_ASSOCIATION,
197
+ content=association_content,
198
+ reference_id=uuid.uuid4(),
199
+ )
200
+ assert (
201
+ enhancement.content.association_type
202
+ == destiny_sdk.enhancements.ReferenceAssociationType.CITES
203
+ )
204
+ assert enhancement.content.associated_reference_ids[1].identifier == "W1234567890"
205
+
206
+
207
+ def test_association_enhancement_empty_associated_reference_ids_errors():
208
+ # Test that an empty associated_reference_ids list raises a validation error
209
+ with pytest.raises(ValidationError):
210
+ destiny_sdk.enhancements.ReferenceAssociationEnhancement(
211
+ enhancement_type=destiny_sdk.enhancements.EnhancementType.REFERENCE_ASSOCIATION,
212
+ associated_reference_ids=[],
213
+ association_type=destiny_sdk.enhancements.ReferenceAssociationType.CITES,
214
+ )
215
+
216
+
217
+ def test_association_enhancement_invalid_identifier_type_errors():
218
+ # Test that an invalid identifier type raises a validation error
219
+ with pytest.raises(ValidationError):
220
+ destiny_sdk.enhancements.ReferenceAssociationEnhancement(
221
+ enhancement_type=destiny_sdk.enhancements.EnhancementType.REFERENCE_ASSOCIATION,
222
+ associated_reference_ids=[
223
+ "random-string",
224
+ ],
225
+ association_type=destiny_sdk.enhancements.ReferenceAssociationType.CITES,
226
+ )
File without changes
File without changes
File without changes
File without changes