pyPreservica 2.9.0__tar.gz → 2.9.1__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.9.0 → pypreservica-2.9.1}/PKG-INFO +1 -1
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/__init__.py +2 -2
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/contentAPI.py +105 -1
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica.egg-info/PKG-INFO +1 -1
- {pypreservica-2.9.0 → pypreservica-2.9.1}/setup.py +1 -1
- {pypreservica-2.9.0 → pypreservica-2.9.1}/LICENSE.txt +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/README.md +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/adminAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/authorityAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/common.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/entityAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/mdformsAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/monitorAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/opex.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/parAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/retentionAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/uploadAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/webHooksAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica/workflowAPI.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica.egg-info/SOURCES.txt +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica.egg-info/dependency_links.txt +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica.egg-info/requires.txt +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/pyPreservica.egg-info/top_level.txt +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/setup.cfg +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_authority_records.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_bitstream.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_children.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_content_api.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_crawl_fs.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_delete.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_download.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_entity.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_export_opex.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_groups.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_identifier.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_ingest.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_integrity_check.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_metadata.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_par.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_replace.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_retention.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_schema.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_security.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_thumbnail.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_upload.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_users.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_workflow.py +0 -0
- {pypreservica-2.9.0 → pypreservica-2.9.1}/tests/test_xml_metadata.py +0 -0
|
@@ -7,7 +7,7 @@ licence: Apache License 2.0
|
|
|
7
7
|
|
|
8
8
|
"""
|
|
9
9
|
from .common import *
|
|
10
|
-
from .contentAPI import ContentAPI
|
|
10
|
+
from .contentAPI import ContentAPI, Field, SortOrder
|
|
11
11
|
from .entityAPI import EntityAPI
|
|
12
12
|
from .uploadAPI import UploadAPI, simple_asset_package, complex_asset_package, cvs_to_xsd, cvs_to_xml, \
|
|
13
13
|
cvs_to_cmis_xslt, csv_to_search_xml, generic_asset_package, upload_config, multi_asset_package
|
|
@@ -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__ = "2.9.
|
|
26
|
+
__version__ = "2.9.1"
|
|
27
27
|
|
|
28
28
|
__license__ = "Apache License Version 2.0"
|
|
@@ -10,11 +10,28 @@ licence: Apache License 2.0
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import csv
|
|
13
|
-
from typing import Generator, Callable
|
|
13
|
+
from typing import Generator, Callable, Optional
|
|
14
14
|
from pyPreservica.common import *
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
|
+
class SortOrder(Enum):
|
|
19
|
+
asc = 1
|
|
20
|
+
desc = 2
|
|
21
|
+
|
|
22
|
+
class Field:
|
|
23
|
+
name: str
|
|
24
|
+
value: Optional[str]
|
|
25
|
+
operator: Optional[str]
|
|
26
|
+
sort_order: Optional[SortOrder]
|
|
27
|
+
|
|
28
|
+
def __init__(self, name: str, value: str, operator: Optional[str]=None, sort_order: Optional[SortOrder]=None):
|
|
29
|
+
self.name = name
|
|
30
|
+
self.value = value
|
|
31
|
+
self.operator = operator
|
|
32
|
+
self.sort_order = sort_order
|
|
33
|
+
|
|
34
|
+
|
|
18
35
|
|
|
19
36
|
class ContentAPI(AuthenticatedAPI):
|
|
20
37
|
|
|
@@ -212,6 +229,93 @@ class ContentAPI(AuthenticatedAPI):
|
|
|
212
229
|
writer.writeheader()
|
|
213
230
|
writer.writerows(self.search_index_filter_list(query, page_size, filter_values, sort_values))
|
|
214
231
|
|
|
232
|
+
def search_fields(self, query: str = "%", fields: list[Field]=None, page_size: int = 25) -> Generator:
|
|
233
|
+
"""
|
|
234
|
+
Run a search query with multiple fields
|
|
235
|
+
|
|
236
|
+
:param query: The main search query.
|
|
237
|
+
:param fields: List of search fields
|
|
238
|
+
:param page_size: The default search page size
|
|
239
|
+
:return: search result
|
|
240
|
+
"""
|
|
241
|
+
search_result = self._search_fields(query=query, fields=fields, start_index=0, page_size=page_size)
|
|
242
|
+
for e in search_result.results_list:
|
|
243
|
+
yield e
|
|
244
|
+
found = len(search_result.results_list)
|
|
245
|
+
while search_result.hits > found:
|
|
246
|
+
search_result = self._search_fields(query=query, fields=fields, start_index=found, page_size=page_size)
|
|
247
|
+
for e in search_result.results_list:
|
|
248
|
+
yield e
|
|
249
|
+
found = found + len(search_result.results_list)
|
|
250
|
+
|
|
251
|
+
def _search_fields(self, query: str = "%", fields: list[Field]=None, start_index: int = 0, page_size: int = 25):
|
|
252
|
+
|
|
253
|
+
start_from = str(start_index)
|
|
254
|
+
headers = {'Content-Type': 'application/x-www-form-urlencoded', HEADER_TOKEN: self.token}
|
|
255
|
+
|
|
256
|
+
if fields is None:
|
|
257
|
+
fields = []
|
|
258
|
+
|
|
259
|
+
field_list = []
|
|
260
|
+
sort_list = []
|
|
261
|
+
metadata_elements = []
|
|
262
|
+
for field in fields:
|
|
263
|
+
metadata_elements.append(field.name)
|
|
264
|
+
if field.value is None or field.value == "":
|
|
265
|
+
field_list.append('{' f' "name": "{field.name}", "values": [] ' + '}')
|
|
266
|
+
elif field.operator == "NOT":
|
|
267
|
+
field_list.append('{' f' "name": "{field.name}", "values": ["{field.value}"], "operator": "NOT" ' + '}')
|
|
268
|
+
else:
|
|
269
|
+
field_list.append('{' f' "name": "{field.name}", "values": ["{field.value}"] ' + '}')
|
|
270
|
+
|
|
271
|
+
if field.sort_order is not None:
|
|
272
|
+
sort_list.append(f'{{"sortFields": ["{field.name}"], "sortOrder": "{field.sort_order.name}"}}')
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
filter_terms = ','.join(field_list)
|
|
276
|
+
|
|
277
|
+
if len(sort_list) == 0:
|
|
278
|
+
query_term = ('{ "q": "%s", "fields": [ %s ] }' % (query, filter_terms))
|
|
279
|
+
else:
|
|
280
|
+
sort_terms = ','.join(sort_list)
|
|
281
|
+
query_term = ('{ "q": "%s", "fields": [ %s ], "sort": [ %s ]}' % (query, filter_terms, sort_terms))
|
|
282
|
+
|
|
283
|
+
if len(metadata_elements) == 0:
|
|
284
|
+
metadata_elements.append("xip.title")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
payload = {'start': start_from, 'max': str(page_size), 'metadata': list(metadata_elements), 'q': query_term}
|
|
288
|
+
logger.debug(payload)
|
|
289
|
+
results = self.session.post(f'{self.protocol}://{self.server}/api/content/search', data=payload,
|
|
290
|
+
headers=headers)
|
|
291
|
+
results_list = []
|
|
292
|
+
if results.status_code == requests.codes.ok:
|
|
293
|
+
json_doc = results.json()
|
|
294
|
+
metadata = json_doc['value']['metadata']
|
|
295
|
+
refs = list(json_doc['value']['objectIds'])
|
|
296
|
+
refs = list(map(lambda x: content_api_identifier_to_type(x), refs))
|
|
297
|
+
hits = int(json_doc['value']['totalHits'])
|
|
298
|
+
|
|
299
|
+
for m_row, r_row in zip(metadata, refs):
|
|
300
|
+
results_map = {'xip.reference': r_row[1]}
|
|
301
|
+
for li in m_row:
|
|
302
|
+
results_map[li['name']] = li['value']
|
|
303
|
+
results_list.append(results_map)
|
|
304
|
+
next_start = start_index + page_size
|
|
305
|
+
|
|
306
|
+
if self.callback is not None:
|
|
307
|
+
value = str(f'{len(results_list) + start_index}:{hits}')
|
|
308
|
+
self.callback(value)
|
|
309
|
+
|
|
310
|
+
search_results = self.SearchResult(metadata, refs, hits, results_list, next_start)
|
|
311
|
+
return search_results
|
|
312
|
+
elif results.status_code == requests.codes.unauthorized:
|
|
313
|
+
self.token = self.__token__()
|
|
314
|
+
return self._search_predicates(query, predicates, start_index, page_size)
|
|
315
|
+
else:
|
|
316
|
+
logger.error(f"search failed with error code: {results.status_code}")
|
|
317
|
+
raise RuntimeError(results.status_code, f"search_index_filter failed")
|
|
318
|
+
|
|
215
319
|
def search_index_filter_list(self, query: str = "%", page_size: int = 25, filter_values: dict = None,
|
|
216
320
|
sort_values: dict = None) -> Generator:
|
|
217
321
|
"""
|
|
@@ -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.9.
|
|
24
|
+
version="2.9.1",
|
|
25
25
|
description="Python library for the Preservica API",
|
|
26
26
|
long_description=README,
|
|
27
27
|
long_description_content_type="text/markdown",
|
|
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
|
|
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
|