pyPreservica 2.7.4__py3-none-any.whl → 2.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyPreservica/__init__.py CHANGED
@@ -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 MDFormsAPI
21
+ from .mdformsAPI import MetadataGroupsAPI, GroupFieldType, GroupField, Group
22
22
 
23
23
  __author__ = "James Carr (drjamescarr@gmail.com)"
24
24
 
25
25
  # Version of the pyPreservica package
26
- __version__ = "2.7.4"
26
+ __version__ = "2.8.1"
27
27
 
28
28
  __license__ = "Apache License Version 2.0"
@@ -8,14 +8,129 @@ author: James Carr
8
8
  licence: Apache License 2.0
9
9
 
10
10
  """
11
- import json
12
11
  import xml.etree.ElementTree
13
- from typing import Callable
12
+ from enum import StrEnum
13
+ from typing import Callable, List, Union, Generator
14
14
 
15
15
  from pyPreservica.common import *
16
16
 
17
17
 
18
- class MDFormsAPI(AuthenticatedAPI):
18
+ class GroupFieldType(StrEnum):
19
+ STRING = "STRING"
20
+ LONG_STRING = "LONGSTRING"
21
+ DATE = "DATE"
22
+ NUMBER = "NUMBER"
23
+
24
+
25
+ class GroupField:
26
+ field_id: str
27
+ name: str
28
+ field_type: GroupFieldType
29
+ maxLength: int
30
+ default: str
31
+ visible: bool
32
+ editable: bool
33
+ minOccurs: int
34
+ maxOccurs: int
35
+ values: List[str]
36
+ indexed: bool
37
+
38
+ def __init__(self, field_id: str, name: str, field_type: GroupFieldType = GroupFieldType.STRING,
39
+ maxLength: int = -1, default: str = "", visible: bool = True, editable: bool = True,
40
+ minOccurs: int = 0, maxOccurs: int = 1, indexed: bool = True, values: List = None):
41
+ self.field_id = field_id
42
+ self.name = name
43
+ self.field_type = field_type
44
+ self.maxLength = maxLength
45
+ self.default = default
46
+ self.visible = visible
47
+ self.editable = editable
48
+ self.minOccurs = minOccurs
49
+ self.maxOccurs = maxOccurs
50
+ self.values = values
51
+ self.indexed = indexed
52
+
53
+ def __str__(self):
54
+ return (f"Field ID: {self.field_id}\n" + f"Field Name: {self.name}\n" + f"Field Type: {self.field_type}\n" +
55
+ f"Field Visible: {self.visible}\n" + f"Field Editable: {self.editable}\n")
56
+
57
+
58
+ class Group:
59
+ group_id: str
60
+ name: str
61
+ description: str
62
+ schemaUri: str
63
+ fields: List[GroupField] = []
64
+
65
+ def __init__(self, name: str, description: str):
66
+ self.name = name
67
+ self.description = description
68
+
69
+ def __str__(self):
70
+ return (f"Group ID: {self.group_id}\n" + f"Group Name: {self.name}\n" +
71
+ f"Group Description: {self.description}\n" + f"Group Schema URI: {self.schemaUri}")
72
+
73
+
74
+ def _object_from_json_(json_doc: dict) -> Group:
75
+ """
76
+ Create a JSON dict object from a Group object
77
+ """
78
+
79
+ group: Group = Group(name=json_doc['name'], description=json_doc['description'])
80
+ group.fields = []
81
+ if 'id' in json_doc:
82
+ group.group_id = json_doc['id']
83
+ if 'schemaUri' in json_doc:
84
+ group.schemaUri = json_doc['schemaUri']
85
+
86
+ if 'fields' in json_doc:
87
+ for field in json_doc['fields']:
88
+ gf: GroupField = GroupField(field['id'], field['name'], GroupFieldType(str(field['type'])))
89
+ if 'minOccurs' in field:
90
+ gf.minOccurs = int(field['minOccurs'])
91
+ if 'maxOccurs' in field:
92
+ gf.maxOccurs = int(field['maxOccurs'])
93
+ if 'visible' in field:
94
+ gf.visible = bool(field['visible'])
95
+ if 'editable' in field:
96
+ gf.editable = bool(field['editable'])
97
+ if 'values' in field:
98
+ for v in field['values']:
99
+ gf.values.append(str(v))
100
+ if 'defaultValue' in field:
101
+ gf.default = str(field['defaultValue'])
102
+ if 'indexed' in field:
103
+ gf.indexed = bool(field['indexed'])
104
+
105
+ group.fields.append(gf)
106
+
107
+ return group
108
+
109
+
110
+ def _json_from_object_(group: Group) -> dict:
111
+ """
112
+ Create a JSON dict object from a Group object
113
+ """
114
+
115
+ fields = []
116
+ for field in group.fields:
117
+ f = {"id": field.field_id, "name": field.name, "type": str(field.field_type)}
118
+ f["minOccurs"] = str(field.minOccurs)
119
+ f["maxOccurs"] = str(field.maxOccurs)
120
+ f["visible"] = str(field.visible)
121
+ f["editable"] = str(field.editable)
122
+ if (field.values is not None) and (len(field.values) > 0):
123
+ f["values"] = [item for item in field.values]
124
+ f["defaultValue"] = str(field.default)
125
+ f["indexed"] = str(field.indexed)
126
+ fields.append(f)
127
+
128
+ json_doc = {"name": group.name, "description": group.description, "fields": fields}
129
+
130
+ return json_doc
131
+
132
+
133
+ class MetadataGroupsAPI(AuthenticatedAPI):
19
134
  def __init__(self, username: str = None, password: str = None, tenant: str = None, server: str = None,
20
135
  use_shared_secret: bool = False, two_fa_secret_key: str = None,
21
136
  protocol: str = "https", request_hook: Callable = None):
@@ -26,18 +141,38 @@ class MDFormsAPI(AuthenticatedAPI):
26
141
  xml.etree.ElementTree.register_namespace("oai_dc", "http://www.openarchives.org/OAI/2.0/oai_dc/")
27
142
  xml.etree.ElementTree.register_namespace("ead", "urn:isbn:1-931666-22-9")
28
143
 
29
- def delete_group(self, id: str):
144
+ def delete_group_namespace(self, schema: str):
30
145
  """
