pyPreservica 3.2.0__py3-none-any.whl → 3.2.1__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.
pyPreservica/__init__.py CHANGED
@@ -35,6 +35,6 @@ from .settingsAPI import SettingsAPI
35
35
  __author__ = "James Carr (drjamescarr@gmail.com)"
36
36
 
37
37
  # Version of the pyPreservica package
38
- __version__ = "3.2.0"
38
+ __version__ = "3.2.1"
39
39
 
40
40
  __license__ = "Apache License Version 2.0"
pyPreservica/common.py CHANGED
@@ -27,6 +27,7 @@ from requests import Session
27
27
  from urllib3.util import Retry
28
28
  import requests
29
29
  from requests.adapters import HTTPAdapter
30
+ from typing import TypeVar
30
31
 
31
32
  import pyPreservica
32
33
 
@@ -420,6 +421,26 @@ class Bitstream:
420
421
  return self.__str__()
421
422
 
422
423
 
424
+ class ExternIdentifier:
425
+ """
426
+ Class to represent the External Identifier Object in the Preservica data model
427
+ """
428
+
429
+ def __init__(self, identifier_type: str, identifier_value: str):
430
+ self.type = identifier_type
431
+ self.value = identifier_value
432
+ self.id = None
433
+
434
+ def __str__(self):
435
+ return f"""
436
+ Identifier: {self.id}
437
+ Identifier Type: {self.type}
438
+ Identifier Value: {self.value}
439
+ """
440
+
441
+ def __repr__(self):
442
+ return self.__str__()
443
+
423
444
  class Generation:
424
445
  """
425
446
  Class to represent the Generation Object in the Preservica data model
@@ -528,6 +549,9 @@ class ContentObject(Entity):
528
549
  self.tag = "ContentObject"
529
550
 
530
551
 
552
+ EntityT = TypeVar("EntityT", Folder, Asset, ContentObject, None)
553
+
554
+
531
555
  class Representation:
532
556
  """
533
557
  Class to represent the Representation Object in the Preservica data model
@@ -738,7 +762,7 @@ class AuthenticatedAPI:
738
762
  Return the edition of this tenancy
739
763
  """
740
764
  if self.major_version < 8 and self.minor_version < 3:
741
- raise RuntimeError("Entitlement API is only available when connected to a v7.3 System")
765
+ raise RuntimeError("Entitlement API is only available when connected to a v7.3 System")
742
766
 
743
767
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json'}
744
768
 
@@ -777,6 +801,7 @@ class AuthenticatedAPI:
777
801
  self.sec_ns = f"{NS_SEC_ROOT}/v{self.major_version}.{self.minor_version}"
778
802
  self.admin_ns = f"{NS_ADMIN}/v{self.major_version}.{self.minor_version}"
779
803
 
804
+
780
805
  def __version_number__(self):
781
806
  """
782
807
  Determine the version number of the server
@@ -801,7 +826,7 @@ class AuthenticatedAPI:
801
826
  RuntimeError(request.status_code, "version number failed")
802
827
 
803
828
  def __str__(self):
804
- return f"pyPreservica version: {pyPreservica.__version__} (Preservica 7.0 Compatible) " \
829
+ return f"pyPreservica version: {pyPreservica.__version__} (Preservica 8.0 Compatible) " \
805
830
  f"Connected to: {self.server} Preservica version: {self.version} as {self.username} " \
806
831
  f"in tenancy {self.tenant}"
807
832
 
pyPreservica/entityAPI.py CHANGED
@@ -486,6 +486,54 @@ class EntityAPI(AuthenticatedAPI):
486
486
  logger.error(request)
487
487
  raise RuntimeError(request.status_code, "delete_identifier failed")
488
488
 
