pyPreservica 3.0.1__py3-none-any.whl → 3.0.5__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 +35 -13
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.5.dist-info}/METADATA +14 -3
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.5.dist-info}/RECORD +9 -9
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.5.dist-info}/WHEEL +1 -1
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.5.dist-info}/LICENSE.txt +0 -0
- {pyPreservica-3.0.1.dist-info → pyPreservica-3.0.5.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.5"
|
|
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
|
@@ -1661,30 +1661,52 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1661
1661
|
security_tag: str = "open",
|
|
1662
1662
|
delete_after_upload: bool = True, max_MB_ingested: int = -1):
|
|
1663
1663
|
|
|
1664
|
+
from pyPreservica import EntityAPI
|
|
1665
|
+
|
|
1666
|
+
def entity_value(client: EntityAPI, identifier: str) -> Entity:
|
|
1667
|
+
back_off: int = 5
|
|
1668
|
+
while True:
|
|
1669
|
+
try:
|
|
1670
|
+
entities = client.identifier("code", identifier)
|
|
1671
|
+
if bool(len(entities) > 0):
|
|
1672
|
+
return entities.pop()
|
|
1673
|
+
else:
|
|
1674
|
+
return None
|
|
1675
|
+
except HTTPException as e:
|
|
1676
|
+
sleep(back_off)
|
|
1677
|
+
back_off = back_off * 2
|
|
1678
|
+
|
|
1679
|
+
def entity_exists(client: EntityAPI, identifier: str) -> bool:
|
|
1680
|
+
back_off: int = 5
|
|
1681
|
+
while True:
|
|
1682
|
+
try:
|
|
1683
|
+
entities = client.identifier("code", identifier)
|
|
1684
|
+
return bool(len(entities) > 0)
|
|
1685
|
+
except HTTPException as e:
|
|
1686
|
+
sleep(back_off)
|
|
1687
|
+
back_off = back_off * 2
|
|
1688
|
+
|
|
1664
1689
|
def get_parent(client, identifier, parent_reference):
|
|
1665
|
-
|
|
1666
|
-
if not
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
if
|
|
1670
|
-
folder = entities.pop()
|
|
1690
|
+
dirname_id: str = str(os.path.dirname(identifier))
|
|
1691
|
+
if not dirname_id:
|
|
1692
|
+
dirname_id = identifier
|
|
1693
|
+
folder = entity_value(client, dirname_id)
|
|
1694
|
+
if folder is not None:
|
|
1671
1695
|
folder = client.folder(folder.reference)
|
|
1672
1696
|
return folder.reference
|
|
1673
1697
|
else:
|
|
1674
1698
|
return parent_reference
|
|
1675
1699
|
|
|
1676
1700
|
def get_folder(client, name, tag, parent_reference, identifier):
|
|
1677
|
-
|
|
1678
|
-
if
|
|
1701
|
+
folder = entity_value(client, identifier)
|
|
1702
|
+
if folder is None:
|
|
1679
1703
|
logger.info(f"Creating new folder with name {name}")
|
|
1680
1704
|
folder = client.create_folder(name, name, tag, parent_reference)
|
|
1681
1705
|
client.add_identifier(folder, "code", identifier)
|
|
1682
1706
|
else:
|
|
1683
1707
|
logger.info(f"Found existing folder with name {name}")
|
|
1684
|
-
folder = entities.pop()
|
|
1685
1708
|
return folder
|
|
1686
1709
|
|
|
1687
|
-
from pyPreservica import EntityAPI
|
|
1688
1710
|
entity_client = EntityAPI(username=self.username, password=self.password, server=self.server,
|
|
1689
1711
|
tenant=self.tenant,
|
|
1690
1712
|
two_fa_secret_key=self.two_fa_secret_key, use_shared_secret=self.shared_secret,
|
|
@@ -1714,7 +1736,7 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1714
1736
|
files.remove(file)
|
|
1715
1737
|
continue
|
|
1716
1738
|
asset_code = os.path.join(code, file)
|
|
1717
|
-
if
|
|
1739
|
+
if not entity_exists(entity_client, asset_code):
|
|
1718
1740
|
bytes_ingested = bytes_ingested + os.stat(full_path).st_size
|
|
1719
1741
|
logger.info(f"Adding new file: {file} to package ready for upload")
|
|
1720
1742
|
file_identifiers = {"code": asset_code}
|
|
@@ -1737,8 +1759,8 @@ class UploadAPI(AuthenticatedAPI):
|
|
|
1737
1759
|
delete_after_upload=delete_after_upload)
|
|
1738
1760
|
else:
|
|
1739
1761
|
self.upload_zip_to_Source(path_to_zip_package=package, container_name=bucket_name,
|
|
1740
|
-
|
|
1741
|
-
|
|
1762
|
+
show_progress=bool(progress_display is not None),
|
|
1763
|
+
delete_after_upload=delete_after_upload)
|
|
1742
1764
|
|
|
1743
1765
|
logger.info(f"Uploaded " + "{:.1f}".format(bytes_ingested / (1024 * 1024)) + " MB")
|
|
1744
1766
|
|
|
@@ -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.5
|
|
4
4
|
Summary: Python library for the Preservica API
|
|
5
5
|
Home-page: https://pypreservica.readthedocs.io/
|
|
6
6
|
Author: James Carr
|
|
@@ -24,12 +24,23 @@ License-File: LICENSE.txt
|
|
|
24
24
|
Requires-Dist: requests
|
|
25
25
|
Requires-Dist: urllib3
|
|
26
26
|
Requires-Dist: certifi
|
|
27
|
-
Requires-Dist: boto3
|
|
27
|
+
Requires-Dist: boto3<1.36.0
|
|
28
28
|
Requires-Dist: botocore
|
|
29
29
|
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=d5_ol6jTBuUxdJrWZUCoaS7jqw4C-o4uX94c5FrF7Ag,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=j7BnJ3tJZhXOIrAyvalAoAXWPgpQLfNVfoz89kO7D_Q,99367
|
|
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.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
|