31
- Delete a group
32
- :param id: Group ID
33
- :return:
146
+ Delete a new Metadata Group using its schema URI
147
+
148
+ :param schema: The Group namespace schema URI
149
+ :type schema: str
150
+
151
+ :return: None
152
+ :rtype: None
153
+
154
+ """
155
+ for group in self.groups():
156
+ if group.schemaUri == schema:
157
+ self.delete_group(group.group_id)
158
+
159
+ def delete_group(self, group_id: str):
34
160
  """
161
+ Delete a new Metadata Group using its ID
162
+
163
+ :param group_id: Group ID
164
+ :type group_id: str
165
+
166
+ :return:
167
+ :rtype: None
168
+
169
+ """
35
170
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
36
- url = f'{self.protocol}://{self.server}/api/metadata/groups/{id}'
171
+ url = f'{self.protocol}://{self.server}/api/metadata/groups/{group_id}'
37
172
  with self.session.delete(url, headers=headers) as request:
38
173
  if request.status_code == requests.codes.unauthorized:
39
174
  self.token = self.__token__()
40
- return self.delete_group(id)
175
+ return self.delete_group(group_id)
41
176
  elif request.status_code == requests.codes.no_content:
42
177
  return None
43
178
  else:
@@ -46,60 +181,182 @@ class MDFormsAPI(AuthenticatedAPI):
46
181
  logger.error(exception)
47
182
  raise exception
48
183
 
49
- def add_group(self, document):
184
+ def add_fields(self, group_id: str, new_fields: List[GroupField]) -> dict:
50
185
  """
51
- Add a new group
52
- :return:
186
+ Add new metadata fields to an existing Group
187
+
188
+ The new fields are appended to the end of the group
189
+
190
+ :param group_id: The group ID of the group to update
191
+ :type group_id: str
192
+
193
+ :param new_fields: The list of new fields to add to the group
194
+ :type new_fields: List[GroupField]
195
+
196
+ :return: The updated Metadata Group as a JSON dict
197
+ :rtype: dict
198
+
199
+
53
200
  """
201
+
202
+ this_group: Group = self.group(group_id)
203
+
204
+ for field in new_fields:
205
+ this_group.fields.append(field)
206
+
207
+ doc = _json_from_object_(this_group)
208
+
54
209
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
55
- url = f'{self.protocol}://{self.server}/api/metadata/groups/'
56
- with self.session.post(url, headers=headers, json=document) as request:
210
+ url = f'{self.protocol}://{self.server}/api/metadata/groups/{group_id}'
211
+ with self.session.put(url, headers=headers, json=doc) as request:
57
212
  if request.status_code == requests.codes.unauthorized:
58
213
  self.token = self.__token__()
59
- return self.add_group(document)
214
+ return self.add_fields(group_id, new_fields)
60
215
  elif request.status_code == requests.codes.created:
61
216
  return json.loads(str(request.content.decode('utf-8')))
62
217
  else:
63
- exception = HTTPException(None, request.status_code, request.url, "group",
218
+ exception = HTTPException(None, request.status_code, request.url, "add_fields",
64
219
  request.content.decode('utf-8'))
65
220
  logger.error(exception)
66
221
  raise exception
67
222
 
68
- def group(self, id: str):
223
+ def add_group(self, group_name: str, group_description: str, fields: List[GroupField]) -> dict:
69
224
  """