489
+ def entity_identifiers(self, entity: Entity, external_identifier_type = None) -> set[ExternIdentifier]:
490
+ """
491
+ Get all external identifiers on an entity
492
+
493
+ Returns the set of external identifiers on the entity
494
+
495
+ :param entity: The Entity (Asset or Folder)
496
+ :param external_identifier_type: Optional identifier type to filter the results
497
+ :type entity: Entity
498
+ """
499
+ headers = {HEADER_TOKEN: self.token}
500
+ request = self.session.get(
501
+ f'{self.protocol}://{self.server}/api/entity/{entity.path}/{entity.reference}/identifiers',
502
+ headers=headers)
503
+ if request.status_code == requests.codes.ok:
504
+ xml_response = str(request.content.decode('utf-8'))
505
+ logger.debug(xml_response)
506
+ entity_response = xml.etree.ElementTree.fromstring(xml_response)
507
+ identifier_list = entity_response.findall(f'.//{{{self.xip_ns}}}Identifier')
508
+ result = set()
509
+ for identifier in identifier_list:
510
+ identifier_value = identifier_type = identifier_id = ""
511
+ for child in identifier:
512
+ if child.tag.endswith("Type"):
513
+ identifier_type = child.text
514
+ if child.tag.endswith("Value"):
515
+ identifier_value = child.text
516
+ if child.tag.endswith("ApiId"):
517
+ identifier_id = child.text
518
+ if external_identifier_type is None:
519
+ external_id: ExternIdentifier = ExternIdentifier(identifier_type, identifier_value)
520
+ external_id.identifier_id = identifier_id
521
+ result.add(external_id)
522
+ else:
523
+ if identifier_type == external_identifier_type:
524
+ external_id: ExternIdentifier = ExternIdentifier(identifier_type, identifier_value)
525
+ external_id.identifier_id = identifier_id
526
+ result.add(external_id)
527
+ return result
528
+ elif request.status_code == requests.codes.unauthorized:
529
+ self.token = self.__token__()
530
+ return self.entity_identifiers(entity)
531
+ else:
532
+ exception = HTTPException(entity.reference, request.status_code, request.url, "identifiers_for_entity",
533
+ request.content.decode('utf-8'))
534
+ logger.error(exception)
535
+ raise exception
536
+
489
537
 
490
538
  def identifiers_for_entity(self, entity: Entity) -> set[Tuple]:
491
539
  """
@@ -526,14 +574,14 @@ class EntityAPI(AuthenticatedAPI):
526
574
 
527
575
 
528
576
 
529
- def identifier(self, identifier_type: str, identifier_value: str) -> set[Entity]:
577
+ def identifier(self, identifier_type: str, identifier_value: str) -> set[EntityT]:
530
578
  """
531
- Get all entities which have the external identifier
579
+ Get all entities which have the external identifier
532
580
 
533
- Returns the set of entities which have the external identifier
581
+ Returns the set of entities which have the external identifier
534
582
 
535
- :param identifier_type: The identifier type
536
- :param identifier_value: The identifier value
583
+ :param identifier_type: The identifier type
584
+ :param identifier_value: The identifier value
537
585
  """
538
586
  headers = {HEADER_TOKEN: self.token}
539
587
  payload = {'type': identifier_type, 'value': identifier_value}
@@ -861,7 +909,7 @@ class EntityAPI(AuthenticatedAPI):
861
909
  logger.error(exception)
862
910
  raise exception
863
911
 
864
- def delete_metadata(self, entity: Entity, schema: str) -> Entity:
912
+ def delete_metadata(self, entity: EntityT, schema: str) -> EntityT:
865
913
  """
866
914
  Deletes all the metadata fragments on an entity which match the schema URI
867
915
 
@@ -887,7 +935,7 @@ class EntityAPI(AuthenticatedAPI):
887
935
 
888
936
  return self.entity(entity.entity_type, entity.reference)
889
937
 
