pyPreservica 3.0.1__py3-none-any.whl → 3.0.2__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 +1 -1
- pyPreservica/common.py +3 -0
- pyPreservica/entityAPI.py +40 -4
- pyPreservica/uploadAPI.py +27 -2
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.2.dist-info}/METADATA +13 -2
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.2.dist-info}/RECORD +9 -9
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.2.dist-info}/WHEEL +1 -1
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.2.dist-info}/LICENSE.txt +0 -0
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.2.dist-info}/top_level.txt +0 -0
pyPreservica/__init__.py
CHANGED
|
@@ -23,6 +23,6 @@ from .mdformsAPI import MetadataGroupsAPI, Group, GroupField, GroupFieldType
|
|
|
23
23
|
__author__ = "James Carr (drjamescarr@gmail.com)"
|
|
24
24
|
|
|
25
25
|
# Version of the pyPreservica package
|
|
26
|
-
__version__ = "3.0.
|
|
26
|
+
__version__ = "3.0.2"
|
|
27
27
|
|
|
28
28
|
__license__ = "Apache License Version 2.0"
|
pyPreservica/common.py
CHANGED
pyPreservica/entityAPI.py
CHANGED
|
@@ -8,7 +8,7 @@ author: James Carr
|
|
|
8
8
|
licence: Apache License 2.0
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import os.path
|
|
13
13
|
import uuid
|
|
14
14
|
import xml.etree.ElementTree
|
|
@@ -118,6 +118,38 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
118
118
|
logger.error(exception)
|
|
119
119
|
raise exception
|
|
120
120
|
|
|
121
|
+
def bitstream_location(self, bitstream: Bitstream):
|
|
122
|
+
""""
|
|
123
|
+
Retrieves information about a bitstreams storage locations
|
|
124
|
+
"""
|
|
125
|
+
if not isinstance(bitstream, Bitstream):
|
|
126
|
+
logger.error("bitstream argument is not a Bitstream object")
|
|
127
|
+
raise RuntimeError("bitstream argument is not a Bitstream object")
|
|
128
|
+
|
|
129
|
+
storage_locations = []
|
|
130
|
+
|
|
131
|
+
url: str = f'{self.protocol}://{self.server}/api/entity/content-objects/{bitstream.co_ref}/generations/{bitstream.gen_index}/bitstreams/{bitstream.bs_index}/storage-locations'
|
|
132
|
+
|
|
133
|
+
with self.session.get(url, headers={HEADER_TOKEN: self.token}, stream=True) as request:
|
|
134
|
+
if request.status_code == requests.codes.unauthorized:
|
|
135
|
+
self.token = self.__token__()
|
|
136
|
+
return self.bitstream_location(bitstream)
|
|
137
|
+
elif request.status_code == requests.codes.ok:
|
|
138
|
+
xml_response = str(request.content.decode('utf-8'))
|
|
139
|
+
entity_response = xml.etree.ElementTree.fromstring(xml_response)
|
|
140
|
+
logger.debug(xml_response)
|
|
141
|
+
locations = entity_response.find(f'.//{{{self.entity_ns}}}StorageLocation')
|
|
142
|
+
for adapter in locations:
|
|
143
|
+
storage_locations.append(adapter.attrib['name'])
|
|
144
|
+
else:
|
|
145
|
+
exception = HTTPException(bitstream.filename, request.status_code, request.url, "bitstream_location",
|
|
146
|
+
request.content.decode('utf-8'))
|
|
147
|
+
logger.error(exception)
|
|
148
|
+
raise exception
|
|
149
|
+
|
|
150
|
+
return storage_locations
|
|
151
|
+
|
|
152
|
+
|
|
121
153
|
def bitstream_content(self, bitstream: Bitstream, filename: str, chunk_size: int = CHUNK_SIZE) -> Union[int, None]:
|
|
122
154
|
"""
|
|
123
155
|
Download a file represented as a Bitstream to a local filename
|
|
@@ -1474,7 +1506,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1474
1506
|
logger.error(exception)
|
|
1475
1507
|
raise exception
|
|
1476
1508
|
|
|
1477
|
-
def generation(self, url: str) -> Generation:
|
|
1509
|
+
def generation(self, url: str, content_ref: str = None) -> Generation:
|
|
1478
1510
|
"""
|
|
1479
1511
|
Retrieve a list of generation objects
|
|
1480
1512
|
|
|
@@ -1524,7 +1556,11 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1524
1556
|
bitstreams = entity_response.findall(f'./{{{self.entity_ns}}}Bitstreams/{{{self.entity_ns}}}Bitstream')
|
|
1525
1557
|
bitstream_list = []
|
|
1526
1558
|
for bit in bitstreams:
|
|
1527
|
-
|
|
1559
|
+
bs: Bitstream = self.bitstream(bit.text)
|
|
1560
|
+
bs.gen_index = index
|
|
1561
|
+
if content_ref is not None:
|
|
1562
|
+
bs.co_ref = content_ref
|
|
1563
|
+
bitstream_list.append(bs)
|
|
1528
1564
|
generation = Generation(strtobool(ge.attrib['original']), strtobool(ge.attrib['active']),
|
|
1529
1565
|
format_group.text if hasattr(format_group, 'text') else None,
|
|
1530
1566
|
effective_date.text if hasattr(effective_date, 'text') else None,
|
|
@@ -1741,7 +1777,7 @@ class EntityAPI(AuthenticatedAPI):
|
|
|
1741
1777
|
result = []
|
|
1742
1778
|
for g in generations:
|
|
1743
1779
|
if hasattr(g, 'text'):
|
|
1744
|
-
generation = self.generation(g.text)
|
|
1780
|
+
generation = self.generation(g.text, content_object.reference)
|
|
1745
1781
|
generation.asset = content_object.asset
|
|
1746
1782
|
generation.content_object = content_object
|
|
1747
1783
|
generation.representation_type = content_object.representation_type
|
pyPreservica/uploadAPI.py
CHANGED
|
@@ -1659,7 +1659,22 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1659
1659
|
|
|
1660
1660
|
def crawl_filesystem(self, filesystem_path, bucket_name, preservica_parent, callback: bool = False,
|
|
1661
1661
|
security_tag: str = "open",
|
|
1662
|
-
delete_after_upload: bool = True, max_MB_ingested: int = -1):
|
|
1662
|
+
delete_after_upload: bool = True, max_MB_ingested: int = -1, max_workflows = 8):
|
|
1663
|
+
"""
|
|
1664
|
+
Crawl a filesystem and upload the contents to Preservica, the filesystem structure is mirrored in Preservica
|
|
1665
|
+
|
|
1666
|
+
|
|
1667
|
+
:param str filesystem_path: The path to the filesystem to crawl
|
|
1668
|
+
:param str bucket_name: The name of the bucket to upload to, use None to send directly to Preservica
|
|
1669
|
+
:param str preservica_parent: The parent folder in Preservica to upload to
|
|
1670
|
+
:param bool callback: Show upload progress bar
|
|
1671
|
+
:param str security_tag: The security tag to apply to the uploaded assets
|
|
1672
|
+
:param bool delete_after_upload: Delete the local copy of the package after the upload has completed
|
|
1673
|
+
:param int max_MB_ingested: The maximum number of MB to ingest
|
|
1674
|
+
:param int max_workflows: The maximum number of workflows to run concurrently
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
"""
|
|
1663
1678
|
|
|
1664
1679
|
def get_parent(client, identifier, parent_reference):
|
|
1665
1680
|
id = str(os.path.dirname(identifier))
|
|
@@ -1684,12 +1699,17 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1684
1699
|
folder = entities.pop()
|
|
1685
1700
|
return folder
|
|
1686
1701
|
|
|
1687
|
-
from pyPreservica import EntityAPI
|
|
1702
|
+
from pyPreservica import EntityAPI, WorkflowAPI
|
|
1688
1703
|
entity_client = EntityAPI(username=self.username, password=self.password, server=self.server,
|
|
1689
1704
|
tenant=self.tenant,
|
|
1690
1705
|
two_fa_secret_key=self.two_fa_secret_key, use_shared_secret=self.shared_secret,
|
|
1691
1706
|
protocol=self.protocol)
|
|
1692
1707
|
|
|
1708
|
+
workflow_client = WorkflowAPI(username=self.username, password=self.password, server=self.server,
|
|
1709
|
+
tenant=self.tenant,
|
|
1710
|
+
two_fa_secret_key=self.two_fa_secret_key, use_shared_secret=self.shared_secret,
|
|
1711
|
+
protocol=self.protocol)
|
|
1712
|
+
|
|
1693
1713
|
if preservica_parent:
|
|
1694
1714
|
parent = entity_client.folder(preservica_parent)
|
|
1695
1715
|
logger.info(f"Folders will be created inside Preservica collection {parent.title}")
|
|
@@ -1732,6 +1752,11 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1732
1752
|
else:
|
|
1733
1753
|
progress_display = None
|
|
1734
1754
|
|
|
1755
|
+
workflow_queue_length = len(list(workflow_client.workflow_instances(workflow_state="Active", workflow_type="Ingest")))
|
|
1756
|
+
while workflow_queue_length > max_workflows:
|
|
1757
|
+
sleep(30)
|
|
1758
|
+
workflow_queue_length = len(list(workflow_client.workflow_instances(workflow_state="Active", workflow_type="Ingest")))
|
|
1759
|
+
|
|
1735
1760
|
if bucket_name is None:
|
|
1736
1761
|
self.upload_zip_package(path_to_zip_package=package, callback=progress_display,
|
|
1737
1762
|
delete_after_upload=delete_after_upload)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: pyPreservica
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.2
|
|
4
4
|
Summary: Python library for the Preservica API
|
|
5
5
|
Home-page: https://pypreservica.readthedocs.io/
|
|
6
6
|
Author: James Carr
|
|
@@ -30,6 +30,17 @@ Requires-Dist: s3transfer
|
|
|
30
30
|
Requires-Dist: azure-storage-blob
|
|
31
31
|
Requires-Dist: tqdm
|
|
32
32
|
Requires-Dist: pyotp
|
|
33
|
+
Dynamic: author
|
|
34
|
+
Dynamic: author-email
|
|
35
|
+
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
37
|
+
Dynamic: description-content-type
|
|
38
|
+
Dynamic: home-page
|
|
39
|
+
Dynamic: keywords
|
|
40
|
+
Dynamic: license
|
|
41
|
+
Dynamic: project-url
|
|
42
|
+
Dynamic: requires-dist
|
|
43
|
+
Dynamic: summary
|
|
33
44
|
|
|
34
45
|
|
|
35
46
|
# pyPreservica
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
pyPreservica/__init__.py,sha256=
|
|
1
|
+
pyPreservica/__init__.py,sha256=HkIx9xYPB52tEV5TP_tH6MFW57o7yDtmSOU9DXOPW8o,1177
|
|
2
2
|
pyPreservica/adminAPI.py,sha256=511bc5KtrCAXbDyBk39dmDnxUVDaOu6xaiyu0jYhxa4,37781
|
|
3
3
|
pyPreservica/authorityAPI.py,sha256=Eule8g6LXr8c8SFcJgpRah4lH1FgevUItO5HhHDEaZE,9172
|
|
4
|
-
pyPreservica/common.py,sha256=
|
|
4
|
+
pyPreservica/common.py,sha256=nZeUObfypPXFauag5yYXEutvRC72sNXwVCN0wAFnssg,37796
|
|
5
5
|
pyPreservica/contentAPI.py,sha256=z_IwndqzpTMtsDKUgneqWec5YPhi2Yb110Z-4tC42qU,22182
|
|
6
|
-
pyPreservica/entityAPI.py,sha256=
|
|
6
|
+
pyPreservica/entityAPI.py,sha256=9BU55nvohydmwE4E3EviAkBrUcIj5ahmHQg2kLYZ8oY,121101
|
|
7
7
|
pyPreservica/mdformsAPI.py,sha256=cTHxHgPV-EZAFN6C1JfnxrVNv3FLzqI1SV_fb5ZOxeE,19196
|
|
8
8
|
pyPreservica/monitorAPI.py,sha256=HD-PUPdSI9wGAa07e2_2_-FLINH8PoWUwpFogz7F-j4,6269
|
|
9
9
|
pyPreservica/opex.py,sha256=ccra1S4ojUXS3PlbU8WfxajOkJrwG4OykBnNrYP_jus,4875
|
|
10
10
|
pyPreservica/parAPI.py,sha256=f0ZUxLd0U-BW6kBx5K7W2Pv7NjG3MkTNydmxQ3U1ZVE,9296
|
|
11
11
|
pyPreservica/retentionAPI.py,sha256=F6okFSyqtnLhfMbcyChd_5V-D_PAxNLwyx8XohH2DEM,24840
|
|
12
|
-
pyPreservica/uploadAPI.py,sha256=
|
|
12
|
+
pyPreservica/uploadAPI.py,sha256=_ldYoDWD6cOIlMXM98KTF2Xnc7GaZ8SKZNHPzbJyfQI,100105
|
|
13
13
|
pyPreservica/webHooksAPI.py,sha256=_K3KUOsmwYf8qMa-mD47sAmNUW7Pzb9oKVpS0VoSbC0,6827
|
|
14
14
|
pyPreservica/workflowAPI.py,sha256=OcOiiUdrQerbPllrkj1lWpmuW0jTuyyV0urwPSYcd_U,17561
|
|
15
|
-
pyPreservica-3.0.
|
|
16
|
-
pyPreservica-3.0.
|
|
17
|
-
pyPreservica-3.0.
|
|
18
|
-
pyPreservica-3.0.
|
|
19
|
-
pyPreservica-3.0.
|
|
15
|
+
pyPreservica-3.0.2.dist-info/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
16
|
+
pyPreservica-3.0.2.dist-info/METADATA,sha256=aPMxioiNMabjITQ0OR-5cSUsk6VgNqSwfsg1QizXVNM,3018
|
|
17
|
+
pyPreservica-3.0.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
18
|
+
pyPreservica-3.0.2.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
|
|
19
|
+
pyPreservica-3.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|