70
- Fetch a metadata Group by its id
71
- :param id: The group ID
72
- :return: JSON Document
225
+ Create a new Metadata Group GroupFields
226
+
227
+ :param group_name: The name of the new Group
228
+ :type group_name: str
229
+
230
+ :param group_description: The description of the new Group
231
+ :type group_description: str
232
+
233
+ :param fields: The list of fields
234
+ :type fields: List[GroupField]
235
+
236
+ :return: The new metadata Group as a JSON dict
237
+ :rtype: dict
238
+
239
+ """
240
+
241
+ group: Group = Group(group_name, group_description)
242
+ group.fields = fields
243
+
244
+ json_document: dict = _json_from_object_(group)
245
+ json_response: dict = self.add_group_json(json_document)
246
+ return json_response
247
+
248
+ def add_group_json(self, json_object: Union[dict, str]) -> dict:
73
249
  """
250
+ Create a new Metadata Group using a JSON dictionary object or document
251
+
252
+ :param json_object: JSON dictionary or string
253
+ :type json_object: dict
254
+
255
+ :return: JSON document
256
+ :rtype: dict
257
+
258
+ """
74
259
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
75
- url = f'{self.protocol}://{self.server}/api/metadata/groups/{id}'
260
+ url = f'{self.protocol}://{self.server}/api/metadata/groups/'
261
+
262
+ if isinstance(json_object, dict):
263
+ with self.session.post(url, headers=headers, json=json_object) as request:
264
+ if request.status_code == requests.codes.unauthorized:
265
+ self.token = self.__token__()
266
+ return self.add_group_json(json_object)
267
+ elif request.status_code == requests.codes.created:
268
+ return json.loads(str(request.content.decode('utf-8')))
269
+ else:
270
+ exception = HTTPException(None, request.status_code, request.url, "add_group_json",
271
+ request.content.decode('utf-8'))
272
+ logger.error(exception)
273
+ raise exception
274
+
275
+ elif isinstance(json_object, str):
276
+ with self.session.post(url, headers=headers, data=json_object) as request:
277
+ if request.status_code == requests.codes.unauthorized:
278
+ self.token = self.__token__()
279
+ return self.add_group_json(json_object)
280
+ elif request.status_code == requests.codes.created:
281
+ return json.loads(str(request.content.decode('utf-8')))
282
+ else:
283
+ exception = HTTPException(None, request.status_code, request.url, "add_group_json",
284
+ request.content.decode('utf-8'))
285
+ logger.error(exception)
286
+ raise exception
287
+ else:
288
+ raise RuntimeError("Argument must be a JSON dictionary or a JSON str")
289
+
290
+ def group_json(self, group_id: str) -> dict:
291
+ """
292
+ Return a Group as a JSON object
293
+
294
+ :param group_id: The Group id
295
+ :type group_id: str
296
+
297
+ :return: JSON document
298
+ :rtype: dict
299
+
300
+ """
301
+ headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
302
+ url = f'{self.protocol}://{self.server}/api/metadata/groups/{group_id}'
76
303
  with self.session.get(url, headers=headers) as request:
77
304
  if request.status_code == requests.codes.unauthorized:
78
305
  self.token = self.__token__()
79
- return self.group(id)
306
+ return self.group_json(group_id)
80
307
  elif request.status_code == requests.codes.ok:
81
308
  return json.loads(str(request.content.decode('utf-8')))
82
309
  else:
83
- exception = HTTPException(None, request.status_code, request.url, "group",
310
+ exception = HTTPException(None, request.status_code, request.url, "group_json",
84
311
  request.content.decode('utf-8'))
85
312
  logger.error(exception)
86
313
  raise exception
87
314
 
88
- def groups(self):
315
+ def group(self, group_id: str) -> Group:
316
+ """
317
+ Return a Group object by its ID
318
+
319
+ :param group_id: The Group id
320
+ :type group_id: str
321
+
322
+ :return: The metadata Group Object
323
+ :rtype: Group
324
+
325
+ """
326
+
327
+ return _object_from_json_(self.group_json(group_id))
328
+
329
+ def groups_json(self) -> List[dict]:
89
330
  """
