pyPreservica 2.8.1__tar.gz → 2.9.0__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.
- {pypreservica-2.8.1 → pypreservica-2.9.0}/PKG-INFO +3 -5
- {pypreservica-2.8.1 → pypreservica-2.9.0}/README.md +1 -4
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/__init__.py +2 -2
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/entityAPI.py +72 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/mdformsAPI.py +6 -4
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/retentionAPI.py +53 -24
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/uploadAPI.py +3 -3
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/webHooksAPI.py +1 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica.egg-info/PKG-INFO +3 -5
- {pypreservica-2.8.1 → pypreservica-2.9.0}/setup.py +2 -1
- pypreservica-2.9.0/tests/test_authority_records.py +38 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_bitstream.py +25 -3
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_children.py +29 -6
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_content_api.py +35 -12
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_groups.py +11 -5
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_identifier.py +76 -11
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_par.py +1 -1
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_retention.py +3 -3
- pypreservica-2.8.1/tests/test_authority_records.py +0 -20
- {pypreservica-2.8.1 → pypreservica-2.9.0}/LICENSE.txt +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/adminAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/authorityAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/common.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/contentAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/monitorAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/opex.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/parAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica/workflowAPI.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica.egg-info/SOURCES.txt +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica.egg-info/dependency_links.txt +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica.egg-info/requires.txt +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/pyPreservica.egg-info/top_level.txt +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/setup.cfg +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_crawl_fs.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_delete.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_download.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_entity.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_export_opex.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_ingest.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_integrity_check.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_metadata.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_replace.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_schema.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_security.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_thumbnail.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_upload.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_users.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_workflow.py +0 -0
- {pypreservica-2.8.1 → pypreservica-2.9.0}/tests/test_xml_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyPreservica
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0
|
|
4
4
|
Summary: Python library for the Preservica API
|
|
5
5
|
Home-page: https://pypreservica.readthedocs.io/
|
|
6
6
|
Author: James Carr
|
|
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
19
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
21
|
Classifier: Topic :: System :: Archiving
|
|
@@ -34,12 +35,9 @@ Requires-Dist: pyotp
|
|
|
34
35
|
# pyPreservica
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
<!---
|
|
38
|
-
[](https://pepy.tech/project/pyPreservica/month)
|
|
39
|
-
--->
|
|
40
|
-
|
|
41
38
|
[](https://pypi.org/project/pyPreservica)
|
|
42
39
|
[](https://github.com/carj/pyPreservica/actions/workflows/codeql-analysis.yml)
|
|
40
|
+

|
|
43
41
|
|
|
44
42
|
Python language binding for the Preservica API
|
|
45
43
|
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
# pyPreservica
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
<!---
|
|
6
|
-
[](https://pepy.tech/project/pyPreservica/month)
|
|
7
|
-
--->
|
|
8
|
-
|
|
9
5
|
[](https://pypi.org/project/pyPreservica)
|
|
10
6
|
[](https://github.com/carj/pyPreservica/actions/workflows/codeql-analysis.yml)
|
|
7
|
+

|
|
11
8
|
|
|
12
9
|
Python language binding for the Preservica API
|
|
13
10
|
|
|
@@ -18,11 +18,11 @@ from .adminAPI import AdminAPI
|
|
|
18
18
|
from .monitorAPI import MonitorAPI, MonitorCategory, MonitorStatus, MessageStatus
|
|
19
19
|
from .webHooksAPI import WebHooksAPI, TriggerType, WebHookHandler
|
|
20
20
|
from .authorityAPI import AuthorityAPI, Table
|
|
21
|
-
from .mdformsAPI import MetadataGroupsAPI,
|
|
21
|
+
from .mdformsAPI import MetadataGroupsAPI, Group, GroupField, GroupFieldType
|
|
22
22
|
|
|
23
23
|
__author__ = "James Carr (drjamescarr@gmail.com)"
|
|
24
24
|
|
|
25
25
|
# Version of the pyPreservica package
|
|
26
|
-
__version__ = "2.
|
|
26
|
+
__version__ = "2.9.0"
|
|
27
27
|
|
|
28
28
|
__license__ = "Apache License Version 2.0"
|
|
@@ -572,6 +572,76 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
572
572
|
logger.error(exception)
|
|
573
573
|
raise exception
|
|
574
574
|
|
|
575
|
+
def update_identifiers(self, entity: Entity, identifier_type: str = None, identifier_value: str = None):
|
|
576
|
+
"""
|
|
577
|
+
Update external identifiers based on Entity and Type
|
|
578
|
+
|
|
579
|
+
Returns the internal identifier DB Key
|
|
580
|
+
|
|
581
|
+
:param entity: The entity to delete identifiers from
|
|
582
|
+
:param identifier_type: The type of the identifier to delete.
|
|
583
|
+
:param identifier_value: The value of the identifier to delete.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
if (self.major_version < 7) and (self.minor_version < 1):
|
|
587
|
+
raise RuntimeError("update_identifiers API call is not available when connected to a v6.0 System")
|
|
588
|
+
|
|
589
|
+
headers = {HEADER_TOKEN: self.token}
|
|
590
|
+
response = self.session.get(
|
|
591
|
+
f'{self.protocol}://{self.server}/api/entity/{entity.path}/{entity.reference}/identifiers',
|
|
592
|
+
headers=headers)
|
|
593
|
+
|
|
594
|
+
if response.status_code == requests.codes.ok:
|
|
595
|
+
xml_response = str(response.content.decode('utf-8'))
|
|
596
|
+
entity_response = xml.etree.ElementTree.fromstring(xml_response)
|
|
597
|
+
identifier_list = entity_response.findall(f'.//{{{self.xip_ns}}}Identifier')
|
|
598
|
+
for identifier_element in identifier_list:
|
|
599
|
+
_ref = _type = _value = _aipid = None
|
|
600
|
+
for identifier in identifier_element:
|
|
601
|
+
if identifier.tag.endswith("Entity"):
|
|
602
|
+
_ref = identifier.text
|
|
603
|
+
if identifier.tag.endswith("Type") and identifier_type is not None:
|
|
604
|
+
_type = identifier.text
|
|
605
|
+
if identifier.tag.endswith("Value") and identifier_value is not None:
|
|
606
|
+
_value = identifier.text
|
|
607
|
+
if identifier.tag.endswith("ApiId"):
|
|
608
|
+
_aipid = identifier.text
|
|
609
|
+
if _ref == entity.reference and _type == identifier_type:
|
|
610
|
+
|
|
611
|
+
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
|
|
612
|
+
|
|
613
|
+
xml_object = xml.etree.ElementTree.Element('Identifier', {"xmlns": self.xip_ns})
|
|
614
|
+
xml.etree.ElementTree.SubElement(xml_object, "Type").text = identifier_type
|
|
615
|
+
xml.etree.ElementTree.SubElement(xml_object, "Value").text = identifier_value
|
|
616
|
+
xml.etree.ElementTree.SubElement(xml_object, "Entity").text = entity.reference
|
|
617
|
+
xml_request = xml.etree.ElementTree.tostring(xml_object, encoding='utf-8')
|
|
618
|
+
|
|
619
|
+
put_response = self.session.put(
|
|
620
|
+
f'{self.protocol}://{self.server}/api/entity/{entity.path}/{entity.reference}/identifiers/{_aipid}',
|
|
621
|
+
headers=headers, data=xml_request)
|
|
622
|
+
if put_response.status_code == requests.codes.ok:
|
|
623
|
+
xml_string = str(put_response.content.decode("utf-8"))
|
|
624
|
+
identifier_response = xml.etree.ElementTree.fromstring(xml_string)
|
|
625
|
+
aip_id = identifier_response.find(f'.//{{{self.xip_ns}}}ApiId')
|
|
626
|
+
if hasattr(aip_id, 'text'):
|
|
627
|
+
return aip_id.text
|
|
628
|
+
else:
|
|
629
|
+
return None
|
|
630
|
+
if put_response.status_code == requests.codes.unauthorized:
|
|
631
|
+
self.token = self.__token__()
|
|
632
|
+
return self.update_identifiers(entity, identifier_type, identifier_value)
|
|
633
|
+
if put_response.status_code == requests.codes.no_content:
|
|
634
|
+
pass
|
|
635
|
+
else:
|
|
636
|
+
return None
|
|
637
|
+
return entity
|
|
638
|
+
elif response.status_code == requests.codes.unauthorized:
|
|
639
|
+
self.token = self.__token__()
|
|
640
|
+
return self.update_identifiers(entity, identifier_type, identifier_value)
|
|
641
|
+
else:
|
|
642
|
+
logger.error(response)
|
|
643
|
+
raise RuntimeError(response.status_code, "update_identifiers failed")
|
|
644
|
+
|
|
575
645
|
def delete_relationships(self, entity: Entity, relationship_type: str = None):
|
|
576
646
|
"""
|
|
577
647
|
Delete a relationship between two entities by its internal id
|
|
@@ -2275,6 +2345,8 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
2275
2345
|
entity_response = xml.etree.ElementTree.fromstring(req.content.decode("utf-8"))
|
|
2276
2346
|
status = entity_response.find(".//{http://status.preservica.com}Status")
|
|
2277
2347
|
if hasattr(status, 'text'):
|
|
2348
|
+
if status.text == "COMPLETED":
|
|
2349
|
+
return entity.reference
|
|
2278
2350
|
if status.text == "PENDING":
|
|
2279
2351
|
headers = {HEADER_TOKEN: self.manager_token(manager_username, manager_password),
|
|
2280
2352
|
'Content-Type': 'application/xml;charset=UTF-8'}
|
|
@@ -9,13 +9,12 @@ licence: Apache License 2.0
|
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
11
|
import xml.etree.ElementTree
|
|
12
|
-
from enum import StrEnum
|
|
13
12
|
from typing import Callable, List, Union, Generator
|
|
14
13
|
|
|
15
14
|
from pyPreservica.common import *
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
class GroupFieldType(
|
|
17
|
+
class GroupFieldType(Enum):
|
|
19
18
|
STRING = "STRING"
|
|
20
19
|
LONG_STRING = "LONGSTRING"
|
|
21
20
|
DATE = "DATE"
|
|
@@ -60,11 +59,12 @@ class Group:
|
|
|
60
59
|
name: str
|
|
61
60
|
description: str
|
|
62
61
|
schemaUri: str
|
|
63
|
-
fields: List[GroupField]
|
|
62
|
+
fields: List[GroupField]
|
|
64
63
|
|
|
65
64
|
def __init__(self, name: str, description: str):
|
|
66
65
|
self.name = name
|
|
67
66
|
self.description = description
|
|
67
|
+
self.fields = []
|
|
68
68
|
|
|
69
69
|
def __str__(self):
|
|
70
70
|
return (f"Group ID: {self.group_id}\n" + f"Group Name: {self.name}\n" +
|
|
@@ -96,6 +96,8 @@ def _object_from_json_(json_doc: dict) -> Group:
|
|
|
96
96
|
gf.editable = bool(field['editable'])
|
|
97
97
|
if 'values' in field:
|
|
98
98
|
for v in field['values']:
|
|
99
|
+
if gf.values is None:
|
|
100
|
+
gf.values = []
|
|
99
101
|
gf.values.append(str(v))
|
|
100
102
|
if 'defaultValue' in field:
|
|
101
103
|
gf.default = str(field['defaultValue'])
|
|
@@ -114,7 +116,7 @@ def _json_from_object_(group: Group) -> dict:
|
|
|
114
116
|
|
|
115
117
|
fields = []
|
|
116
118
|
for field in group.fields:
|
|
117
|
-
f = {"id": field.field_id, "name": field.name, "type": str(field.field_type)}
|
|
119
|
+
f = {"id": field.field_id, "name": field.name, "type": str(field.field_type.value)}
|
|
118
120
|
f["minOccurs"] = str(field.minOccurs)
|
|
119
121
|
f["maxOccurs"] = str(field.maxOccurs)
|
|
120
122
|
f["visible"] = str(field.visible)
|
|
@@ -9,7 +9,6 @@ licence: Apache License 2.0
|
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
|
|
13
12
|
import xml.etree.ElementTree
|
|
14
13
|
from typing import Set, Callable
|
|
15
14
|
|
|
@@ -60,7 +59,6 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
60
59
|
|
|
61
60
|
def __init__(self, username=None, password=None, tenant=None, server=None, use_shared_secret=False,
|
|
62
61
|
two_fa_secret_key: str = None, protocol: str = "https", request_hook: Callable = None):
|
|
63
|
-
|
|
64
62
|
super().__init__(username, password, tenant, server, use_shared_secret, two_fa_secret_key,
|
|
65
63
|
protocol, request_hook)
|
|
66
64
|
if self.major_version < 7 and self.minor_version < 2:
|
|
@@ -78,7 +76,8 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
78
76
|
|
|
79
77
|
"""
|
|
80
78
|
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
|
|
81
|
-
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
|
|
79
|
+
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
|
|
80
|
+
headers=headers)
|
|
82
81
|
if request.status_code == requests.codes.ok:
|
|
83
82
|
xml_response = str(request.content.decode('utf-8'))
|
|
84
83
|
logger.debug(xml_response)
|
|
@@ -92,14 +91,22 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
92
91
|
security_tag = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}SecurityTag').text
|
|
93
92
|
rp.security_tag = security_tag
|
|
94
93
|
start_date_field = entity_response.find(
|
|
95
|
-
f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}StartDateField')
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}StartDateField')
|
|
95
|
+
if start_date_field is not None:
|
|
96
|
+
rp.start_date_field = start_date_field.text
|
|
97
|
+
else:
|
|
98
|
+
start_date_field = None
|
|
99
|
+
period = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}Period')
|
|
100
|
+
if period is not None:
|
|
101
|
+
rp.period = period.text
|
|
102
|
+
else:
|
|
103
|
+
rp.period = None
|
|
104
|
+
period_unit = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}PeriodUnit')
|
|
105
|
+
if period_unit is not None:
|
|
106
|
+
rp.period_unit = period_unit.text
|
|
107
|
+
else:
|
|
108
|
+
rp.period_unit = None
|
|
109
|
+
expiry_action = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}ExpiryAction')
|
|
103
110
|
if expiry_action is not None:
|
|
104
111
|
rp.expiry_action = expiry_action.text
|
|
105
112
|
else:
|
|
@@ -134,8 +141,9 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
134
141
|
"""
|
|
135
142
|
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'text/plain;charset=UTF-8'}
|
|
136
143
|
data = str(status)
|
|
137
|
-
request = self.session.put(
|
|
138
|
-
|
|
144
|
+
request = self.session.put(
|
|
145
|
+
f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}/assignable',
|
|
146
|
+
headers=headers, data=data)
|
|
139
147
|
if request.status_code == requests.codes.ok:
|
|
140
148
|
pass
|
|
141
149
|
elif request.status_code == requests.codes.unauthorized:
|
|
@@ -230,7 +238,8 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
230
238
|
|
|
231
239
|
xml_request = xml.etree.ElementTree.tostring(retention_policy, encoding='utf-8')
|
|
232
240
|
|
|
233
|
-
request = self.session.put(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
|
|
241
|
+
request = self.session.put(f'{self.protocol}://{self.server}/api/entity/retention-policies/{reference}',
|
|
242
|
+
data=xml_request,
|
|
234
243
|
headers=headers)
|
|
235
244
|
if request.status_code == requests.codes.ok:
|
|
236
245
|
return self.policy(reference)
|
|
@@ -374,7 +383,8 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
374
383
|
"""
|
|
375
384
|
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
|
|
376
385
|
data = {'start': str(0), 'max': "250"}
|
|
377
|
-
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', data=data,
|
|
386
|
+
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', data=data,
|
|
387
|
+
headers=headers)
|
|
378
388
|
if request.status_code == requests.codes.ok:
|
|
379
389
|
xml_response = str(request.content.decode('utf-8'))
|
|
380
390
|
logger.debug(xml_response)
|
|
@@ -390,10 +400,10 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
390
400
|
else:
|
|
391
401
|
raise RuntimeError(request.status_code, "policies failed")
|
|
392
402
|
|
|
393
|
-
def policies(self) ->
|
|
403
|
+
def policies(self, maximum: int = 250, next_page: str = None) -> PagedSet:
|
|
394
404
|
"""
|
|
395
405
|
Return a list of all retention policies
|
|
396
|
-
|
|
406
|
+
Returns a maxmium of 250 policies by default
|
|
397
407
|
|
|
398
408
|
|
|
399
409
|
:return: Set of retention policies
|
|
@@ -401,22 +411,33 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
401
411
|
|
|
402
412
|
"""
|
|
403
413
|
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/xml;charset=UTF-8'}
|
|
404
|
-
|
|
405
|
-
|
|
414
|
+
|
|
415
|
+
if next_page is None:
|
|
416
|
+
params = {'start': '0', 'max': str(maximum)}
|
|
417
|
+
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/retention-policies', params=params,
|
|
418
|
+
headers=headers)
|
|
419
|
+
else:
|
|
420
|
+
request = self.session.get(next_page, headers=headers)
|
|
421
|
+
|
|
406
422
|
if request.status_code == requests.codes.ok:
|
|
407
423
|
xml_response = str(request.content.decode('utf-8'))
|
|
408
424
|
entity_response = xml.etree.ElementTree.fromstring(xml_response)
|
|
409
425
|
logger.debug(xml_response)
|
|
410
426
|
result = set()
|
|
427
|
+
next_url = entity_response.find(f'.//{{{self.entity_ns}}}Paging/{{{self.entity_ns}}}Next')
|
|
411
428
|
total_results = int(entity_response.find(
|
|
412
429
|
f'.//{{{self.entity_ns}}}TotalResults').text)
|
|
413
|
-
if total_results > 250:
|
|
414
|
-
logger.error("Not all retention policies have been returned.")
|
|
415
430
|
for assignment in entity_response.findall(f'.//{{{self.entity_ns}}}RetentionPolicy'):
|
|
416
431
|
ref = assignment.attrib['ref']
|
|
417
432
|
name = assignment.attrib['name']
|
|
418
433
|
result.add(self.policy(reference=ref))
|
|
419
|
-
|
|
434
|
+
has_more = True
|
|
435
|
+
url = None
|
|
436
|
+
if next_url is None:
|
|
437
|
+
has_more = False
|
|
438
|
+
else:
|
|
439
|
+
url = next_url.text
|
|
440
|
+
return PagedSet(result, has_more, total_results, url)
|
|
420
441
|
elif request.status_code == requests.codes.unauthorized:
|
|
421
442
|
self.token = self.__token__()
|
|
422
443
|
return self.policies()
|
|
@@ -455,7 +476,11 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
455
476
|
api_id = entity_response.find(f'.//{{{self.rm_ns}}}ApiId').text
|
|
456
477
|
policy_ref = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy').text
|
|
457
478
|
entity_ref = entity_response.find(f'.//{{{self.rm_ns}}}Entity').text
|
|
458
|
-
start_date = entity_response.find(f'.//{{{self.rm_ns}}}StartDate')
|
|
479
|
+
start_date = entity_response.find(f'.//{{{self.rm_ns}}}StartDate')
|
|
480
|
+
if start_date is not None:
|
|
481
|
+
start_date = start_date.text
|
|
482
|
+
else:
|
|
483
|
+
start_date = None
|
|
459
484
|
assert entity_ref == entity.reference
|
|
460
485
|
assert policy_ref == policy.reference
|
|
461
486
|
return RetentionAssignment(entity_ref, policy_ref, api_id, start_date)
|
|
@@ -516,7 +541,11 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
516
541
|
entity_ref = assignment.find(f'.//{{{self.rm_ns}}}Entity').text
|
|
517
542
|
assert entity_ref == entity.reference
|
|
518
543
|
policy = assignment.find(f'.//{{{self.rm_ns}}}RetentionPolicy').text
|
|
519
|
-
start_date = assignment.find(f'.//{{{self.rm_ns}}}StartDate')
|
|
544
|
+
start_date = assignment.find(f'.//{{{self.rm_ns}}}StartDate')
|
|
545
|
+
if start_date is not None:
|
|
546
|
+
start_date = start_date.text
|
|
547
|
+
else:
|
|
548
|
+
start_date = None
|
|
520
549
|
expired = bool(assignment.find(f'.//{{{self.rm_ns}}}Expired').text == 'true')
|
|
521
550
|
api_id = assignment.find(f'.//{{{self.rm_ns}}}ApiId').text
|
|
522
551
|
ra = RetentionAssignment(entity_ref, policy, api_id, start_date, expired)
|
|
@@ -1421,7 +1421,7 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1421
1421
|
try:
|
|
1422
1422
|
auth = tweepy.AppAuthHandler(twitter_consumer_key, twitter_secret_key)
|
|
1423
1423
|
api = tweepy.API(auth, wait_on_rate_limit=True)
|
|
1424
|
-
except
|
|
1424
|
+
except RuntimeError:
|
|
1425
1425
|
logger.error("No valid Twitter API keys. Could not authenticate")
|
|
1426
1426
|
raise RuntimeError("No valid Twitter API keys. Could not authenticate")
|
|
1427
1427
|
if api is not None:
|
|
@@ -1734,8 +1734,8 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1734
1734
|
self.upload_zip_package(path_to_zip_package=package, callback=progress_display,
|
|
1735
1735
|
delete_after_upload=delete_after_upload)
|
|
1736
1736
|
else:
|
|
1737
|
-
self.
|
|
1738
|
-
|
|
1737
|
+
self.upload_zip_to_Source(path_to_zip_package=package, container_name=bucket_name,
|
|
1738
|
+
show_progress= bool(progress_display is not None),
|
|
1739
1739
|
delete_after_upload=delete_after_upload)
|
|
1740
1740
|
|
|
1741
1741
|
logger.info(f"Uploaded " + "{:.1f}".format(bytes_ingested / (1024 * 1024)) + " MB")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyPreservica
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0
|
|
4
4
|
Summary: Python library for the Preservica API
|
|
5
5
|
Home-page: https://pypreservica.readthedocs.io/
|
|
6
6
|
Author: James Carr
|
|
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
19
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
21
|
Classifier: Topic :: System :: Archiving
|
|
@@ -34,12 +35,9 @@ Requires-Dist: pyotp
|
|
|
34
35
|
# pyPreservica
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
<!---
|
|
38
|
-
[](https://pepy.tech/project/pyPreservica/month)
|
|
39
|
-
--->
|
|
40
|
-
|
|
41
38
|
[](https://pypi.org/project/pyPreservica)
|
|
42
39
|
[](https://github.com/carj/pyPreservica/actions/workflows/codeql-analysis.yml)
|
|
40
|
+

|
|
43
41
|
|
|
44
42
|
Python language binding for the Preservica API
|
|
45
43
|
|
|
@@ -21,7 +21,7 @@ if sys.argv[-1] == 'publish':
|
|
|
21
21
|
# This call to setup() does all the work
|
|
22
22
|
setup(
|
|
23
23
|
name=PKG,
|
|
24
|
-
version="2.
|
|
24
|
+
version="2.9.0",
|
|
25
25
|
description="Python library for the Preservica API",
|
|
26
26
|
long_description=README,
|
|
27
27
|
long_description_content_type="text/markdown",
|
|
@@ -36,6 +36,7 @@ setup(
|
|
|
36
36
|
'Programming Language :: Python :: 3.9',
|
|
37
37
|
'Programming Language :: Python :: 3.10',
|
|
38
38
|
'Programming Language :: Python :: 3.11',
|
|
39
|
+
'Programming Language :: Python :: 3.12',
|
|
39
40
|
"License :: OSI Approved :: Apache Software License",
|
|
40
41
|
"Operating System :: OS Independent",
|
|
41
42
|
"Topic :: System :: Archiving",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from pyPreservica import *
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def setup():
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
def tear_down():
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def setup_data():
|
|
14
|
+
print("\nSetting up resources...")
|
|
15
|
+
|
|
16
|
+
setup()
|
|
17
|
+
|
|
18
|
+
yield
|
|
19
|
+
|
|
20
|
+
print("\nTearing down resources...")
|
|
21
|
+
|
|
22
|
+
tear_down()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_get_tables(setup_data):
|
|
26
|
+
client = AuthorityAPI()
|
|
27
|
+
results = client.tables()
|
|
28
|
+
assert isinstance(results, set)
|
|
29
|
+
for table in results:
|
|
30
|
+
assert isinstance(table, Table)
|
|
31
|
+
assert table.name in ["Countries", 'Physical Storage']
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_records(setup_data):
|
|
35
|
+
client = AuthorityAPI()
|
|
36
|
+
tables = client.tables()
|
|
37
|
+
for tab in tables:
|
|
38
|
+
records = client.records(tab)
|
|
@@ -3,10 +3,32 @@ from pathlib import Path
|
|
|
3
3
|
import pytest
|
|
4
4
|
from pyPreservica import *
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
def setup():
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def tear_down():
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def setup_data():
|
|
17
|
+
print("\nSetting up resources...")
|
|
18
|
+
|
|
19
|
+
setup()
|
|
20
|
+
|
|
21
|
+
yield
|
|
22
|
+
|
|
23
|
+
print("\nTearing down resources...")
|
|
24
|
+
|
|
25
|
+
tear_down()
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
ASSET_ID = "b14848b5-4c4d-4d8a-b394-3b764069ee93"
|
|
7
29
|
|
|
8
30
|
|
|
9
|
-
def test_get_representations():
|
|
31
|
+
def test_get_representations(setup_data):
|
|
10
32
|
client = EntityAPI()
|
|
11
33
|
asset = client.asset(ASSET_ID)
|
|
12
34
|
assert asset is not None
|
|
@@ -20,7 +42,7 @@ def test_get_representations():
|
|
|
20
42
|
assert representation.name == "Preservation-1"
|
|
21
43
|
|
|
22
44
|
|
|
23
|
-
def test_get_generations():
|
|
45
|
+
def test_get_generations(setup_data):
|
|
24
46
|
client = EntityAPI()
|
|
25
47
|
asset = client.asset(ASSET_ID)
|
|
26
48
|
assert asset is not None
|
|
@@ -60,7 +82,7 @@ def test_get_generations():
|
|
|
60
82
|
assert generation.format_group == "jpeg"
|
|
61
83
|
|
|
62
84
|
|
|
63
|
-
def test_get_bitstream_content():
|
|
85
|
+
def test_get_bitstream_content(setup_data):
|
|
64
86
|
client = EntityAPI()
|
|
65
87
|
asset = client.asset(ASSET_ID)
|
|
66
88
|
preservation_representations = list(filter(lambda x: x.rep_type == "Preservation", client.representations(asset)))
|
|
@@ -8,7 +8,30 @@ ASSET_ID = "683f9db7-ff81-4859-9c03-f68cfa5d9c3d"
|
|
|
8
8
|
CO_ID = "0f2997f7-728c-4e55-9f92-381ed1260d70"
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
def setup():
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def tear_down():
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def setup_data():
|
|
22
|
+
print("\nSetting up resources...")
|
|
23
|
+
|
|
24
|
+
setup()
|
|
25
|
+
|
|
26
|
+
yield
|
|
27
|
+
|
|
28
|
+
print("\nTearing down resources...")
|
|
29
|
+
|
|
30
|
+
tear_down()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_root_folders(setup_data):
|
|
12
35
|
client = EntityAPI()
|
|
13
36
|
paged_set = client.children(None)
|
|
14
37
|
assert paged_set.total > 0
|
|
@@ -20,14 +43,14 @@ def test_get_root_folders():
|
|
|
20
43
|
assert len(objs) == paged_set.total
|
|
21
44
|
|
|
22
45
|
|
|
23
|
-
def test_get_root_folders_descendants():
|
|
46
|
+
def test_get_root_folders_descendants(setup_data):
|
|
24
47
|
client = EntityAPI()
|
|
25
48
|
for f in client.descendants(None):
|
|
26
49
|
assert f.entity_type == EntityType.FOLDER
|
|
27
50
|
assert f.parent is None
|
|
28
51
|
|
|
29
52
|
|
|
30
|
-
def test_get_root_folder1():
|
|
53
|
+
def test_get_root_folder1(setup_data):
|
|
31
54
|
client = EntityAPI()
|
|
32
55
|
paged_set = client.children()
|
|
33
56
|
assert paged_set.total > 0
|
|
@@ -39,7 +62,7 @@ def test_get_root_folder1():
|
|
|
39
62
|
assert len(objs) == paged_set.total
|
|
40
63
|
|
|
41
64
|
|
|
42
|
-
def test_get_root_folders_paged():
|
|
65
|
+
def test_get_root_folders_paged(setup_data):
|
|
43
66
|
client = EntityAPI()
|
|
44
67
|
objs = set()
|
|
45
68
|
url = None
|
|
@@ -56,7 +79,7 @@ def test_get_root_folders_paged():
|
|
|
56
79
|
assert len(objs) == paged_set.total
|
|
57
80
|
|
|
58
81
|
|
|
59
|
-
def test_get_children_of_folder():
|
|
82
|
+
def test_get_children_of_folder(setup_data):
|
|
60
83
|
client = EntityAPI()
|
|
61
84
|
paged_set = client.children(FOLDER_ID)
|
|
62
85
|
assert paged_set.total == 171
|
|
@@ -65,7 +88,7 @@ def test_get_children_of_folder():
|
|
|
65
88
|
assert f.parent == FOLDER_ID
|
|
66
89
|
|
|
67
90
|
|
|
68
|
-
def test_get_children_of_folder_descendants():
|
|
91
|
+
def test_get_children_of_folder_descendants(setup_data):
|
|
69
92
|
client = EntityAPI()
|
|
70
93
|
objs = set()
|
|
71
94
|
for f in client.descendants(FOLDER_ID):
|
|
@@ -7,7 +7,30 @@ ASSET_ID = "683f9db7-ff81-4859-9c03-f68cfa5d9c3d"
|
|
|
7
7
|
CO_ID = "0f2997f7-728c-4e55-9f92-381ed1260d70"
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def setup():
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def tear_down():
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def setup_data():
|
|
22
|
+
print("\nSetting up resources...")
|
|
23
|
+
|
|
24
|
+
setup()
|
|
25
|
+
|
|
26
|
+
yield
|
|
27
|
+
|
|
28
|
+
print("\nTearing down resources...")
|
|
29
|
+
|
|
30
|
+
tear_down()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_get_asset_details(setup_data):
|
|
11
34
|
client = ContentAPI()
|
|
12
35
|
json_dict = client.object_details(EntityType.ASSET, ASSET_ID)
|
|
13
36
|
assert json_dict is not None
|
|
@@ -15,41 +38,41 @@ def test_get_asset_details():
|
|
|
15
38
|
assert json_dict['name'] == 'LC-USZ62-20901'
|
|
16
39
|
|
|
17
40
|
|
|
18
|
-
def test_download_asset():
|
|
41
|
+
def test_download_asset(setup_data):
|
|
19
42
|
client = ContentAPI()
|
|
20
43
|
filename = client.download(ASSET_ID, "filename.img")
|
|
21
44
|
assert os.path.exists(filename)
|
|
22
45
|
os.remove(filename)
|
|
23
46
|
|
|
24
47
|
|
|
25
|
-
def test_download_folder():
|
|
48
|
+
def test_download_folder(setup_data):
|
|
26
49
|
client = ContentAPI()
|
|
27
50
|
with pytest.raises(RuntimeError):
|
|
28
51
|
filename = client.download(FOLDER_ID, "filename.img")
|
|
29
52
|
|
|
30
53
|
|
|
31
|
-
def test_get_thumbnail_small():
|
|
54
|
+
def test_get_thumbnail_small(setup_data):
|
|
32
55
|
client = ContentAPI()
|
|
33
56
|
small = client.thumbnail("IO", "464444f7-8a6e-40f3-86c3-1dd2a51cfeeb", "filename.img", Thumbnail.SMALL)
|
|
34
57
|
assert os.path.exists(small)
|
|
35
58
|
os.remove(small)
|
|
36
59
|
|
|
37
60
|
|
|
38
|
-
def test_get_thumbnail_med():
|
|
61
|
+
def test_get_thumbnail_med(setup_data):
|
|
39
62
|
client = ContentAPI()
|
|
40
63
|
med = client.thumbnail("IO", "8d268bed-93d7-449b-91e4-2e7e86562a07", "filename.img", Thumbnail.MEDIUM)
|
|
41
64
|
assert os.path.exists(med)
|
|
42
65
|
os.remove(med)
|
|
43
66
|
|
|
44
67
|
|
|
45
|
-
def test_get_thumbnail_large():
|
|
68
|
+
def test_get_thumbnail_large(setup_data):
|
|
46
69
|
client = ContentAPI()
|
|
47
70
|
large = client.thumbnail("IO", "d5048e76-79c5-4ca7-99c9-a202c8f6dc8b", "filename.img", Thumbnail.LARGE)
|
|
48
71
|
assert os.path.exists(large)
|
|
49
72
|
os.remove(large)
|
|
50
73
|
|
|
51
74
|
|
|
52
|
-
def test_get_indexed_fields():
|
|
75
|
+
def test_get_indexed_fields(setup_data):
|
|
53
76
|
client = ContentAPI()
|
|
54
77
|
fields = client.indexed_fields()
|
|
55
78
|
assert fields is not None
|
|
@@ -57,24 +80,24 @@ def test_get_indexed_fields():
|
|
|
57
80
|
assert 'xip.description' in fields
|
|
58
81
|
|
|
59
82
|
|
|
60
|
-
def test_simple_search_list():
|
|
83
|
+
def test_simple_search_list(setup_data):
|
|
61
84
|
client = ContentAPI()
|
|
62
85
|
results = list(client.simple_search_list(query="pyPreservica"))
|
|
63
|
-
assert len(results) ==
|
|
86
|
+
assert len(results) == 5
|
|
64
87
|
assert results.pop()['xip.reference'] == '9fd239eb-19a3-4a46-9495-40fd9a5d8f93'
|
|
65
88
|
|
|
66
89
|
|
|
67
|
-
def test_simple_search_list2():
|
|
90
|
+
def test_simple_search_list2(setup_data):
|
|
68
91
|
client = ContentAPI()
|
|
69
92
|
|
|
70
93
|
columns = ["xip.reference", "xip.title", "xip.description", "xip.document_type"]
|
|
71
94
|
|
|
72
95
|
results = list(client.simple_search_list("pyPreservica", 25, columns))
|
|
73
|
-
assert len(results) ==
|
|
96
|
+
assert len(results) == 5
|
|
74
97
|
assert results.pop()['xip.reference'] == '9fd239eb-19a3-4a46-9495-40fd9a5d8f93'
|
|
75
98
|
|
|
76
99
|
|
|
77
|
-
def test_field_search():
|
|
100
|
+
def test_field_search(setup_data):
|
|
78
101
|
search = ContentAPI()
|
|
79
102
|
for result in search.search_index_filter_list(query="%", filter_values={"xip.security_descriptor": "open",
|
|
80
103
|
"xip.document_type": "IO",
|
|
@@ -35,9 +35,9 @@ def test_can_get_group():
|
|
|
35
35
|
def test_can_add_group_by_object():
|
|
36
36
|
client = MetadataGroupsAPI()
|
|
37
37
|
group1: Group = Group("my_group_name1", "my_group_description1")
|
|
38
|
-
group1.fields.append(GroupField(field_id="attribute_1", name="Attribute
|
|
39
|
-
group1.fields.append(GroupField(field_id="attribute_2", name="Attribute
|
|
40
|
-
group1.fields.append(GroupField(field_id="attribute_3", name="Attribute
|
|
38
|
+
group1.fields.append(GroupField(field_id="attribute_1", name="Attribute 1x", field_type=GroupFieldType.STRING))
|
|
39
|
+
group1.fields.append(GroupField(field_id="attribute_2", name="Attribute 2x", field_type=GroupFieldType.NUMBER))
|
|
40
|
+
group1.fields.append(GroupField(field_id="attribute_3", name="Attribute 3x", field_type=GroupFieldType.DATE))
|
|
41
41
|
|
|
42
42
|
g1: dict = client.add_group(group1.name, group1.description, group1.fields)
|
|
43
43
|
|
|
@@ -46,18 +46,24 @@ def test_can_add_group_by_object():
|
|
|
46
46
|
|
|
47
47
|
assert len(g1['fields']) == 3
|
|
48
48
|
|
|
49
|
-
client.
|
|
49
|
+
group1: Group = client.group(g1['id'])
|
|
50
|
+
|
|
51
|
+
client.delete_group(group1.group_id)
|
|
50
52
|
|
|
51
53
|
|
|
52
54
|
def test_can_add_new_fields_to_group():
|
|
53
55
|
client = MetadataGroupsAPI()
|
|
54
56
|
|
|
55
|
-
group2: Group = Group("
|
|
57
|
+
group2: Group = Group("test_group_1", "test_group_1_description")
|
|
58
|
+
|
|
59
|
+
assert len(group2.fields) == 0
|
|
56
60
|
|
|
57
61
|
group2.fields.append(GroupField(field_id="attribute_11", name="Attribute 11", field_type=GroupFieldType.STRING))
|
|
58
62
|
group2.fields.append(GroupField(field_id="attribute_22", name="Attribute 22", field_type=GroupFieldType.NUMBER))
|
|
59
63
|
group2.fields.append(GroupField(field_id="attribute_33", name="Attribute 33", field_type=GroupFieldType.DATE))
|
|
60
64
|
|
|
65
|
+
assert len(group2.fields) == 3
|
|
66
|
+
|
|
61
67
|
g2: dict = client.add_group(group2.name, group2.description, group2.fields)
|
|
62
68
|
|
|
63
69
|
assert g2['name'] == group2.name
|
|
@@ -6,7 +6,40 @@ ASSET_ID = "683f9db7-ff81-4859-9c03-f68cfa5d9c3d"
|
|
|
6
6
|
CO_ID = "0f2997f7-728c-4e55-9f92-381ed1260d70"
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def delete_identifiers():
|
|
10
|
+
client = EntityAPI()
|
|
11
|
+
folder = client.folder(FOLDER_ID)
|
|
12
|
+
for i in client.identifiers_for_entity(folder):
|
|
13
|
+
client.delete_identifiers(folder, i[0], i[1])
|
|
14
|
+
|
|
15
|
+
asset = client.asset(ASSET_ID)
|
|
16
|
+
for i in client.identifiers_for_entity(asset):
|
|
17
|
+
client.delete_identifiers(asset, i[0], i[1])
|
|
18
|
+
|
|
19
|
+
co = client.content_object(CO_ID)
|
|
20
|
+
for i in client.identifiers_for_entity(co):
|
|
21
|
+
client.delete_identifiers(co, i[0], i[1])
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def setup_data():
|
|
26
|
+
print("\nSetting up resources...")
|
|
27
|
+
|
|
28
|
+
client = EntityAPI()
|
|
29
|
+
folder = client.folder(FOLDER_ID)
|
|
30
|
+
|
|
31
|
+
delete_identifiers()
|
|
32
|
+
|
|
33
|
+
client.add_identifier(folder, "code", "Amelia Earhart")
|
|
34
|
+
|
|
35
|
+
yield
|
|
36
|
+
|
|
37
|
+
print("\nTearing down resources...")
|
|
38
|
+
|
|
39
|
+
delete_identifiers()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_get_entity_by_identifier(setup_data):
|
|
10
43
|
client = EntityAPI()
|
|
11
44
|
list_of_objects = client.identifier("code", "Amelia Earhart")
|
|
12
45
|
assert len(list_of_objects) == 1
|
|
@@ -16,7 +49,7 @@ def test_get_entity_by_identifier():
|
|
|
16
49
|
assert entity.reference == FOLDER_ID
|
|
17
50
|
|
|
18
51
|
|
|
19
|
-
def test_add_identifier_folder():
|
|
52
|
+
def test_add_identifier_folder(setup_data):
|
|
20
53
|
client = EntityAPI()
|
|
21
54
|
folder = client.folder(FOLDER_ID)
|
|
22
55
|
client.add_identifier(folder, "ISBN", "1234567890")
|
|
@@ -26,7 +59,7 @@ def test_add_identifier_folder():
|
|
|
26
59
|
assert entity.reference == folder.reference
|
|
27
60
|
|
|
28
61
|
|
|
29
|
-
def test_add_identifier_asset():
|
|
62
|
+
def test_add_identifier_asset(setup_data):
|
|
30
63
|
client = EntityAPI()
|
|
31
64
|
asset = client.asset(ASSET_ID)
|
|
32
65
|
client.add_identifier(asset, "ARK", "1234567890")
|
|
@@ -37,7 +70,7 @@ def test_add_identifier_asset():
|
|
|
37
70
|
assert len(client.identifiers_for_entity(asset)) == 1
|
|
38
71
|
|
|
39
72
|
|
|
40
|
-
def test_add_identifier_content_obj():
|
|
73
|
+
def test_add_identifier_content_obj(setup_data):
|
|
41
74
|
client = EntityAPI()
|
|
42
75
|
content_object = client.content_object(CO_ID)
|
|
43
76
|
client.add_identifier(content_object, "CO", "12333")
|
|
@@ -48,11 +81,15 @@ def test_add_identifier_content_obj():
|
|
|
48
81
|
assert len(client.identifiers_for_entity(content_object)) == 1
|
|
49
82
|
|
|
50
83
|
|
|
51
|
-
def test_get_identifier_folder():
|
|
84
|
+
def test_get_identifier_folder(setup_data):
|
|
52
85
|
client = EntityAPI()
|
|
53
86
|
folder = client.folder(FOLDER_ID)
|
|
87
|
+
|
|
88
|
+
client.add_identifier(folder, "ISBN", "1234567890")
|
|
89
|
+
client.add_identifier(folder, "ARK", "1234567890")
|
|
90
|
+
|
|
54
91
|
identifiers = client.identifiers_for_entity(folder)
|
|
55
|
-
assert len(identifiers) ==
|
|
92
|
+
assert len(identifiers) == 3
|
|
56
93
|
test_pass = False
|
|
57
94
|
for identifier in identifiers:
|
|
58
95
|
if "ISBN" in identifier:
|
|
@@ -61,9 +98,12 @@ def test_get_identifier_folder():
|
|
|
61
98
|
assert test_pass
|
|
62
99
|
|
|
63
100
|
|
|
64
|
-
def test_get_identifier_asset():
|
|
101
|
+
def test_get_identifier_asset(setup_data):
|
|
65
102
|
client = EntityAPI()
|
|
66
103
|
asset = client.asset(ASSET_ID)
|
|
104
|
+
|
|
105
|
+
client.add_identifier(asset, "ARK", "1234567890")
|
|
106
|
+
|
|
67
107
|
identifiers = client.identifiers_for_entity(asset)
|
|
68
108
|
assert len(identifiers) == 1
|
|
69
109
|
test_pass = False
|
|
@@ -74,9 +114,12 @@ def test_get_identifier_asset():
|
|
|
74
114
|
assert test_pass
|
|
75
115
|
|
|
76
116
|
|
|
77
|
-
def test_delete_identifier_folder():
|
|
117
|
+
def test_delete_identifier_folder(setup_data):
|
|
78
118
|
client = EntityAPI()
|
|
79
119
|
folder = client.folder(FOLDER_ID)
|
|
120
|
+
|
|
121
|
+
client.add_identifier(folder, "ISBN", "1234567890")
|
|
122
|
+
|
|
80
123
|
entity_set = client.identifier("ISBN", "1234567890")
|
|
81
124
|
assert len(entity_set) == 1
|
|
82
125
|
entity = entity_set.pop()
|
|
@@ -89,9 +132,12 @@ def test_delete_identifier_folder():
|
|
|
89
132
|
assert len(identifiers) == 1
|
|
90
133
|
|
|
91
134
|
|
|
92
|
-
def test_delete_identifier_asset():
|
|
135
|
+
def test_delete_identifier_asset(setup_data):
|
|
93
136
|
client = EntityAPI()
|
|
94
137
|
asset = client.asset(ASSET_ID)
|
|
138
|
+
|
|
139
|
+
client.add_identifier(asset, "ARK", "1234567890")
|
|
140
|
+
|
|
95
141
|
entity_set = client.identifier("ARK", "1234567890")
|
|
96
142
|
assert len(entity_set) == 1
|
|
97
143
|
entity = entity_set.pop()
|
|
@@ -101,9 +147,12 @@ def test_delete_identifier_asset():
|
|
|
101
147
|
assert len(entity_set) == 0
|
|
102
148
|
|
|
103
149
|
|
|
104
|
-
def test_delete_identifier_co():
|
|
150
|
+
def test_delete_identifier_co(setup_data):
|
|
105
151
|
client = EntityAPI()
|
|
106
152
|
content_object = client.content_object(CO_ID)
|
|
153
|
+
|
|
154
|
+
client.add_identifier(content_object, "CO", "12333")
|
|
155
|
+
|
|
107
156
|
entity_set = client.identifier("CO", "12333")
|
|
108
157
|
assert len(entity_set) == 1
|
|
109
158
|
entity = entity_set.pop()
|
|
@@ -113,7 +162,7 @@ def test_delete_identifier_co():
|
|
|
113
162
|
assert len(entity_set) == 0
|
|
114
163
|
|
|
115
164
|
|
|
116
|
-
def test_add_same_id_to_asset_folder():
|
|
165
|
+
def test_add_same_id_to_asset_folder(setup_data):
|
|
117
166
|
client = EntityAPI()
|
|
118
167
|
asset = client.asset(ASSET_ID)
|
|
119
168
|
folder = client.folder(FOLDER_ID)
|
|
@@ -129,3 +178,19 @@ def test_add_same_id_to_asset_folder():
|
|
|
129
178
|
client.delete_identifiers(folder, "DOI", "123456:98776")
|
|
130
179
|
entity_set = client.identifier("DOI", "123456:98776")
|
|
131
180
|
assert len(entity_set) == 0
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_can_update_identifier(setup_data):
|
|
184
|
+
client = EntityAPI()
|
|
185
|
+
folder = client.folder(FOLDER_ID)
|
|
186
|
+
client.add_identifier(folder, "ISBN", "ISBN_0001")
|
|
187
|
+
entity_set = client.identifier("ISBN", "ISBN_0001")
|
|
188
|
+
assert len(entity_set) == 1
|
|
189
|
+
entity = entity_set.pop()
|
|
190
|
+
assert entity.reference == folder.reference
|
|
191
|
+
client.update_identifiers(folder, "ISBN", "ISBN_0002")
|
|
192
|
+
entity_set = client.identifier("ISBN", "ISBN_0002")
|
|
193
|
+
assert len(entity_set) == 1
|
|
194
|
+
entity = entity_set.pop()
|
|
195
|
+
assert entity.reference == folder.reference
|
|
196
|
+
client.delete_identifiers(folder, "ISBN", "ISBN_0002")
|
|
@@ -6,7 +6,7 @@ from pyPreservica import *
|
|
|
6
6
|
def test_format_families():
|
|
7
7
|
par = PreservationActionRegistry()
|
|
8
8
|
document = par.format_families()
|
|
9
|
-
assert len(json.loads(document)['formatFamilies']) ==
|
|
9
|
+
assert len(json.loads(document)['formatFamilies']) == 190
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def test_format():
|
|
@@ -14,7 +14,7 @@ def test_get_policy_by_name():
|
|
|
14
14
|
|
|
15
15
|
def test_get_policies():
|
|
16
16
|
retention = RetentionAPI()
|
|
17
|
-
for p in retention.policies():
|
|
17
|
+
for p in retention.policies().results:
|
|
18
18
|
print(p.name)
|
|
19
19
|
print(p.reference)
|
|
20
20
|
print(p.description)
|
|
@@ -106,7 +106,7 @@ def test_add_assignments():
|
|
|
106
106
|
|
|
107
107
|
assert len(retention_assignments) == 0
|
|
108
108
|
|
|
109
|
-
policy = retention.policies().pop()
|
|
109
|
+
policy = retention.policies().results.pop()
|
|
110
110
|
|
|
111
111
|
if not policy.assignable:
|
|
112
112
|
retention.assignable_policy(policy.reference, True)
|
|
@@ -126,7 +126,7 @@ def test_add_assignments():
|
|
|
126
126
|
|
|
127
127
|
def test_zdelete_policy():
|
|
128
128
|
retention = RetentionAPI()
|
|
129
|
-
for policy in retention.policies():
|
|
129
|
+
for policy in retention.policies().results:
|
|
130
130
|
if policy.name == "API Created Policy1":
|
|
131
131
|
retention.delete_policy(policy.reference)
|
|
132
132
|
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
from pyPreservica import *
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def test_get_tables():
|
|
6
|
-
client = AuthorityAPI()
|
|
7
|
-
results = client.tables()
|
|
8
|
-
assert isinstance(results, set)
|
|
9
|
-
for table in results:
|
|
10
|
-
assert isinstance(table, Table)
|
|
11
|
-
assert table.name in ["Countries", 'Physical Storage']
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def test_get_records():
|
|
15
|
-
client = AuthorityAPI()
|
|
16
|
-
tables = client.tables()
|
|
17
|
-
for tab in tables:
|
|
18
|
-
records = client.records(tab)
|
|
19
|
-
|
|
20
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|