890
- def update_metadata(self, entity: Entity, schema: str, data: Any) -> Entity:
938
+ def update_metadata(self, entity: EntityT, schema: str, data: Any) -> EntityT:
891
939
  """
892
940
  Update all existing metadata fragments which match the schema
893
941
 
@@ -933,7 +981,9 @@ class EntityAPI(AuthenticatedAPI):
933
981
  raise exception
934
982
  return self.entity(entity.entity_type, entity.reference)
935
983
 
936
- def add_metadata_as_fragment(self, entity: Entity, schema: str, xml_fragment: str) -> Entity:
984
+ def add_metadata_as_fragment(
985
+ self, entity: EntityT, schema: str, xml_fragment: str
986
+ ) -> EntityT:
937
987
  """
938
988
  Add a metadata fragment with a given namespace URI to an Entity
939
989
 
@@ -969,8 +1019,7 @@ class EntityAPI(AuthenticatedAPI):
969
1019
  logger.error(exception)
970
1020
  raise exception
971
1021
 
972
-
973
- def add_metadata(self, entity: Entity, schema: str, data) -> Entity:
1022
+ def add_metadata(self, entity: EntityT, schema: str, data) -> EntityT:
974
1023
  """
975
1024
  Add a metadata fragment with a given namespace URI
976
1025
 
@@ -1011,7 +1060,7 @@ class EntityAPI(AuthenticatedAPI):
1011
1060
  logger.error(exception)
1012
1061
  raise exception
1013
1062
 
1014
- def save(self, entity: Entity) -> Entity:
1063
+ def save(self, entity: EntityT) -> EntityT:
1015
1064
  """
1016
1065
  Save the title and description of an entity
1017
1066
 
@@ -1129,7 +1178,7 @@ class EntityAPI(AuthenticatedAPI):
1129
1178
  logger.error(exception)
1130
1179
  raise exception
1131
1180
 
1132
- def move_sync(self, entity: Entity, dest_folder: Folder) -> Entity:
1181
+ def move_sync(self, entity: EntityT, dest_folder: Folder) -> EntityT:
1133
1182
  """
1134
1183
  Move an Entity (Asset or Folder) to a new Folder
1135
1184
  If dest_folder is None then the entity must be a Folder and will be moved to the root of the repository
@@ -1169,7 +1218,7 @@ class EntityAPI(AuthenticatedAPI):
1169
1218
  logger.error(exception)
1170
1219
  raise exception
1171
1220
 
1172
- def move(self, entity: Entity, dest_folder: Folder) -> Entity:
1221
+ def move(self, entity: EntityT, dest_folder: Folder) -> EntityT:
1173
1222
  """
1174
1223
  Move an Entity (Asset or Folder) to a new Folder
1175
1224
  If dest_folder is None then the entity must be a Folder and will be moved to the root of the repository
@@ -1274,7 +1323,7 @@ class EntityAPI(AuthenticatedAPI):
1274
1323
  else:
1275
1324
  return xml_object.find(tag).text
1276
1325
 
1277
- def security_tag_sync(self, entity: Entity, new_tag: str):
1326
+ def security_tag_sync(self, entity: EntityT, new_tag: str) -> EntityT:
1278
1327
  """
1279
1328
  Change the security tag for a folder or asset
1280
1329
 
@@ -1354,7 +1403,7 @@ class EntityAPI(AuthenticatedAPI):
1354
1403
  logger.error(exception)
1355
1404
  raise exception
1356
1405
 
1357
- def entity(self, entity_type: EntityType, reference: str) -> Entity:
1406
+ def entity(self, entity_type: EntityType, reference: str) -> EntityT:
1358
1407
  """
1359
1408
  Retrieve an entity by its type and reference
1360
1409
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyPreservica
3
- Version: 3.2.0
3
+ Version: 3.2.1
4
4
  Summary: Python library for the Preservica API
5
5
  Home-page: https://pypreservica.readthedocs.io/
6
6
  Author: James Carr
@@ -23,8 +23,8 @@ License-File: LICENSE.txt
23
23
  Requires-Dist: requests
24
24
  Requires-Dist: urllib3
25
25
  Requires-Dist: certifi