90
- Fetch all the Metadata Groups as JSON
91
- :return: JSON Document
331
+ Return all the metadata Groups in the tenancy as a list of JSON dict objects
332
+
333
+ :return: List of JSON dictionary object
334
+ :rtype: List[dict]
335
+
92
336
  """
337
+
93
338
  headers = {HEADER_TOKEN: self.token, 'Content-Type': 'application/json;charset=UTF-8'}
94
339
  url = f'{self.protocol}://{self.server}/api/metadata/groups'
95
340
  with self.session.get(url, headers=headers) as request:
96
341
  if request.status_code == requests.codes.unauthorized:
97
342
  self.token = self.__token__()
98
- return self.groups()
343
+ return self.groups_json()
99
344
  elif request.status_code == requests.codes.ok:
100
345
  return json.loads(str(request.content.decode('utf-8')))['groups']
101
346
  else:
102
- exception = HTTPException(None, request.status_code, request.url, "groups",
347
+ exception = HTTPException(None, request.status_code, request.url, "groups_json",
103
348
  request.content.decode('utf-8'))
104
349
  logger.error(exception)
105
350
  raise exception
351
+
352
+ def groups(self) -> Generator[Group, None, None]:
353
+ """
354
+ Return all the metadata Groups in the tenancy as Group Objects
355
+
356
+ :return: Generator of Group Objects
357
+ :rtype: Group
358
+
359
+ """
360
+
361
+ for group in self.groups_json():
362
+ yield _object_from_json_(group)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyPreservica
3
- Version: 2.7.4
3
+ Version: 2.8.1
4
4
  Summary: Python library for the Preservica API
5
5
  Home-page: https://pypreservica.readthedocs.io/
6
6
  Author: James Carr
@@ -1,10 +1,10 @@
1
- pyPreservica/__init__.py,sha256=RmOn1lvHV9iH7Hmz5YQ0F06ASdqetV0_-m1I8S4erqY,1117
1
+ pyPreservica/__init__.py,sha256=NiLSCAwOwFa5Io_lXzaK3kSb5ZpANS1g4h4MePtqCFs,1159
2
2
  pyPreservica/adminAPI.py,sha256=511bc5KtrCAXbDyBk39dmDnxUVDaOu6xaiyu0jYhxa4,37781
3
3
  pyPreservica/authorityAPI.py,sha256=Eule8g6LXr8c8SFcJgpRah4lH1FgevUItO5HhHDEaZE,9172
4
4
  pyPreservica/common.py,sha256=yZNMlq8aOOLSbFS2DDHYBUWyN5ojDjYUYmcePVbUd44,37636
5
5
  pyPreservica/contentAPI.py,sha256=F3VwaybSUel0OfhWOckqfM77AVQCD1erHbu-Xrv4cd0,17388
6
6
  pyPreservica/entityAPI.py,sha256=f-RlCEtUq0KDB62LuSPy0Kb-lT6Hp2gPOmSiTeomqkM,114853
7
- pyPreservica/mdformsAPI.py,sha256=As5YN5m1k59N6SpM8fLldVviJ0n4lhlZD8rV5v0Jehs,4698
7
+ pyPreservica/mdformsAPI.py,sha256=bpKh1Iun9OYQOW0u6w0r6FcPIhZ-z7DqWrNATvGwyas,13533
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=bgaQvYfWNnzdD7ibKMV3ZV85pNkEdSoLsgVigoiFFfw,10771
@@ -12,8 +12,8 @@ pyPreservica/retentionAPI.py,sha256=EmQvmUW_I_sPslCiTZDZ2uqloesjfxmmc5AQImWX2cs,
12
12
  pyPreservica/uploadAPI.py,sha256=Nl6Z4h1cW9TmZyrhVLPff3jSAnzCdkfn0xDJ9Q_ZhdI,96444
13
13
  pyPreservica/webHooksAPI.py,sha256=0wP-59mep8gtlIZ9P5vV68-HnNdTuuo2kzGcDWj0bNg,6790
14
14
  pyPreservica/workflowAPI.py,sha256=wDDR5_CsJ3dhX79E5mJaziAtgYb830J0ZpNJppzgvqk,17493
15
- pyPreservica-2.7.4.dist-info/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
16
- pyPreservica-2.7.4.dist-info/METADATA,sha256=bbipiUj1ByD22LxVh2X7a3ytTLitfSt9GVi_nKfVoXs,2784
17
- pyPreservica-2.7.4.dist-info/WHEEL,sha256=YiKiUUeZQGmGJoR_0N1Y933DOBowq4AIvDe2-UIy8E4,91
18
- pyPreservica-2.7.4.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
19
- pyPreservica-2.7.4.dist-info/RECORD,,
15
+ pyPreservica-2.8.1.dist-info/LICENSE.txt,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
16
+ pyPreservica-2.8.1.dist-info/METADATA,sha256=3Y8NHjy7Lpb2WLV40MUkv7IbhKrPnY9NYWv7Ok-RgBo,2784
17
+ pyPreservica-2.8.1.dist-info/WHEEL,sha256=YiKiUUeZQGmGJoR_0N1Y933DOBowq4AIvDe2-UIy8E4,91
18
+ pyPreservica-2.8.1.dist-info/top_level.txt,sha256=iIBh6NAznYQHOV8mv_y_kGKSDITek9rANyFDwJsbU-c,13
19
+ pyPreservica-2.8.1.dist-info/RECORD,,