pyPreservica 3.0.5__py3-none-any.whl → 3.1.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 +14 -3
- pyPreservica/adminAPI.py +8 -8
- pyPreservica/authorityAPI.py +5 -6
- pyPreservica/common.py +20 -3
- pyPreservica/contentAPI.py +1 -1
- pyPreservica/entityAPI.py +60 -7
- pyPreservica/mdformsAPI.py +3 -4
- pyPreservica/monitorAPI.py +2 -2
- pyPreservica/retentionAPI.py +2 -2
- pyPreservica/uploadAPI.py +24 -16
- pyPreservica/webHooksAPI.py +0 -1
- {pyPreservica-3.0.5.dist-info → pypreservica-3.1.1.dist-info}/METADATA +5 -4
- pypreservica-3.1.1.dist-info/RECORD +19 -0
- {pyPreservica-3.0.5.dist-info → pypreservica-3.1.1.dist-info}/WHEEL +1 -1
- pyPreservica-3.0.5.dist-info/RECORD +0 -19
- {pyPreservica-3.0.5.dist-info → pypreservica-3.1.1.dist-info/licenses}/LICENSE.txt +0 -0
- {pyPreservica-3.0.5.dist-info → pypreservica-3.1.1.dist-info}/top_level.txt +0 -0
pyPreservica/__init__.py
CHANGED
|
@@ -6,11 +6,22 @@ author: James Carr
|
|
|
6
6
|
licence: Apache License 2.0
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
|
+
|
|
9
10
|
from .common import *
|
|
10
11
|
from .contentAPI import ContentAPI, Field, SortOrder
|
|
11
12
|
from .entityAPI import EntityAPI
|
|
12
|
-
from .uploadAPI import
|
|
13
|
-
|
|
13
|
+
from .uploadAPI import (
|
|
14
|
+
UploadAPI,
|
|
15
|
+
simple_asset_package,
|
|
16
|
+
complex_asset_package,
|
|
17
|
+
cvs_to_xsd,
|
|
18
|
+
cvs_to_xml,
|
|
19
|
+
cvs_to_cmis_xslt,
|
|
20
|
+
csv_to_search_xml,
|
|
21
|
+
generic_asset_package,
|
|
22
|
+
upload_config,
|
|
23
|
+
multi_asset_package,
|
|
24
|
+
)
|
|
14
25
|
from .workflowAPI import WorkflowAPI, WorkflowContext, WorkflowInstance
|
|
15
26
|
from .retentionAPI import RetentionAPI, RetentionAssignment, RetentionPolicy
|
|
16
27
|
from .parAPI import PreservationActionRegistry
|
|
@@ -23,6 +34,6 @@ from .mdformsAPI import MetadataGroupsAPI, Group, GroupField, GroupFieldType
|
|
|
23
34
|
__author__ = "James Carr (drjamescarr@gmail.com)"
|
|
24
35
|
|
|
25
36
|
# Version of the pyPreservica package
|
|
26
|
-
__version__ = "3.
|
|
37
|
+
__version__ = "3.1.1"
|
|
27
38
|
|
|
28
39
|
__license__ = "Apache License Version 2.0"
|
pyPreservica/adminAPI.py
CHANGED
|
@@ -444,7 +444,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
444
444
|
:param xml_data: The xml schema as a UTF-8 string or a file like object
|
|
445
445
|
:type xml_data: Any
|
|
446
446
|
|
|
447
|
-
:return:
|
|
447
|
+
:return:
|
|
448
448
|
:rtype: None
|
|
449
449
|
"""
|
|
450
450
|
|
|
@@ -493,7 +493,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
493
493
|
:param document_type: The type of the XML document, defaults to descriptive metadata templates
|
|
494
494
|
:type document_type: str
|
|
495
495
|
|
|
496
|
-
:return:
|
|
496
|
+
:return:
|
|
497
497
|
:rtype: None
|
|
498
498
|
|
|
499
499
|
"""
|
|
@@ -523,12 +523,12 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
523
523
|
|
|
524
524
|
def delete_xml_document(self, uri: str):
|
|
525
525
|
"""
|
|
526
|
-
Delete
|
|
526
|
+
Delete an XML document from Preservica's XML document store
|
|
527
527
|
|
|
528
528
|
:param uri: The URI of the xml document to delete
|
|
529
529
|
:type uri: str
|
|
530
530
|
|
|
531
|
-
:return:
|
|
531
|
+
:return:
|
|
532
532
|
:rtype: None
|
|
533
533
|
|
|
534
534
|
"""
|
|
@@ -558,7 +558,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
558
558
|
:param uri: The URI of the xml schema to delete
|
|
559
559
|
:type uri: str
|
|
560
560
|
|
|
561
|
-
:return:
|
|
561
|
+
:return:
|
|
562
562
|
:rtype: None
|
|
563
563
|
|
|
564
564
|
"""
|
|
@@ -582,7 +582,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
582
582
|
|
|
583
583
|
def xml_schema(self, uri: str) -> str:
|
|
584
584
|
"""
|
|
585
|
-
|
|
585
|
+
Fetch the metadata schema XSD document as a string by its URI
|
|
586
586
|
|
|
587
587
|
:param uri: The URI of the xml schema
|
|
588
588
|
:type uri: str
|
|
@@ -793,7 +793,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
793
793
|
:param output_uri: The URI of the output XML document
|
|
794
794
|
:type output_uri: str
|
|
795
795
|
|
|
796
|
-
:return:
|
|
796
|
+
:return:
|
|
797
797
|
:rtype: None
|
|
798
798
|
|
|
799
799
|
"""
|
|
@@ -839,7 +839,7 @@ class AdminAPI(AuthenticatedAPI):
|
|
|
839
839
|
:param xml_data: The transform xml as a string or file like object
|
|
840
840
|
:type xml_data: Any
|
|
841
841
|
|
|
842
|
-
:return:
|
|
842
|
+
:return:
|
|
843
843
|
:rtype: None
|
|
844
844
|
|
|
845
845
|
"""
|
pyPreservica/authorityAPI.py
CHANGED
|
@@ -8,9 +8,8 @@ author: James Carr
|
|
|
8
8
|
licence: Apache License 2.0
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import csv
|
|
13
|
-
import requests
|
|
14
13
|
from typing import List, Set
|
|
15
14
|
|
|
16
15
|
from pyPreservica.common import *
|
|
@@ -92,7 +91,7 @@ class AuthorityAPI(AuthenticatedAPI):
|
|
|
92
91
|
:param table: The Table to add the record to
|
|
93
92
|
:type: table: Table
|
|
94
93
|
|
|
95
|
-
:param record: The record
|
|
94
|
+
:param record: The record as a dictionary
|
|
96
95
|
:type: record: dict
|
|
97
96
|
|
|
98
97
|
:return: A single record
|
|
@@ -123,7 +122,7 @@ class AuthorityAPI(AuthenticatedAPI):
|
|
|
123
122
|
"""
|
|
124
123
|
Return a record by its reference
|
|
125
124
|
|
|
126
|
-
:param reference: The record
|
|
125
|
+
:param reference: The reference of the record
|
|
127
126
|
:type: reference: str
|
|
128
127
|
|
|
129
128
|
:return: A single record
|
|
@@ -149,7 +148,7 @@ class AuthorityAPI(AuthenticatedAPI):
|
|
|
149
148
|
"""
|
|
150
149
|
Return all records from a table
|
|
151
150
|
|
|
152
|
-
:param table: The authority table
|
|
151
|
+
:param table: The authority table to return the records from
|
|
153
152
|
:type: table: Table
|
|
154
153
|
|
|
155
154
|
:return: List of records
|
|
@@ -178,7 +177,7 @@ class AuthorityAPI(AuthenticatedAPI):
|
|
|
178
177
|
:param reference: The reference for the authority table
|
|
179
178
|
:type: reference: str
|
|
180
179
|
|
|
181
|
-
:return: An authority table
|
|
180
|
+
:return: An authority table of interest
|
|
182
181
|
:rtype: Table
|
|
183
182
|
|
|
184
183
|
"""
|
pyPreservica/common.py
CHANGED
|
@@ -23,7 +23,7 @@ import xml.etree.ElementTree
|
|
|
23
23
|
from enum import Enum
|
|
24
24
|
from pathlib import Path
|
|
25
25
|
import pyotp
|
|
26
|
-
from requests import
|
|
26
|
+
from requests import Session
|
|
27
27
|
from urllib3.util import Retry
|
|
28
28
|
import requests
|
|
29
29
|
from requests.adapters import HTTPAdapter
|
|
@@ -568,6 +568,22 @@ class Thumbnail(Enum):
|
|
|
568
568
|
LARGE = "large"
|
|
569
569
|
|
|
570
570
|
|
|
571
|
+
class AsyncProgress(Enum):
|
|
572
|
+
"""
|
|
573
|
+
Enumeration of the possible status of an asynchronous process
|
|
574
|
+
"""
|
|
575
|
+
ABORTED = "ABORTED"
|
|
576
|
+
ACTIVE = "ACTIVE"
|
|
577
|
+
COMPLETED = "COMPLETED"
|
|
578
|
+
PENDING = "PENDING"
|
|
579
|
+
SUSPENDING = "SUSPENDING"
|
|
580
|
+
SUSPENDED = "SUSPENDED"
|
|
581
|
+
UNKNOWN = "UNKNOWN"
|
|
582
|
+
FAILED = "FAILED"
|
|
583
|
+
FINISHED_MIXED_OUTCOME = "FINISHED_MIXED_OUTCOME"
|
|
584
|
+
CANCELLED = "CANCELLED"
|
|
585
|
+
|
|
586
|
+
|
|
571
587
|
def sanitize(filename) -> str:
|
|
572
588
|
"""
|
|
573
589
|
Return a fairly safe version of the filename.
|
|
@@ -837,6 +853,7 @@ class AuthenticatedAPI:
|
|
|
837
853
|
if self.tenant is None:
|
|
838
854
|
self.tenant = response.json()['tenant']
|
|
839
855
|
if self.two_fa_secret_key:
|
|
856
|
+
logger.debug("Found Two Factor Token")
|
|
840
857
|
totp = pyotp.TOTP(self.two_fa_secret_key)
|
|
841
858
|
data = {'username': self.username,
|
|
842
859
|
'continuationToken': response.json()['continuationToken'],
|
|
@@ -849,8 +866,8 @@ class AuthenticatedAPI:
|
|
|
849
866
|
else:
|
|
850
867
|
msg = "Failed to create a 2FA authentication token. Check your credentials are correct"
|
|
851
868
|
logger.error(msg)
|
|
852
|
-
logger.error(str(
|
|
853
|
-
raise RuntimeError(
|
|
869
|
+
logger.error(str(response_2fa.content))
|
|
870
|
+
raise RuntimeError(response_2fa.status_code, msg)
|
|
854
871
|
else:
|
|
855
872
|
msg = "2FA twoFactorToken required to authenticate against this account using 2FA"
|
|
856
873
|
logger.error(msg)
|
pyPreservica/contentAPI.py
CHANGED
|
@@ -316,7 +316,7 @@ class ContentAPI(AuthenticatedAPI):
|
|
|
316
316
|
return search_results
|
|
317
317
|
elif results.status_code == requests.codes.unauthorized:
|
|
318
318
|
self.token = self.__token__()
|
|
319
|
-
return self.
|
|
319
|
+
return self._search_fields(query, fields, start_index, page_size)
|
|
320
320
|
else:
|
|
321
321
|
logger.error(f"search failed with error code: {results.status_code}")
|
|
322
322
|
raise RuntimeError(results.status_code, f"search_index_filter failed")
|
pyPreservica/entityAPI.py
CHANGED
|
@@ -70,7 +70,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
70
70
|
with self.session.get(bitstream.content_url, headers={HEADER_TOKEN: self.token}, stream=True) as request:
|
|
71
71
|
if request.status_code == requests.codes.unauthorized:
|
|
72
72
|
self.token = self.__token__()
|
|
73
|
-
|
|
73
|
+
yield from self.bitstream_chunks(bitstream)
|
|
74
74
|
elif request.status_code == requests.codes.ok:
|
|
75
75
|
for chunk in request.iter_content(chunk_size=chunk_size):
|
|
76
76
|
yield chunk
|
|
@@ -918,7 +918,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
918
918
|
content.append(tree.getroot())
|
|
919
919
|
else:
|
|
920
920
|
raise RuntimeError("Unknown data type")
|
|
921
|
-
xml_request = xml.etree.ElementTree.tostring(xml_object, encoding='utf-8')
|
|
921
|
+
xml_request = xml.etree.ElementTree.tostring(xml_object, encoding='utf-8').decode("utf-8")
|
|
922
922
|
logger.debug(xml_request)
|
|
923
923
|
request = self.session.put(url, data=xml_request, headers=headers)
|
|
924
924
|
if request.status_code == requests.codes.ok:
|
|
@@ -1068,6 +1068,10 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1068
1068
|
logger.error(exception)
|
|
1069
1069
|
raise exception
|
|
1070
1070
|
|
|
1071
|
+
def get_progress(self, pid: str) -> AsyncProgress:
|
|
1072
|
+
return AsyncProgress[self.get_async_progress(pid)]
|
|
1073
|
+
|
|
1074
|
+
|
|
1071
1075
|
def get_async_progress(self, pid: str) -> str:
|
|
1072
1076
|
headers = {HEADER_TOKEN: self.token, 'Content-Type': 'text/plain'}
|
|
1073
1077
|
request = self.session.get(f"{self.protocol}://{self.server}/api/entity/progress/{pid}", headers=headers)
|
|
@@ -1181,7 +1185,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1181
1185
|
logger.error(exception)
|
|
1182
1186
|
raise exception
|
|
1183
1187
|
|
|
1184
|
-
def all_metadata(self, entity: Entity) -> Tuple:
|
|
1188
|
+
def all_metadata(self, entity: Entity) -> Generator[Tuple[str, str], None, None]:
|
|
1185
1189
|
"""
|
|
1186
1190
|
Retrieve all metadata fragments on an entity
|
|
1187
1191
|
|
|
@@ -1511,6 +1515,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1511
1515
|
Retrieve a list of generation objects
|
|
1512
1516
|
|
|
1513
1517
|
:param url:
|
|
1518
|
+
:param content_ref:
|
|
1514
1519
|
:returns Generation
|
|
1515
1520
|
"""
|
|
1516
1521
|
headers = {HEADER_TOKEN: self.token}
|
|
@@ -1873,9 +1878,46 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1873
1878
|
logger.error(exception)
|
|
1874
1879
|
raise exception
|
|
1875
1880
|
|
|
1881
|
+
# def add_preservation_representation(self, entity: Entity, preservation_file: str, name: str = "Preservation"):
|
|
1882
|
+
# """
|
|
1883
|
+
# Add a new Preservation representation to an existing asset.
|
|
1884
|
+
#
|
|
1885
|
+
# :param entity: The existing asset which will receive the new representation
|
|
1886
|
+
# :param preservation_file: The new digital file
|
|
1887
|
+
# :param name: The name of the new access representation defaults to "Access"
|
|
1888
|
+
# :return:
|
|
1889
|
+
# """
|
|
1890
|
+
#
|
|
1891
|
+
# if self.major_version < 7 and self.minor_version < 12:
|
|
1892
|
+
# raise RuntimeError("Add Representation API is only available when connected to a v6.12 System")
|
|
1893
|
+
#
|
|
1894
|
+
# if isinstance(entity, Folder) or isinstance(entity, ContentObject):
|
|
1895
|
+
# raise RuntimeError("Add Representation cannot be added to Folders and Content Objects")
|
|
1896
|
+
#
|
|
1897
|
+
# headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/octet-stream'}
|
|
1898
|
+
#
|
|
1899
|
+
# filename = os.path.basename(preservation_file)
|
|
1900
|
+
#
|
|
1901
|
+
# params = {'type': 'Preservation', 'name': name, 'filename': filename}
|
|
1902
|
+
#
|
|
1903
|
+
# with open(preservation_file, 'rb') as fd:
|
|
1904
|
+
# request = self.session.post(
|
|
1905
|
+
# f'{self.protocol}://{self.server}/api/entity/{entity.path}/{entity.reference}/representations',
|
|
1906
|
+
# data=fd, headers=headers, params=params)
|
|
1907
|
+
# if request.status_code == requests.codes.accepted:
|
|
1908
|
+
# return str(request.content.decode('utf-8'))
|
|
1909
|
+
# elif request.status_code == requests.codes.unauthorized:
|
|
1910
|
+
# self.token = self.__token__()
|
|
1911
|
+
# return self.add_access_representation(entity, preservation_file, name)
|
|
1912
|
+
# else:
|
|
1913
|
+
# exception = HTTPException(entity.reference, request.status_code, request.url,
|
|
1914
|
+
# "add_preservation_representation", request.content.decode('utf-8'))
|
|
1915
|
+
# logger.error(exception)
|
|
1916
|
+
# raise exception
|
|
1917
|
+
|
|
1876
1918
|
def add_access_representation(self, entity: Entity, access_file: str, name: str = "Access"):
|
|
1877
1919
|
"""
|
|
1878
|
-
Add a new representation to an existing asset.
|
|
1920
|
+
Add a new Access representation to an existing asset.
|
|
1879
1921
|
|
|
1880
1922
|
:param entity: The existing asset which will receive the new representation
|
|
1881
1923
|
:param access_file: The new digital file
|
|
@@ -2084,9 +2126,15 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
2084
2126
|
actions = entity_response.findall(f'.//{{{self.xip_ns}}}EventAction')
|
|
2085
2127
|
result_list = []
|
|
2086
2128
|
for action in actions:
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2129
|
+
item: dict = {}
|
|
2130
|
+
event = action.find(f'.//{{{self.xip_ns}}}Event')
|
|
2131
|
+
event_type = event.attrib["type"]
|
|
2132
|
+
item['EventType'] = event_type
|
|
2133
|
+
entity_date = action.find(f'.//{{{self.xip_ns}}}Date')
|
|
2134
|
+
item['Date'] = entity_date.text
|
|
2135
|
+
entity_ref = action.find(f'.//{{{self.xip_ns}}}Entity')
|
|
2136
|
+
item['Entity'] = entity_ref.text
|
|
2137
|
+
result_list.append(item)
|
|
2090
2138
|
next_url = entity_response.find(f'.//{{{self.entity_ns}}}Next')
|
|
2091
2139
|
total_hits = entity_response.find(f'.//{{{self.entity_ns}}}TotalResults')
|
|
2092
2140
|
has_more = True
|
|
@@ -2120,6 +2168,9 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
2120
2168
|
params["from"] = kwargs.get("from_date")
|
|
2121
2169
|
if "to_date" in kwargs:
|
|
2122
2170
|
params["to"] = kwargs.get("to_date")
|
|
2171
|
+
if "username" in kwargs:
|
|
2172
|
+
params["username"] = kwargs.get("username")
|
|
2173
|
+
|
|
2123
2174
|
|
|
2124
2175
|
if next_page is None:
|
|
2125
2176
|
request = self.session.get(f'{self.protocol}://{self.server}/api/entity/events', params=params,
|
|
@@ -2324,6 +2375,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
2324
2375
|
:param asset: The Asset
|
|
2325
2376
|
:param operator_comment: The operator comment on the deletion
|
|
2326
2377
|
:param supervisor_comment: The supervisor comment on the deletion
|
|
2378
|
+
:param credentials_path: The path to the credentials file
|
|
2327
2379
|
"""
|
|
2328
2380
|
if isinstance(asset, Asset):
|
|
2329
2381
|
return self._delete_entity(asset, operator_comment, supervisor_comment, credentials_path)
|
|
@@ -2338,6 +2390,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
2338
2390
|
:param folder: The Folder
|
|
2339
2391
|
:param operator_comment: The operator comment on the deletion
|
|
2340
2392
|
:param supervisor_comment: The supervisor comment on the deletion
|
|
2393
|
+
:param credentials_path: The path to the credentials file
|
|
2341
2394
|
"""
|
|
2342
2395
|
if isinstance(folder, Folder):
|
|
2343
2396
|
return self._delete_entity(folder, operator_comment, supervisor_comment, credentials_path)
|
pyPreservica/mdformsAPI.py
CHANGED
|
@@ -8,7 +8,6 @@ author: James Carr
|
|
|
8
8
|
licence: Apache License 2.0
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
|
-
import json
|
|
12
11
|
import xml.etree.ElementTree
|
|
13
12
|
from typing import Callable, List, Union, Generator
|
|
14
13
|
|
|
@@ -251,7 +250,7 @@ class MetadataGroupsAPI(AuthenticatedAPI):
|
|
|
251
250
|
|
|
252
251
|
def add_form(self, json_form: Union[dict, str]):
|
|
253
252
|
"""
|
|
254
|
-
Create a new Metadata
|
|
253
|
+
Create a new Metadata form using a JSON dictionary object or document
|
|
255
254
|
|
|
256
255
|
:param json_form: JSON dictionary or string
|
|
257
256
|
:type json_form: dict
|
|
@@ -267,7 +266,7 @@ class MetadataGroupsAPI(AuthenticatedAPI):
|
|
|
267
266
|
with self.session.post(url, headers=headers, json=json_form) as request:
|
|
268
267
|
if request.status_code == requests.codes.unauthorized:
|
|
269
268
|
self.token = self.__token__()
|
|
270
|
-
return self.
|
|
269
|
+
return self.add_form(json_form)
|
|
271
270
|
elif request.status_code == requests.codes.created:
|
|
272
271
|
return json.loads(str(request.content.decode('utf-8')))
|
|
273
272
|
else:
|
|
@@ -280,7 +279,7 @@ class MetadataGroupsAPI(AuthenticatedAPI):
|
|
|
280
279
|
with self.session.post(url, headers=headers, data=json_form) as request:
|
|
281
280
|
if request.status_code == requests.codes.unauthorized:
|
|
282
281
|
self.token = self.__token__()
|
|
283
|
-
return self.
|
|
282
|
+
return self.add_form(json_form)
|
|
284
283
|
elif request.status_code == requests.codes.created:
|
|
285
284
|
return json.loads(str(request.content.decode('utf-8')))
|
|
286
285
|
else:
|
pyPreservica/monitorAPI.py
CHANGED
|
@@ -89,7 +89,7 @@ class MonitorAPI(AuthenticatedAPI):
|
|
|
89
89
|
|
|
90
90
|
:param monitor_id: The Process ID
|
|
91
91
|
:type monitor_id: str
|
|
92
|
-
:param status: The message status, info, warning, error etc
|
|
92
|
+
:param status: The message status, info, warning, error etc.
|
|
93
93
|
:type status: MessageStatus
|
|
94
94
|
:return: Generator for each message, each message is a dict object
|
|
95
95
|
"""
|
|
@@ -147,7 +147,7 @@ class MonitorAPI(AuthenticatedAPI):
|
|
|
147
147
|
yield monitor
|
|
148
148
|
elif request.status_code == requests.codes.unauthorized:
|
|
149
149
|
self.token = self.__token__()
|
|
150
|
-
|
|
150
|
+
yield from self.monitors(status, category)
|
|
151
151
|
else:
|
|
152
152
|
logger.error(request.content.decode('utf-8'))
|
|
153
153
|
raise RuntimeError(request.status_code, "monitors failed")
|
pyPreservica/retentionAPI.py
CHANGED
|
@@ -96,7 +96,7 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
96
96
|
if start_date_field is not None:
|
|
97
97
|
rp.start_date_field = start_date_field.text
|
|
98
98
|
else:
|
|
99
|
-
start_date_field = None
|
|
99
|
+
rp.start_date_field = None
|
|
100
100
|
period = entity_response.find(f'.//{{{self.rm_ns}}}RetentionPolicy/{{{self.rm_ns}}}Period')
|
|
101
101
|
if period is not None:
|
|
102
102
|
rp.period = period.text
|
|
@@ -404,7 +404,7 @@ class RetentionAPI(AuthenticatedAPI):
|
|
|
404
404
|
def policies(self, maximum: int = 250, next_page: str = None) -> PagedSet:
|
|
405
405
|
"""
|
|
406
406
|
Return a list of all retention policies
|
|
407
|
-
Returns a
|
|
407
|
+
Returns a maximum of 250 policies by default
|
|
408
408
|
|
|
409
409
|
|
|
410
410
|
:return: Set of retention policies
|
pyPreservica/uploadAPI.py
CHANGED
|
@@ -20,7 +20,6 @@ from xml.etree import ElementTree
|
|
|
20
20
|
from xml.etree.ElementTree import Element, SubElement
|
|
21
21
|
|
|
22
22
|
import boto3
|
|
23
|
-
import botocore
|
|
24
23
|
import s3transfer.tasks
|
|
25
24
|
import s3transfer.upload
|
|
26
25
|
from botocore.session import get_session
|
|
@@ -483,7 +482,7 @@ def generic_asset_package(preservation_files_dict=None, access_files_dict=None,
|
|
|
483
482
|
content_type = kwargs.get('CustomType', "")
|
|
484
483
|
|
|
485
484
|
if not compress:
|
|
486
|
-
shutil.register_archive_format("szip", _make_stored_zipfile, None, "UnCompressed ZIP file")
|
|
485
|
+
shutil.register_archive_format(name="szip", function=_make_stored_zipfile, extra_args=None, description="UnCompressed ZIP file")
|
|
487
486
|
|
|
488
487
|
has_preservation_files = bool((preservation_files_dict is not None) and (len(preservation_files_dict) > 0))
|
|
489
488
|
has_access_files = bool((access_files_dict is not None) and (len(access_files_dict) > 0))
|
|
@@ -912,17 +911,22 @@ def complex_asset_package(preservation_files_list=None, access_files_list=None,
|
|
|
912
911
|
if has_preservation_files:
|
|
913
912
|
if default_asset_title is None:
|
|
914
913
|
default_asset_title = os.path.splitext(os.path.basename(preservation_files_list[0]))[0]
|
|
915
|
-
|
|
916
914
|
# create the asset
|
|
917
|
-
|
|
915
|
+
if io_ref is None:
|
|
916
|
+
xip, io_ref = __create_io__(file_name=default_asset_title, parent_folder=parent_folder, **kwargs)
|
|
918
917
|
|
|
919
918
|
if has_access_files:
|
|
920
919
|
if default_asset_title is None:
|
|
921
920
|
default_asset_title = os.path.splitext(os.path.basename(access_files_list[0]))[0]
|
|
922
|
-
|
|
923
921
|
if io_ref is None:
|
|
924
922
|
xip, io_ref = __create_io__(file_name=default_asset_title, parent_folder=parent_folder, **kwargs)
|
|
925
923
|
|
|
924
|
+
if io_ref is None:
|
|
925
|
+
default_asset_title = kwargs.get('Title', None)
|
|
926
|
+
if default_asset_title is None:
|
|
927
|
+
default_asset_title = "New Asset"
|
|
928
|
+
xip, io_ref = __create_io__(file_name=default_asset_title, parent_folder=parent_folder, **kwargs)
|
|
929
|
+
|
|
926
930
|
if has_preservation_files:
|
|
927
931
|
# add the content objects
|
|
928
932
|
representation_name = kwargs.get('Preservation_Representation_Name', "Preservation")
|
|
@@ -1531,7 +1535,7 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1531
1535
|
"""
|
|
1532
1536
|
Ingest a web video such as YouTube etc based on the URL
|
|
1533
1537
|
|
|
1534
|
-
:param str url: URL to the
|
|
1538
|
+
:param str url: URL to the YouTube video
|
|
1535
1539
|
:param Folder parent_folder: The folder to ingest the video into
|
|
1536
1540
|
:param str Title: Optional asset title
|
|
1537
1541
|
:param str Description: Optional asset description
|
|
@@ -1936,18 +1940,18 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1936
1940
|
|
|
1937
1941
|
|
|
1938
1942
|
retries= {
|
|
1939
|
-
'max_attempts':
|
|
1943
|
+
'max_attempts': 5,
|
|
1940
1944
|
'mode': 'adaptive'
|
|
1941
1945
|
}
|
|
1942
1946
|
|
|
1943
1947
|
def new_credentials():
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1948
|
+
cred_metadata: dict = {}
|
|
1949
|
+
cred_metadata['access_key'] = self.__token__()
|
|
1950
|
+
cred_metadata['secret_key'] = "NOT_USED"
|
|
1951
|
+
cred_metadata['token'] = ""
|
|
1952
|
+
cred_metadata["expiry_time"] = (datetime.now(tzlocal()) + timedelta(minutes=12)).isoformat()
|
|
1949
1953
|
logger.info("Refreshing credentials at: " + str(datetime.now(tzlocal())))
|
|
1950
|
-
return
|
|
1954
|
+
return cred_metadata
|
|
1951
1955
|
|
|
1952
1956
|
session = get_session()
|
|
1953
1957
|
|
|
@@ -1963,9 +1967,13 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1963
1967
|
|
|
1964
1968
|
session._credentials = session_credentials
|
|
1965
1969
|
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1970
|
+
config = Config(s3={'addressing_style': 'path'}, read_timeout=120, connect_timeout=120,
|
|
1971
|
+
request_checksum_calculation="WHEN_REQUIRED",
|
|
1972
|
+
response_checksum_validation="WHEN_REQUIRED",
|
|
1973
|
+
retries=retries, tcp_keepalive=True)
|
|
1974
|
+
|
|
1975
|
+
|
|
1976
|
+
s3_client = autorefresh_session.client('s3', endpoint_url=endpoint, config=config)
|
|
1969
1977
|
|
|
1970
1978
|
metadata = {}
|
|
1971
1979
|
if folder is not None:
|
pyPreservica/webHooksAPI.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pyPreservica
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: Python library for the Preservica API
|
|
5
5
|
Home-page: https://pypreservica.readthedocs.io/
|
|
6
6
|
Author: James Carr
|
|
@@ -16,7 +16,6 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
20
19
|
Classifier: Operating System :: OS Independent
|
|
21
20
|
Classifier: Topic :: System :: Archiving
|
|
22
21
|
Description-Content-Type: text/markdown
|
|
@@ -24,12 +23,13 @@ License-File: LICENSE.txt
|
|
|
24
23
|
Requires-Dist: requests
|
|
25
24
|
Requires-Dist: urllib3
|
|
26
25
|
Requires-Dist: certifi
|
|
27
|
-
Requires-Dist: boto3
|
|
26
|
+
Requires-Dist: boto3
|
|
28
27
|
Requires-Dist: botocore
|
|
29
28
|
Requires-Dist: s3transfer
|
|
30
29
|
Requires-Dist: azure-storage-blob
|
|
31
30
|
Requires-Dist: tqdm
|
|
32
31
|
Requires-Dist: pyotp
|
|
32
|
+
Requires-Dist: python-dateutil
|
|
33
33
|
Dynamic: author
|
|
34
34
|
Dynamic: author-email
|
|
35
35
|
Dynamic: classifier
|
|
@@ -38,6 +38,7 @@ Dynamic: description-content-type
|
|
|
38
38
|
Dynamic: home-page
|
|
39
39
|
Dynamic: keywords
|
|
40
40
|
Dynamic: license
|
|
41
|
+
Dynamic: license-file
|
|
41
42
|
Dynamic: project-url
|
|
42
43
|
Dynamic: requires-dist
|
|
43
44
|
Dynamic: summary
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
pyPreservica/__init__.py,sha256=A3EpVn5oHQJjia8sh7D3Pzk6GlNPgrlpRL0VnDZn1f8,1212
|
|
2
|
+
pyPreservica/adminAPI.py,sha256=aMN2twcUZOFoGx2yapC6GVtBTdYHUJFA-5bdWVkCwS8,37773
|
|
3
|
+
pyPreservica/authorityAPI.py,sha256=jpf_m9i-IakyNVooi2yELuKt4yhX73hWqQNbPRHZx2g,9206
|
|
4
|
+
pyPreservica/common.py,sha256=iEeF4Kg51d4Vug-Dv8TeqS1lP2zcfM7YtBO8oANEcCU,38273
|
|
5
|
+
pyPreservica/contentAPI.py,sha256=nOj7WciYARhLQWW65215Ghwz3CG61AVvikETPdtN4r0,22174
|
|
6
|
+
pyPreservica/entityAPI.py,sha256=p0u2OoLWOg1UxGq7ZRU__bz99FS5_nXW7wENufMgKNI,123919
|
|
7
|
+
pyPreservica/mdformsAPI.py,sha256=_hBjT4-OzgLQGDfYX7b_01P27wc-RmsCEu57VtyAdh8,19173
|
|
8
|
+
pyPreservica/monitorAPI.py,sha256=LJOUrynBOWKlNiYpZ1iH8qB1oIIuKX1Ms1SRBcuXohA,6274
|
|
9
|
+
pyPreservica/opex.py,sha256=ccra1S4ojUXS3PlbU8WfxajOkJrwG4OykBnNrYP_jus,4875
|
|
10
|
+
pyPreservica/parAPI.py,sha256=f0ZUxLd0U-BW6kBx5K7W2Pv7NjG3MkTNydmxQ3U1ZVE,9296
|
|
11
|
+
pyPreservica/retentionAPI.py,sha256=QUTCbN4P3IpqmrebU_wd3n5ZVcyxVLTFAli8Y_GxOW4,24843
|
|
12
|
+
pyPreservica/uploadAPI.py,sha256=uX67mW-2q7FmjtXQ759GwHPL6Zs7R-iE8-86PBApvbY,99823
|
|
13
|
+
pyPreservica/webHooksAPI.py,sha256=B3C6PV_3JLlJrr9PtsTzL-21M0msx8Mnj18Xb3Bv4RE,6814
|
|
14
|
+
pyPreservica/workflowAPI.py,sha256=OcOiiUdrQerbPllrkj1lWpmuW0jTuyyV0urwPSYcd_U,17561
|
|
15
|
+
pypreservica-3.1.1.dist-info/licenses/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
16
|
+
pypreservica-3.1.1.dist-info/METADATA,sha256=fWV7Yk9RUUDKhAGYJnkpf27fjbzwqFjqYN4NdB5-ZWI,3009
|
|
17
|
+
pypreservica-3.1.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
18
|
+
pypreservica-3.1.1.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
|
|
19
|
+
pypreservica-3.1.1.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
pyPreservica/__init__.py,sha256=d5_ol6jTBuUxdJrWZUCoaS7jqw4C-o4uX94c5FrF7Ag,1177
|
|
2
|
-
pyPreservica/adminAPI.py,sha256=511bc5KtrCAXbDyBk39dmDnxUVDaOu6xaiyu0jYhxa4,37781
|
|
3
|
-
pyPreservica/authorityAPI.py,sha256=Eule8g6LXr8c8SFcJgpRah4lH1FgevUItO5HhHDEaZE,9172
|
|
4
|
-
pyPreservica/common.py,sha256=nZeUObfypPXFauag5yYXEutvRC72sNXwVCN0wAFnssg,37796
|
|
5
|
-
pyPreservica/contentAPI.py,sha256=z_IwndqzpTMtsDKUgneqWec5YPhi2Yb110Z-4tC42qU,22182
|
|
6
|
-
pyPreservica/entityAPI.py,sha256=9BU55nvohydmwE4E3EviAkBrUcIj5ahmHQg2kLYZ8oY,121101
|
|
7
|
-
pyPreservica/mdformsAPI.py,sha256=cTHxHgPV-EZAFN6C1JfnxrVNv3FLzqI1SV_fb5ZOxeE,19196
|
|
8
|
-
pyPreservica/monitorAPI.py,sha256=HD-PUPdSI9wGAa07e2_2_-FLINH8PoWUwpFogz7F-j4,6269
|
|
9
|
-
pyPreservica/opex.py,sha256=ccra1S4ojUXS3PlbU8WfxajOkJrwG4OykBnNrYP_jus,4875
|
|
10
|
-
pyPreservica/parAPI.py,sha256=f0ZUxLd0U-BW6kBx5K7W2Pv7NjG3MkTNydmxQ3U1ZVE,9296
|
|
11
|
-
pyPreservica/retentionAPI.py,sha256=F6okFSyqtnLhfMbcyChd_5V-D_PAxNLwyx8XohH2DEM,24840
|
|
12
|
-
pyPreservica/uploadAPI.py,sha256=j7BnJ3tJZhXOIrAyvalAoAXWPgpQLfNVfoz89kO7D_Q,99367
|
|
13
|
-
pyPreservica/webHooksAPI.py,sha256=_K3KUOsmwYf8qMa-mD47sAmNUW7Pzb9oKVpS0VoSbC0,6827
|
|
14
|
-
pyPreservica/workflowAPI.py,sha256=OcOiiUdrQerbPllrkj1lWpmuW0jTuyyV0urwPSYcd_U,17561
|
|
15
|
-
pyPreservica-3.0.5.dist-info/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
16
|
-
pyPreservica-3.0.5.dist-info/METADATA,sha256=HSictV4AVTAsXV0nXT9PAOjyaAb-EQ4hUSIGPDBWCKc,3025
|
|
17
|
-
pyPreservica-3.0.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
18
|
-
pyPreservica-3.0.5.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
|
|
19
|
-
pyPreservica-3.0.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|