26
- Requires-Dist: boto3
27
- Requires-Dist: botocore
26
+ Requires-Dist: boto3>=1.36.0
27
+ Requires-Dist: botocore>=1.36.0
28
28
  Requires-Dist: s3transfer
29
29
  Requires-Dist: azure-storage-blob
30
30
  Requires-Dist: tqdm
@@ -1,9 +1,9 @@
1
- pyPreservica/__init__.py,sha256=erL11_X3f9F3yfHhgtVxRdAH1m2LIOsYkTvReMS3em4,1250
1
+ pyPreservica/__init__.py,sha256=IDGY2--79x65wptaP8fj5cWTaDT_a2_2TaSrYJF1UfY,1250
2
2
  pyPreservica/adminAPI.py,sha256=aMN2twcUZOFoGx2yapC6GVtBTdYHUJFA-5bdWVkCwS8,37773
3
3
  pyPreservica/authorityAPI.py,sha256=jpf_m9i-IakyNVooi2yELuKt4yhX73hWqQNbPRHZx2g,9206
4
- pyPreservica/common.py,sha256=iEeF4Kg51d4Vug-Dv8TeqS1lP2zcfM7YtBO8oANEcCU,38273
4
+ pyPreservica/common.py,sha256=pPg29dQYa3SeKvRIci7Q4AwAY9CjCe0ENDaElWYqCxk,38929
5
5
  pyPreservica/contentAPI.py,sha256=ZvX2aGQEaksmw-m-oEUI6daVSqFe_IcE1cGwCNbSCDQ,22286
6
- pyPreservica/entityAPI.py,sha256=cIuipvOlFUNgaLBOXtevTYQrT0zh1NG2y5gXz5sr_k0,125673
6
+ pyPreservica/entityAPI.py,sha256=0ATOcwhBF8Cu6R-BnsV0I4EtXmkLW9jeWbXQaqYyMmo,128230
7
7
  pyPreservica/mdformsAPI.py,sha256=_hBjT4-OzgLQGDfYX7b_01P27wc-RmsCEu57VtyAdh8,19173
8
8
  pyPreservica/monitorAPI.py,sha256=LJOUrynBOWKlNiYpZ1iH8qB1oIIuKX1Ms1SRBcuXohA,6274
9
9
  pyPreservica/opex.py,sha256=ccra1S4ojUXS3PlbU8WfxajOkJrwG4OykBnNrYP_jus,4875
@@ -13,8 +13,8 @@ pyPreservica/settingsAPI.py,sha256=jXnMOCq3mimta6E-Os3J1I1if2pYsjLpOazAx8L-ZQI,1
13
13
  pyPreservica/uploadAPI.py,sha256=uX67mW-2q7FmjtXQ759GwHPL6Zs7R-iE8-86PBApvbY,99823
14
14
  pyPreservica/webHooksAPI.py,sha256=B3C6PV_3JLlJrr9PtsTzL-21M0msx8Mnj18Xb3Bv4RE,6814
15
15
  pyPreservica/workflowAPI.py,sha256=OcOiiUdrQerbPllrkj1lWpmuW0jTuyyV0urwPSYcd_U,17561
16
- pypreservica-3.2.0.dist-info/licenses/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
17
- pypreservica-3.2.0.dist-info/METADATA,sha256=x3FR1zZKihN0pfSN_JdvM10pfP_IsfY1GWV8t3Yd_bo,3009
18
- pypreservica-3.2.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
19
- pypreservica-3.2.0.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
20
- pypreservica-3.2.0.dist-info/RECORD,,
16
+ pypreservica-3.2.1.dist-info/licenses/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
17
+ pypreservica-3.2.1.dist-info/METADATA,sha256=rrmuhukqFCtJTb5_Q-oM6HX5Q2sUlSgO0AcC0ciPvSg,3025
18
+ pypreservica-3.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ pypreservica-3.2.1.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
20
+ pypreservica-3.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5