From 218c2ee360f8df9918a841881c931c1b66fe9a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Michael=20O=2E=20Hegg=C3=B8?= Date: Mon, 9 Nov 2020 21:12:10 +0100 Subject: [PATCH 01/23] Add MarcXchange to namespace list --- sruthi/xmlparse.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sruthi/xmlparse.py b/sruthi/xmlparse.py index 988ceef..d454dd0 100644 --- a/sruthi/xmlparse.py +++ b/sruthi/xmlparse.py @@ -33,6 +33,7 @@ def __init__(self): 'info:srw/extension/2/relevancy-1.0': None, 'http://www.archivportal.ch/srw/extension/': None, 'http://www.loc.gov/MARC21/slim': None, + 'info:lc/xmlns/marcxchange-v1': None, 'http://www.loc.gov/mods/v3': None, 'http://www.loc.gov/standards/mods/v3/mods-3-6.xsd': None, 'http://www.loc.gov/standards/mods/v3/mods-3-6.xsd': None, From c7e958dedebb77c78e0a6b26289990b8e56e12bd Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Fri, 10 Sep 2021 13:34:12 +0200 Subject: [PATCH 02/23] Add CHANGELOG entry for #3 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a34aad4..61edf5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project follows [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- Add MarcXchange (ISO 25577) namespace [#35](https://github.com/metaodi/sruthi/pull/35) (thanks [danmichaelo](https://github.com/danmichaelo)!) ## [0.1.2] - 2020-10-04 ### Fixed From 31ac314bad70a1387fa99eb5450f112393ddb25a Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 4 Dec 2021 09:09:20 +0100 Subject: [PATCH 03/23] Add alternative namespace for explain response --- examples/explain.py | 2 +- sruthi/response.py | 74 +++++++++++++++++++++++++++++++++++++++------ sruthi/xmlparse.py | 7 +++++ 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/examples/explain.py b/examples/explain.py index 8222336..6e0868e 100644 --- a/examples/explain.py +++ b/examples/explain.py @@ -7,7 +7,7 @@ 'https://suche.staatsarchiv.djiktzh.ch/SRU/', 'https://amsquery.stadt-zuerich.ch/SRU/', 'http://lx2.loc.gov:210/LCDB?', - 'https://sru.swissbib.ch/sru/explain', + 'https://na01.alma.exlibrisgroup.com/view/sru/TR_INTEGRATION_INST', ] diff --git a/sruthi/response.py b/sruthi/response.py index a5b119c..2bb2fcb 100644 --- a/sruthi/response.py +++ b/sruthi/response.py @@ -206,8 +206,20 @@ def _parse_content(self, xml): def _parse_server(self, xml): server_info = { - 'host': self.xmlparser.find(xml, './/zr:serverInfo/zr:host').text, - 'port': self.xmlparser.find(xml, './/zr:serverInfo/zr:port').text, + 'host': self.xmlparser.find( + xml, + [ + './/zr:serverInfo/zr:host', + './/zr2:serverInfo/zr:host' + ] + ).text, + 'port': self.xmlparser.find( + xml, + [ + './/zr:serverInfo/zr:port', + './/zr2:serverInfo/zr:port', + ] + ).text, } server_info['port'] = self.maybe_int(server_info['port']) return server_info @@ -230,7 +242,14 @@ def ident(a): } schemas = {} - for schema in self.xmlparser.findall(xml, './/zr:schemaInfo/zr:schema'): + xml_schemas = self.xmlparser.findall( + xml, + [ + './/zr:schemaInfo/zr:schema', + './/zr2:schemaInfo/zr2:schema', + ] + ) + for schema in xml_schemas: schema_info = {} for attr, fn in attributes.items(): xml_attr = schema.attrib.get(attr) @@ -242,13 +261,27 @@ def ident(a): def _parse_config(self, xml): config = {} - for setting in self.xmlparser.findall(xml, './/zr:configInfo/zr:setting'): + settings = self.xmlparser.findall( + xml, + [ + './/zr:configInfo/zr:setting', + './/zr2:configInfo/zr:setting', + ] + ) + for setting in settings: t = setting.attrib['type'] config[t] = self.maybe_int(setting.text) # defaults + xml_defaults = self.xmlparser.findall( + xml, + [ + './/zr:configInfo/zr:default', + './/zr2:configInfo/zr:default', + ] + ) defaults = {} - for default in self.xmlparser.findall(xml, './/zr:configInfo/zr:default'): + for default in xml_defaults: t = default.attrib['type'] defaults[t] = self.maybe_int(default.text) config['defaults'] = defaults @@ -266,15 +299,36 @@ def _parse_database(self, xml): def _parse_index(self, xml): index = defaultdict(defaultdict) - for index_set in self.xmlparser.findall(xml, './/zr:indexInfo/zr:set'): + index_sets = self.xmlparser.findall( + xml, + [ + './/zr:indexInfo/zr:set', + './/zr2:indexInfo/zr2:set', + ] + ) + for index_set in index_sets: index[index_set.attrib['name']] = defaultdict() - for index_field in self.xmlparser.findall(xml, './/zr:indexInfo/zr:index'): - title = self.xmlparser.find(index_field, './zr:title').text or \ - self.xmlparser.find(index_field, './title').text + index_fields = self.xmlparser.findall( + xml, + [ + './/zr:indexInfo/zr:index', + './/zr2:indexInfo/zr2:index' + ] + ) + #print(self.xmlparser.findall(xml, './/zr2:indexInfo/zr2:index')) + for index_field in index_fields: + title = self.xmlparser.find(index_field, ['./zr:title', './title']).text if title: title = title.strip() - for name in self.xmlparser.findall(index_field, './/zr:map/zr:name'): + names = self.xmlparser.findall( + index_field, + [ + './/zr:map/zr:name', + './/zr2:map/zr2:name' + ] + ) + for name in names: index[name.attrib['set']][name.text.strip()] = title return {k: dict(v) for k, v in dict(index).items()} diff --git a/sruthi/xmlparse.py b/sruthi/xmlparse.py index d454dd0..7d12854 100644 --- a/sruthi/xmlparse.py +++ b/sruthi/xmlparse.py @@ -26,6 +26,7 @@ def __init__(self): 'rel': 'info:srw/extension/2/relevancy-1.0', 'ap': 'http://www.archivportal.ch/srw/extension/', 'zr': 'http://explain.z3950.org/dtd/2.1/', + 'zr2': 'http://explain.z3950.org/dtd/2.0/', } self.dict_namespaces = { 'http://www.loc.gov/zing/srw/': 'sru', @@ -62,6 +63,12 @@ def find(self, xml, path): return elem def findall(self, xml, path): + if isinstance(path, list): + for p in path: + elems = self.findall(xml, p) + if elems: + return elems + return [] return xml.findall(path, self.namespaces) def tostring(self, xml): From b697651a2128238430a5e5bbe312972fa352f3b3 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 4 Dec 2021 09:09:37 +0100 Subject: [PATCH 04/23] Return empty dict if databaseInfo is missing --- sruthi/response.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sruthi/response.py b/sruthi/response.py index 2bb2fcb..634fcac 100644 --- a/sruthi/response.py +++ b/sruthi/response.py @@ -207,7 +207,7 @@ def _parse_content(self, xml): def _parse_server(self, xml): server_info = { 'host': self.xmlparser.find( - xml, + xml, [ './/zr:serverInfo/zr:host', './/zr2:serverInfo/zr:host' @@ -289,6 +289,8 @@ def _parse_config(self, xml): def _parse_database(self, xml): db = self.xmlparser.find(xml, './/zr:databaseInfo') + if not db: + return {} db_info = { 'title': self.xmlparser.find(db, ['./zr:title', './title']).text, 'description': self.xmlparser.find(db, ['./zr:description', './description']).text, @@ -316,9 +318,8 @@ def _parse_index(self, xml): './/zr2:indexInfo/zr2:index' ] ) - #print(self.xmlparser.findall(xml, './/zr2:indexInfo/zr2:index')) for index_field in index_fields: - title = self.xmlparser.find(index_field, ['./zr:title', './title']).text + title = self.xmlparser.find(index_field, ['./zr:title', './title']).text if title: title = title.strip() names = self.xmlparser.findall( From 307ee5d8136b1a58b99685901b876cb30b037ff1 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 23:36:01 +0100 Subject: [PATCH 05/23] Add database field to server section of explain response --- sruthi/response.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/sruthi/response.py b/sruthi/response.py index 634fcac..e584e05 100644 --- a/sruthi/response.py +++ b/sruthi/response.py @@ -207,19 +207,26 @@ def _parse_content(self, xml): def _parse_server(self, xml): server_info = { 'host': self.xmlparser.find( - xml, - [ - './/zr:serverInfo/zr:host', - './/zr2:serverInfo/zr:host' - ] - ).text, + xml, + [ + './/zr:serverInfo/zr:host', + './/zr2:serverInfo/zr:host' + ] + ).text, 'port': self.xmlparser.find( - xml, - [ - './/zr:serverInfo/zr:port', - './/zr2:serverInfo/zr:port', - ] - ).text, + xml, + [ + './/zr:serverInfo/zr:port', + './/zr2:serverInfo/zr:port', + ] + ).text, + 'database': self.xmlparser.find( + xml, + [ + './/zr:serverInfo/zr:database', + './/zr2:serverInfo/zr:database', + ] + ).text, } server_info['port'] = self.maybe_int(server_info['port']) return server_info From 887487f7c6559612541b157e7f090982d648fec6 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 09:23:34 +0100 Subject: [PATCH 06/23] Do not use fail-fast strategy --- .github/workflows/lint_python.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml index a00405f..182c867 100644 --- a/.github/workflows/lint_python.yml +++ b/.github/workflows/lint_python.yml @@ -8,6 +8,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 strategy: + fail-fast: false matrix: python-version: [3.6, 3.7, 3.8] From d796d42752a05ca13849d402775ed47482674cb7 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 09:50:26 +0100 Subject: [PATCH 07/23] Add Makefile --- CONTRIBUTING.md | 8 +++++++- Makefile | 36 ++++++++++++++++++++++++++++++++++++ README.md | 8 ++++++++ test-requirements.txt | 1 + 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 Makefile diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5589b7..423bb02 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,18 +13,24 @@ Install the dependencies using `pip`: ```bash pip install -r requirements.txt pip install -r test-requirements.txt + +# or use make +make deps ``` Make sure the tests pass: ```bash -pytest +make test ``` To ensure a good quality of the code use `flake8` to check the code style: ```bash flake8 --install-hook git + +# with make +make lint ``` ## Create a pull request diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5fba338 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +.DEFAULT_GOAL := help +.PHONY: coverage deps help lint test + +coverage: ## Run tests with coverage + python -m coverage erase + python -m coverage run --include=sruthi/* -m pytest -ra + python -m coverage report -m + +deps: ## Install dependencies + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + python -m pip install -r test-requirements.txt + +lint: ## Linting of source code + python -m flake8 --statistics --show-source . + +test: ## Run tests + python -m pytest --cov=sruthi tests/ + +help: SHELL := /bin/bash +help: ## Show help message + @IFS=$$'\n' ; \ + help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##/:/'`); \ + printf "%s\n\n" "Usage: make [task]"; \ + printf "%-20s %s\n" "task" "help" ; \ + printf "%-20s %s\n" "------" "----" ; \ + for help_line in $${help_lines[@]}; do \ + IFS=$$':' ; \ + help_split=($$help_line) ; \ + help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \ + help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \ + printf '\033[36m'; \ + printf "%-20s %s" $$help_command ; \ + printf '\033[0m'; \ + printf "%s\n" $$help_info; \ + done diff --git a/README.md b/README.md index c532b38..ef861bd 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Currently only SRU 1.2 is supported. * [`searchretrieve` operation](#searchretrieve-operation) * [`explain` operation](#explain-operation) * [Schemas](#schemas) +* [Development](#development) * [Release](#release) ## Installation @@ -85,6 +86,13 @@ sruthi has been tested with the following schemas: * [MARCXML: The MARC 21 XML Schema](http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd) (marcxml) * [ISAD(G): General International Standard Archival Description, Second edition](http://www.expertisecentrumdavid.be/xmlschemas/isad.xsd) (isad) +## Development + +To contribute to sruthi simply clone this repository and follow the instructions in [CONTRIBUTING.md](/CONTRIBUTING.md). + +This project ha a Makefile with the most common commands. +Type `make help` to get an overview. + ## Release To create a new release, follow these steps (please respect [Semantic Versioning](http://semver.org/)): diff --git a/test-requirements.txt b/test-requirements.txt index 5ecd5cd..421bd5b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,3 +4,4 @@ flake8 mock pytest pytest-cov +coverage From 6f7c4166e0bd1074b01a4ff4d8d89b8bcb449b06 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 09:52:47 +0100 Subject: [PATCH 08/23] Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61edf5c..6b55c94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed - Add MarcXchange (ISO 25577) namespace [#35](https://github.com/metaodi/sruthi/pull/35) (thanks [danmichaelo](https://github.com/danmichaelo)!) +### Fixed +- Fix parsing of non-standard namespaces for explain response + ## [0.1.2] - 2020-10-04 ### Fixed - Fix missing dependencies in setup.py From c55906168dbad2666a418fdd030b746c747889a8 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 10:30:50 +0100 Subject: [PATCH 09/23] Add zr2 namespace test --- sruthi/response.py | 4 +- tests/client_test.py | 48 + .../test_explain_with_zr2_namespace.xml | 4441 +++++++++++++++++ 3 files changed, 4491 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/test_explain_with_zr2_namespace.xml diff --git a/sruthi/response.py b/sruthi/response.py index e584e05..788df76 100644 --- a/sruthi/response.py +++ b/sruthi/response.py @@ -219,14 +219,14 @@ def _parse_server(self, xml): './/zr:serverInfo/zr:port', './/zr2:serverInfo/zr:port', ] - ).text, + ).text, 'database': self.xmlparser.find( xml, [ './/zr:serverInfo/zr:database', './/zr2:serverInfo/zr:database', ] - ).text, + ).text, } server_info['port'] = self.maybe_int(server_info['port']) return server_info diff --git a/tests/client_test.py b/tests/client_test.py index 18b5d07..a7d29e2 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -79,6 +79,7 @@ def test_explain(self): server = info.server self.assertEqual(server['host'], 'https://test.com/sru') self.assertEqual(server['port'], 80) + self.assertEqual(server['database'], 'sru') # database db = info.database @@ -123,6 +124,53 @@ def test_explain_with_requests_kwargs(self): verify=False ) + def test_explain_with_zr2_namespace(self): + client = Client('https://example.com/sru') + info = client.explain() + + # server + server = info.server + self.assertEqual(server['host'], 'example.com/sru') + self.assertEqual(server['port'], 443) + + # index + index = info.index + self.assertEqual(len(index), 2) + self.assertEqual(list(index.keys()), ['alma', 'rec']) + self.assertIn('title', index['alma']) + self.assertIn('notes', index['alma']) + self.assertIn('date', index['alma']) + self.assertIn('description', index['alma']) + self.assertEqual(index['alma']['url'], 'URL (Electronic Portfolio)') + + # schema + schema = info.schema + self.assertEqual(len(schema), 8) + self.assertEqual( + list(schema.keys()), + [ + 'marcxml', + 'dc', + 'mods', + 'dcx', + 'unimarcxml', + 'kormarcxml', + 'cnmarcxml', + 'isohold', + ] + ) + self.assertEqual(schema['marcxml']['name'], 'marcxml') + self.assertEqual(schema['marcxml']['sort'], True) + self.assertEqual( + schema['marcxml']['identifier'], + 'http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd' + ) + + # config + config = info.config + self.assertEqual(config['maximumRecords'], 50) + self.assertEqual(config['defaults']['numberOfRecords'], 10) + def test_passing_maximum_records(self): client = Client('http://my-param.com/sru', maximum_records=111) self.assertEqual(client.maximum_records, 111) diff --git a/tests/fixtures/test_explain_with_zr2_namespace.xml b/tests/fixtures/test_explain_with_zr2_namespace.xml new file mode 100644 index 0000000..e67e577 --- /dev/null +++ b/tests/fixtures/test_explain_with_zr2_namespace.xml @@ -0,0 +1,4441 @@ + + 1.2 + + http://explain.z3950.org/dtd/2.1/ + xml + + + + example.com/sru + 443 + TR_INTEGRATION_INST + + + + + Accompanying Material + + accompanying_material + + + all + = + + + + + Additional Physical Form Available Note + + additional_physical_form_available_note + + + all + = + == + + + + Keywords + + all_for_ui + + + all + = + + + + + Edition + + alternate_complete_edition + + + all + = + == + + + + Authority Id + + authority_id + + + all + = + + + + + Authority Vocabulary + + authority_vocabulary + + + all + = + + + + + Bibliographic Level + + bib_level + + + == + <> + + = + all + + + + Carrier Type Code (Title) + + carrier_type_code + + + == + <> + + = + all + + + + Carrier Type Term (Title) + + carrier_type_term + + + == + <> + + = + all + + + + Cartographic Mathematical Data + + cartographic_mathematical_data + + + all + = + + + + + Physical Description + + category_of_material + + + == + <> + + = + all + + + + Classification Part + + classification_part + + + all + = + == + + + + Coded Cartographic Mathematical Data + + coded_cartographic_mathematical_data + + + all + = + + + + + Content Related Data + + content_related_data + + + all + = + + + + + Content Type Code + + content_type_code + + + == + <> + + = + all + + + + Content Type Term + + content_type_term + + + == + <> + + = + all + + + + Copyright Note + + copyrights_note + + + all + = + + + + + Country of Publication (code) + + country_of_publication + + + all + = + + + + + Country of Publication + + country_of_publication_new + + + == + <> + + = + all + + + + Creator + + creator + + + all + = + == + + + + Additional Publication Year + + date_of_publication + + + all + = + + + + + dc:contributor + + dc_contributor + + + all + = + + + + + dc:coverage + + dc_coverage + + + all + = + + + + + dc:creator + + dc_creator + + + all + = + + + + + dc:date + + dc_date + + + all + = + + + + + dc:description + + dc_description + + + all + = + + + + + dc:format + + dc_format + + + all + = + + + + + dc:language + + dc_language + + + == + <> + + = + all + + + + dc:publisher + + dc_publisher + + + all + = + + + + + dc:relation + + dc_relation + + + all + = + + + + + dc:rights + + dc_rights + + + all + = + + + + + dc:source + + dc_source + + + all + = + + + + + dc:subject + + dc_subject + + + all + = + + + + + dc:title + + dc_title + + + all + = + == + + + + + dc:type + + dc_type + + + == + <> + + = + all + + + + Description + + description + + + all + = + + + + + Dewey Decimal Class Number + + dewey_decimal_class_number + + + all + = + == + + + + + DOI - Digital Object Identifier + + digital_object_identifier + + + all + = + + + + + Electronic Location And Note + + elocation + + + all + = + == + + + + + Event Date + + event_date + + + all + = + + + + + Public Note (Title) + + general_note + + + all + = + == + + + + Genre Form + + genre_form + + + all + = + + + + + Geographic Area Code + + geographic_area_code + + + all + = + == + + + + Government Document Number + + government_document_number + + + all + = + + + + + Granular Resource Type + + granular_resource_type + + + all + = + + + + + Has Inventory + + has_inventory + + + == + = + all + + + + Heading Information + + heading_info + + + all + = + == + + + + dc:identifier + + identifier + + + == + <> + + = + all + + + + Is linked + + is_linked + + + == + = + all + + + + ISBN + + isbn + + + all + = + + + + + Other Standard ID + + ismn + + + all + = + + + + + ISNI - International Standard Name Identifier + + isni_identifier + + + all + = + + + + + ISSN + + issn + + + all + = + + + + + ISSN link + + issn_link + + + all + = + + + + + Language (Title) + + language + + + == + <> + + = + all + + + + Language Of Cataloging + + language_of_cataloging + + + == + <> + + = + all + + + + LC Call Number + + lc_class_number + + + all + = + == + + + + + LC Control No. + + lccn + + + all + = + + + + + Subjects (LC) + + lcsh + + + all + = + == + + + + Linked Institution + + link_inst + + + == + <> + + = + all + + + + Local Control Field 009 + + local_control_field_009 + + + all + = + == + + + + + Local field 900 + + local_field_900 + + + all + = + + + + + Local field 906 + + local_field_906 + + + all + = + + + + + Local field 912 + + local_field_912 + + + all + = + + + + + Local field 917 + + local_field_917 + + + all + = + + + + + Local field 919 + + local_field_919 + + + all + = + + + + + SHK + + local_field_939 + + + all + = + + + + + Local field 960 + + local_field_960 + + + all + = + + + + + Local field 977 + + local_field_977 + + + all + = + + + + + CR Restricted + + local_field_999 + + + all + = + + + + + Local Notes + + local_notes + + + all + = + + + + + lom-edu:context + + lom_context + + + all + = + + + + + lom-edu:description + + lom_description + + + all + = + + + + + lom-edu:difficulty + + lom_difficulty + + + all + = + + + + + lom-edu:intendedEndUserRole + + lom_intendedEndUserRole + + + all + = + + + + + lom-edu:interactivityLevel + + lom_interactivityLevel + + + all + = + + + + + lom-edu:interactivityType + + lom_interactivityType + + + all + = + + + + + lom-edu:language + + lom_language + + + all + = + + + + + lom-edu:semanticDensity + + lom_semanticDensity + + + all + = + + + + + lom-edu:type + + lom_type + + + all + = + + + + + lom-edu:typicalLearningTime + + lom_typicalLearningTime + + + all + = + + + + + Publication Year + + main_pub_date + + + == + > + >= + < + <= + <> + = + all + + + + Media Type Code (Title) + + media_type_code + + + == + <> + + = + all + + + + Media Type Term (Title) + + media_type_term + + + == + <> + + = + all + + + + Medium Type + + medium_type + + + == + <> + + = + all + + + + Medical Subjects (MeSH) + + mesh + + + all + = + == + + + + Brief Level + + mms_briefLevel + + + all + = + == + > + >= + < + <= + + + + + Cataloger Level + + mms_catalogerLevel + + + all + = + == + > + >= + < + <= + + + + + Contributed By + + mms_contributedBy + + + all + = + + + + + MMS Creation Date (Title) + + mms_createDate + + + == + < + > + + = + all + + + + MMS ID + + mms_id + + + == + > + >= + < + <= + <> + = + all + + + + Managed By Provider (Title) + + mms_managed_by + + + == + = + all + + + + Material type + + mms_material_type + + + == + <> + + = + all + + + + Md Import modification job id + + mms_mdImportModificationHistory + + + all + = + + + + + Collection ID + + mms_memberOfDeep + + + all + = + + + + + Modification Date (Title) + + mms_modificationDate + + + == + < + > + + = + all + + + + Originating System + + mms_originatingSystem + + + all + = + == + + + + + Originating System Id + + mms_originatingSystemId + + + all + = + + + + + Resource Type + + mms_resource_type + + + == + <> + + = + all + + + + MMS SIP ID + + mms_sip_id + + + all + = + + + + + Tag Suppressed (Title) + + mms_tagSuppressed + + + == + <> + + = + all + + + + Tag Suppressed From External Search + + mms_tagSuppressedExternalSearch + + + == + <> + + = + all + + + + Tag Sync External Catalog + + mms_tagSyncExternalCatalog + + + == + <> + + = + all + + + + Tag Sync External Catalog + + mms_tagSyncNationalCatalog + + + == + <> + + = + all + + + + Names + + name + + + all + = + == + + + + + National Bibliography Number + + national_bibliography_number + + + all + = + + + + + NLM-type Call Number + + nlm_call_number + + + all + = + == + + + + + Notes + + notes + + + all + = + + + + + OCLC Control Number (019) + + oclc_control_number_019_a + + + all + = + == + + + + + OCLC Control Number (035a) + + oclc_control_number_035_a + + + all + = + == + + + + + OCLC Control Number (035a+z) + + oclc_control_number_035_az + + + all + = + == + + + + + OCLC Control Number (035z) + + oclc_control_number_035_z + + + all + = + == + + + + + Open Access + + open_access + + + == + <> + + = + all + + + + ORCID - Open Researcher and Contributor ID + + orcid_identifier + + + all + = + + + + + Original Cataloging Agency + + original_cataloging_agency + + + all + = + + + + + Other Classification Number + + other_class_number + + + all + = + == + + + + + Other Physical Details + + other_physical_details + + + all + = + + + + + Other Standard Identifier + + other_standard_identifier + + + all + = + + + + + Other System Number + + other_system_number + + + all + = + == + + + + + Peer Reviewed + + peer_reviewed + + + == + <> + + = + all + + + + Publisher + + publisher + + + all + = + == + + + + Publisher Location + + publisher_location + + + all + = + + + + + Publisher Number + + publisher_number + + + all + = + + + + + Record Format + + registry_id + + + all + = + + + + + Relator + + relator + + + all + = + + + + + RUC Classification Number + + ruc_class_number + + + all + = + == + + + + + Series + + series + + + all + = + == + + + + + Shelving Location + + shelving_location + + + all + = + == + + + + Source Record Id + + source_record_id + + + all + = + + + + + Standard Number + + standard_number + + + all + = + + + + + International Standard Recording Code + + stored_standard_number_024_a_ind1_0 + + + all + = + == + + + + Universal Product Code + + stored_standard_number_024_a_ind1_1 + + + all + = + == + + + + International Standard Music Number + + stored_standard_number_024_a_ind1_2 + + + all + = + == + + + + International Article Number + + stored_standard_number_024_a_ind1_3 + + + all + = + == + + + + Serial Item and Contribution Identifier + + stored_standard_number_024_a_ind1_4 + + + all + = + == + + + + Subject Category Code + + subject_category_code + + + all + = + + + + + Subjects + + subjects + + + all + = + == + + + + + Sublocation + + sublocation + + + all + = + == + + + + Title + + title + + + all + = + == + + + + + Date Type Status + + type_of_date + + + == + <> + + = + all + + + + Bibliographic Format + + type_of_record + + + == + <> + + = + all + + + + Uniform Title + + uniform_title + + + all + = + == + + + + Serial Title + + unique_serial_title + + + all + = + == + + + + UDC + + universal_decimal_class_number + + + all + = + == + + + + + Item call number + + alterCallNumber + + + all + = + + + + + Item call number type + + alternativeCallNumberType + + + == + + = + all + + + + Receiving date + + arrivalDate + + + == + < + > + + = + all + + + + Barcode + + barcode + + + all + = + + + + + Base status + + baseStatus + + + == + + = + all + + + + Chronology I + + chronologyI + + + all + = + + + + + Chronology J + + chronologyJ + + + all + = + + + + + Chronology K + + chronologyK + + + all + = + + + + + Chronology L + + chronologyL + + + all + = + + + + + Chronology M + + chronologyM + + + all + = + + + + + c.search.index_names.current_library + + current_Library + + + == + + = + all + + + + c.search.index_names.current_location + + current_Location + + + == + + = + all + + + + Enumeration A + + enumerationA + + + all + = + + + + + Enumeration B + + enumerationB + + + all + = + + + + + Enumeration C + + enumerationC + + + all + = + + + + + Enumeration D + + enumerationD + + + all + = + + + + + Enumeration E + + enumerationE + + + all + = + + + + + Enumeration F + + enumerationF + + + all + = + + + + + Enumeration G + + enumerationG + + + all + = + + + + + Enumeration H + + enumerationH + + + all + = + + + + + Expected receiving date + + expectedArrivalDate + + + == + < + > + + = + all + + + + Due back from temp location date + + expectedReturnFromTempLocation + + + == + < + > + + = + all + + + + Fulfillment Note + + fulfilment_note + + + all + = + + + + + Internal note 1 + + internal_note_1 + + + all + = + + + + + Internal note 2 + + internal_note_2 + + + all + = + + + + + Internal note 3 + + internal_note_3 + + + all + = + + + + + Inventory date + + inventoryDate + + + == + < + > + + = + all + + + + Inventory number + + inventoryNumber + + + all + = + + + + + Is Magnetic + + isMagnetic + + + == + + = + all + + + + Issue year + + issueYear + + + == + > + >= + < + <= + = + all + + + + Creation Date (Physical Item) + + item_createDate + + + == + < + > + + = + all + + + + Description + + item_description + + + all + = + + + + + Modification Date (Physical Item) + + item_modificationDate + + + == + < + > + + = + all + + + + Item PID + + item_pid + + + == + > + >= + < + <= + = + all + + + + Item Issue Date + + itemIssueDate + + + == + < + > + + = + all + + + + Library + + itemLibrary + + + == + + = + all + + + + Location + + itemPhysicalLocation + + + == + + = + all + + + + Item policy + + itemPolicy + + + == + + = + all + + + + PO Line + + itemPOLineID + + + all + = + + + + + Item sequence number + + itemSequenceNumber + + + all + = + + + + + Material Type (Physical Item) + + materialType + + + == + + = + all + + + + On shelf date + + onShelfDate + + + == + < + > + + = + all + + + + On shelf seq + + onShelfSeq + + + all + = + + + + + Pages + + pages + + + all + = + + + + + Call Number Type + + permanentCallNumberTypeFacet + + + == + + = + all + + + + Physical condition + + physicalCondition + + + == + + = + all + + + + Pieces + + pieces + + + all + = + + + + + Process type + + processType + + + == + + = + all + + + + Provenance Code + + provenanceCode + + + == + + = + all + + + + Public note (Physical Item) + + public_note + + + all + = + + + + + Statistics note 1 + + statisticsNote1 + + + all + = + + + + + Statistics note 2 + + statisticsNote2 + + + all + = + + + + + Statistics note 3 + + statisticsNote3 + + + all + = + + + + + Storage Location ID + + storageLocationID + + + all + = + + + + + Temporary call number + + temporaryCallNumber + + + all + = + + + + + Temporary call number type + + temporaryCallNumberType + + + == + + = + all + + + + Temporary item policy + + temporaryItemPolicy + + + == + + = + all + + + + Temporary library + + temporaryLibrary + + + == + + = + all + + + + Temporary physical location + + temporaryPhysicalLocation + + + == + + = + all + + + + In temporary location + + temporaryPhysicalLocationInUse + + + == + > + >= + < + <= + = + all + + + + Accession Number + + accessionNumber + + + all + = + == + > + >= + < + <= + + + + + Acquisition Note + + acquisition_note + + + all + = + + + + + Action note + + action_note + + + all + = + == + + + + Action note - authorization + + action_note_authorization + + + all + = + == + + + + Action note - note + + action_note_note + + + all + = + == + + + + Binding Note + + binding_note + + + all + = + + + + + Call number prefix + + callNumberPrefix + + + all + = + + + + + Call number suffix + + callNumberSuffix + + + all + = + + + + + Completeness + + completeness + + + == + + = + all + + + + Encoding level + + encoding_level + + + == + + = + all + + + + Ownership and Custodial History + + f561a + + + all + = + + + + + General retention policy + + general_retention_policy + + + == + + = + all + + + + Control number (Holdings) + + hol_control_number + + + all + = + == + + + + Creation date (physical holdings) + + hol_createDate + + + == + < + > + + = + all + + + + Modification date (physical holdings) + + hol_modificationDate + + + == + < + > + + = + all + + + + OCLC Control Number (035a) - Holdings + + hol_oclc_control_number_035_a + + + all + = + == + + + + OCLC Control Number (035a+z) - Holdings + + hol_oclc_control_number_035_az + + + all + = + == + + + + OCLC Control Number (035z) - Holdings + + hol_oclc_control_number_035_z + + + all + = + == + + + + Other System Number (035a) - Holdings + + hol_other_system_number_035_a + + + all + = + == + + + + Other System Number (035a+z) - Holdings + + hol_other_system_number_035_az + + + all + = + == + + + + Other System Number (035z) - Holdings + + hol_other_system_number_035_z + + + all + = + == + + + + Type of record + + hol_type_of_record + + + == + + = + all + + + + URL + + hol_url + + + all + = + == + + + + URL access status + + hol_url_access_status + + + all + = + == + + + + URL link text + + hol_url_link_text + + + all + = + == + + + + URL materials specified + + hol_url_materials_specified + + + all + = + == + + + + URL method + + hol_url_method + + + all + = + == + + + + URL non public note + + hol_url_non_public_note + + + all + = + == + + + + URL public note + + hol_url_public_note + + + all + = + == + + + + Carrier Type Code (Title) + + holding_carrier_type_code + + + == + + = + all + + + + Carrier Type Term (Title) + + holding_carrier_type_term + + + == + + = + all + + + + Library (Holdings) + + holding_Library + + + == + + = + all + + + + Media type code (Holdings) + + holding_media_type_code + + + == + + = + all + + + + Media type term (Holdings) + + holding_media_type_term + + + == + + = + all + + + + Holdings note + + holding_Note + + + all + = + + + + + Holdings PID + + holding_pid + + + == + > + >= + < + <= + = + all + + + + Tag Suppressed (Holdings) + + holding_tagSuppressed + + + == + + = + all + + + + Lending Policy + + lending_policy + + + == + + = + all + + + + Linkage number + + linkage_number + + + all + = + == + + + + LOCAL holding 935 + + local_holding_field_935 + + + all + = + + + + + Local holding field 959 + + local_holding_field_959 + + + all + = + + + + + Local holding field 991 + + local_holding_field_991 + + + all + = + + + + + Local holding field 999 + + local_holding_field_999 + + + all + = + + + + + Method of acquisition + + method_of_acquisition + + + == + + = + all + + + + c.search.index_names.has_items + + p_level_4_id + + + == + = + all + + + + Pattern 5th level of enumeration + + pattern_fifth_level_enum + + + all + = + == + + + + Pattern 1st level of enumeration + + pattern_first_level_enum + + + all + = + == + + + + Pattern 4th level of enumeration + + pattern_fourth_level_enum + + + all + = + == + + + + Pattern frequency + + pattern_frequency + + + all + = + == + + + + Pattern 2nd level of enumeration + + pattern_second_level_enum + + + all + = + == + + + + Pattern 6th level of enumeration + + pattern_sixth_level_enum + + + all + = + == + + + + Pattern 3rd level of enumeration + + pattern_third_level_enum + + + all + = + == + + + + Permanent call number + + PermanentCallNumber + + + all + = + == + > + >= + < + <= + + + + + Permanent call number type + + permanentCallNumberType + + + == + + = + all + + + + Permanent physical location + + permanentPhysicalLocation + + + == + + = + all + + + + Receipt, acquisition, or access status + + receipt_acq_status + + + == + + = + all + + + + Reproduction Policy + + reproduction_policy + + + == + + = + all + + + + Summary holdings + + summaryHolding + + + all + = + + + + + Textual holdings + + textual_holdings + + + all + = + == + + + + Textual holdings nonpublic note + + textual_holdings_non_public_note + + + all + = + == + + + + Textual holdings public note + + textual_holdings_public_note + + + all + = + == + + + + Available for + + available_for + + + == + + = + all + + + + Available for group + + available_for_group + + + == + + = + all + + + + Available for + + available_only_for + + + == + + = + all + + + + Available explicitly for group + + available_only_for_group + + + == + + = + all + + + + Coverage In Use + + coverageInUse + + + == + + = + all + + + + Public note (Electronic Portfolio) + + generalNote + + + all + = + == + + + + c.search.index_names.isStandalone + + is_standalone + + + == + = + all + + + + Access Rights (Electronic Portfolio) + + portfolio_accessRights + + + == + + = + all + + + + Portfolio Access Type + + portfolio_accessType + + + == + + = + all + + + + Activation Date (Electronic Portfolio) + + portfolio_activationDate + + + == + < + > + + = + all + + + + Authentication note (Electronic Portfolio) + + portfolio_authenticationNote + + + all + = + + + + + Availability (Electronic Portfolio) + + portfolio_baseStatus + + + == + + = + all + + + + Contributed By (Electronic Portfolio) + + portfolio_contributedBy + + + all + = + + + + + Creation Date (Electronic Portfolio) + + portfolio_creation_date + + + == + < + > + + = + all + + + + Portfolio EBA ID + + portfolio_ebaId + + + all + = + + + + + Has Local Coverage Information + + portfolio_has_local_coverage + + + == + + = + all + + + + Interface Name (Electronic Portfolio) + + portfolio_interfaceName + + + all + = + + + + + Internal Description (Electronic Portfolio) + + portfolio_internalDescription + + + all + = + == + + + + Is Local (Electronic Portfolio) + + portfolio_is_local + + + == + + = + all + + + + c.search.index_names.portfolioLibrary + + portfolio_Library + + + == + + = + all + + + + Portfolio License ID + + portfolio_license_id + + + all + = + + + + + Managed by Provider (Electronic Portfolio) + + portfolio_managed_by + + + == + = + all + + + + Material Type (Electronic Portfolio) + + portfolio_materialType + + + == + + = + all + + + + Modification Date (Electronic Portfolio) + + portfolio_modification_date + + + == + < + > + + = + all + + + + Notes tab + + portfolio_note_out + + + all + = + + + + + Portfolio PDA ID + + portfolio_pdaId + + + all + = + + + + + Portfolio PID + + portfolio_pid + + + == + > + >= + < + <= + = + all + + + + Portfolio PO Line ID + + portfolio_POLineID + + + all + = + + + + + Proxy Enabled (Electronic Portfolio) + + portfolioProxyEnabled + + + == + + = + all + + + + Proxy name (Electronic Portfolio) + + proxy + + + all + = + + + + + Public Access Model + + publicAccessModel + + + == + + = + all + + + + ProQuest purchase model + + purchaseModel + + + == + + = + all + + + + URL (Electronic Portfolio) + + url + + + all + = + + + + + Access Rights Policy Name + + ar_policy + + + == + + = + all + + + + Copyrights Name + + copyrightsId + + + == + + = + all + + + + Date + + date + + + all + = + + + + + Deposit ID + + deposit_id + + + all + = + + + + + Request ID + + digitization_request_id + + + all + = + + + + + Issue + + issue + + + all + = + + + + + Number + + number + + + all + = + + + + + Usage Type + + preservationType + + + == + + = + all + + + + Remote repository + + remote_representation_integration_system_code + + + == + <> + + = + all + + + + Linking Parameter 1 + + remote_representation_linkingparameter1 + + + all + = + + + + + Linking Parameter 2 + + remote_representation_linkingparameter2 + + + all + = + + + + + Linking Parameter 3 + + remote_representation_linkingparameter3 + + + all + = + + + + + Linking Parameter 4 + + remote_representation_linkingparameter4 + + + all + = + + + + + Linking Parameter 5 + + remote_representation_linkingparameter5 + + + all + = + + + + + Originating Record ID + + remote_representation_originating_system_id + + + all + = + + + + + Library + + rep_Library + + + == + <> + + = + all + + + + Public note (Physical Item) + + rep_public_note + + + all + = + + + + + Creator (Title) + + repCreator + + + all + = + + + + + PO Line + + repPoLineId + + + all + = + + + + + Representation Label + + representation_label + + + all + = + + + + + Provenance ID + + representation_originating_system_id + + + all + = + + + + + Representation PID + + representation_pid + + + == + > + >= + < + <= + = + all + + + + Entity type + + representationEntityType + + + == + <> + + = + all + + + + Title + + repTitle + + + all + = + + + + + Tag Active (Representation) + + tagActive + + + == + = + all + + + + Volume + + volume + + + all + = + + + + + Activate From + + activateFrom + + + == + < + > + + = + all + + + + Activate To + + activateTo + + + == + < + > + + = + all + + + + Electronic Collection Type + + aggregator + + + == + + = + all + + + + Category + + category + + + all + = + + + + + CDI-only full text activation + + cdi_delivery + + + == + = + all + + + + Collection Available for group + + coll_available_for_group + + + == + + = + all + + + + Collection available explicitly for group + + coll_available_only_for_group + + + == + + = + all + + + + Creator Name (Electronic Collection) + + creatorName + + + all + = + + + + + Crossref enabled + + crossrefenabled + + + == + + = + all + + + + CDI Collection ID (DB ID) + + db_id + + + == + = + all + + + + Collection Access Type + + iepa_accessType + + + == + + = + all + + + + Activation Date (Electronic Collection) + + iepa_activationDate + + + == + < + > + + = + all + + + + Authentication note (Electronic Collection) + + iepa_authenticationNote + + + all + = + + + + + CDI Fulltext rights + + iepa_cdi_fulltext_rights + + + == + = + all + + + + CDI Fulltext Linking + + iepa_cdi_linking + + + == + = + all + + + + CDI Newspapers + + iepa_cdi_newspaper_search + + + == + = + all + + + + CDI Provider Coverage + + iepa_cdi_provider_coverage + + + == + = + all + + + + CDI Search rights + + iepa_cdi_search_rights + + + == + = + all + + + + CDI Type + + iepa_cdi_type + + + == + = + all + + + + Contributed By (Electronic Collection) + + iepa_contributedBy + + + all + = + + + + + Is Local (Electronic Collection) + + iepa_is_local + + + == + + = + all + + + + Free (Electronic Collection) + + iepa_isFree + + + == + + = + all + + + + Language (Electronic Collection) + + iepa_language + + + == + + = + all + + + + c.search.index_names.iepaLibrary + + iepa_Library + + + == + + = + all + + + + Electronic Collection ID + + iepa_pid + + + == + > + >= + < + <= + = + all + + + + Collection PO Line ID + + iepa_POLineID + + + all + = + + + + + Proxy Enabled (Electronic Collection) + + iepa_proxyEnabled + + + == + + = + all + + + + We subscribe only to some titles in this collection + + iepa_selectiveIndication + + + == + = + all + + + + CDI Suppress Full Text + + iepa_suppressFromCdi + + + == + = + all + + + + Interface Name (Electronic Collection) + + interfaceName + + + all + = + + + + + Internal Description (Electronic Collection) + + internalDescription + + + all + = + == + + + + Free (Service) + + isFree + + + == + + = + all + + + + Linking Level + + linkingLevel + + + == + + = + all + + + + Link Resolver Plugin + + linkResolverPlugin + + + == + + = + all + + + + Available for + + package_available_for + + + == + + = + all + + + + Available for + + package_available_only_for + + + == + + = + all + + + + Creation Date (Electronic Collection) + + package_creation_date + + + == + < + > + + = + all + + + + Service Authentication Note + + package_license_id + + + all + = + + + + + Modification Date (Electronic Collection) + + package_modification_date + + + == + < + > + + = + all + + + + URL (Electronic Collection) + + package_nativeInterfaceUrl + + + all + = + + + + + Electronic Collection Name + + packageName + + + all + = + + + + + Electronic Collection Content Type + + packageType + + + == + + = + all + + + + Service Authentication Note + + pps_authenticationNote + + + all + = + + + + + Availability (Electronic Collection) + + pps_baseStatus + + + == + + = + all + + + + Proxy name (Electronic Collection) + + proxySelected + + + all + = + + + + + Public note (Electronic Collection) + + publicNote + + + all + = + + + + + Title Service PID + + service_pid + + + == + > + >= + < + <= + = + all + + + + Proxy Enabled (Service) + + service_proxyEnabled + + + == + + = + all + + + + Service Type + + serviceType + + + == + + = + all + + + + Managed by Provider (Electronic Collection) + + tps_managed_by + + + == + = + all + + + + Record Identifier (MMS ID) + + id + + + == + > + >= + < + <= + <> + = + all + + + + + + + + + + + + + + + 10 + 50 + = + all + == + > + < + >= + <= + <> + + + + + + From 853e3140d758cb0dd42f5dff27bd42c009912e59 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 11:22:56 +0100 Subject: [PATCH 10/23] Update README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ef861bd..40935cc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![PyPI Version](https://img.shields.io/pypi/v/sruthi)](https://pypi.org/project/sruthi/) +[![Tests + Linting Python](https://github.com/metaodi/sruthi/actions/workflows/lint_python.yml/badge.svg)](https://github.com/metaodi/sruthi/actions/workflows/lint_python.yml) + # sruthi **sru**thi is a client for python to make [SRU requests (Search/Retrieve via URL)](http://www.loc.gov/standards/sru/). From f289da50a4182b6829dc3f0c639a3d30f6a39092 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 4 Dec 2021 16:36:02 +0100 Subject: [PATCH 11/23] Allow passing of sru_version as parameter --- sruthi/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sruthi/client.py b/sruthi/client.py index 11e8078..0d249fb 100644 --- a/sruthi/client.py +++ b/sruthi/client.py @@ -7,10 +7,10 @@ class Client(object): - def __init__(self, url=None, maximum_records=10, record_schema=None): + def __init__(self, url=None, maximum_records=10, record_schema=None, sru_version='1.2'): self.url = url self.maximum_records = maximum_records - self.sru_version = '1.2' + self.sru_version = sru_version self.record_schema = record_schema def searchretrieve(self, query, start_record=1, requests_kwargs=None): From 873bfa8df4a7ad57f3e3aed71899b8e7be30d54e Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 4 Dec 2021 16:36:48 +0100 Subject: [PATCH 12/23] Allow arbitrary arguments for sruthi.explain call --- sruthi/sru.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sruthi/sru.py b/sruthi/sru.py index 583b482..0e3f2b5 100644 --- a/sruthi/sru.py +++ b/sruthi/sru.py @@ -16,6 +16,6 @@ def searchretrieve(url, query, **kwargs): return c.searchretrieve(**search_kwargs) -def explain(url): - c = client.Client(url) +def explain(url, **kwargs): + c = client.Client(url, **kwargs) return c.explain() From 8bb2b3913d38a71155fe6c93b95be62bffa0fdf0 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sat, 4 Dec 2021 16:37:09 +0100 Subject: [PATCH 13/23] Add SRU 1.1 example --- examples/sru1.1.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 examples/sru1.1.py diff --git a/examples/sru1.1.py b/examples/sru1.1.py new file mode 100644 index 0000000..0c9a5d8 --- /dev/null +++ b/examples/sru1.1.py @@ -0,0 +1,28 @@ +import sruthi +from pprint import pprint + +# check supported schemas of server +server_url = 'https://services.dnb.de/sru/dnb' + +# create sruthi client +client = sruthi.Client(server_url, record_schema='oai_dc', sru_version='1.1') + +explain = client.explain() +print(f'SRU version: {explain.sru_version}') +pprint(explain.server) +pprint(explain.config) +pprint(explain.index, depth=1) +pprint(explain.schema, depth=1) +pprint(explain.database) + + +print(20 * '=') +print('=') +print(f"= Record with schema: {client.record_schema}") +print('=') +print(20 * '=') +records = client.searchretrieve( + query='Zurich' +) +print(f'Total records: {records.count}') +pprint(records[0]) From c646cd7da5da37327500dfbb81e2f5c66b74b2b4 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Sun, 5 Dec 2021 23:48:34 +0100 Subject: [PATCH 14/23] Mention support of SRU 1.1 in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40935cc..d0bd301 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **sru**thi is a client for python to make [SRU requests (Search/Retrieve via URL)](http://www.loc.gov/standards/sru/). -Currently only SRU 1.2 is supported. +Currently only **SRU 1.1 and 1.2** is supported. ## Table of Contents From 08a14e301a93dbd14bfdc71e397f179fcda4e3c0 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 10:28:36 +0100 Subject: [PATCH 15/23] Update examples in README --- README.md | 74 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d0bd301..a197ccc 100644 --- a/README.md +++ b/README.md @@ -32,30 +32,38 @@ See the [`examples` directory](https://github.com/metaodi/sruthi/tree/master/exa ### `searchretrieve` operation ```python -import sruthi - -records = sruthi.searchretrieve('https://suche.staatsarchiv.djiktzh.ch/SRU/', query='Zurich') - -for record in records: - # print fields from schema - print(record['reference']) - print(record['title']) - print(record['date']) - print(record['extra']['link']) # extra record data is available at the 'extra' key -``` - -```python -# you can get more information at each step -import sruthi - -# note: records is an iterator -records = sruthi.searchretrieve('https://suche.staatsarchiv.djiktzh.ch/SRU/', query='Human') -print(records.sru_version) -print(records.count) - -for record in records: - print(record) - print(record['schema']) +>>> import sruthi +>>> records = sruthi.searchretrieve('https://suche.staatsarchiv.djiktzh.ch/SRU/', query='Brettspiel') +>>> print(records) +SearchRetrieveResponse(sru_version='1.2',count=500,next_start_record=11) +>>> print(records.count) +4 +>>> print(record[0]) +{'schema': 'isad', 'reference': 'PAT 2, 54 d, Nr. 253492', 'title': 'Schlumberger, Jean, Zürich: Brettspiel', 'date': '08.03.1946', 'descriptionlevel': 'Dossier', 'extent': None, 'creator': None, 'extra': {'score': '0.4', 'link': 'https://suche.staatsarchiv.djiktzh.ch/detail.aspx?Id=1114641', 'beginDateISO': '1946-03-08', 'beginApprox': '0', 'endDateISO': '1946-03-08', 'endApprox': '0', 'hasDigitizedItems': '0'}} +>>> +>>> for record in records: +... # print fields from schema +... print(record['reference']) +... print(record['title']) +... print(record['date']) +... print(record['extra']['link']) # extra record data is available at the 'extra' key +PAT 2, 54 d, Nr. 253492 +Schlumberger, Jean, Zürich: Brettspiel +08.03.1946 +https://suche.staatsarchiv.djiktzh.ch/detail.aspx?Id=1114641 +PAT 2, 54 d, Nr. 246025 +Frei, K. H., Weisslingen: Brettspiel +26.10.1945 +https://suche.staatsarchiv.djiktzh.ch/detail.aspx?Id=1114639 +DS 107.2.37 +UZH Magazin +Die Wissenschaftszeitschrift +2019 +https://suche.staatsarchiv.djiktzh.ch/detail.aspx?Id=4612939 +G I 1, Nr. 34 +Verordnung der Stadt Zürich betreffend die Erfüllung von Amtspflichten durch die Chorherren des Grossmünsterstifts +24.09.1485 +https://suche.staatsarchiv.djiktzh.ch/detail.aspx?Id=3796980 ``` The return value of `searchretrieve` is iterable, so you can easily loop over it. Or you can use indices to access elements, e.g. `records[1]` to get the second elemenet, or `records[-1]` to get the last one. @@ -70,13 +78,17 @@ for records in records[:5]: ### `explain` operation ```python -import sruthi - -info = sruthi.explain('https://suche.staatsarchiv.djiktzh.ch/SRU/') -print(info.server) -print(info.database) -print(info.index) -print(info.schema) +>>> import sruthi +>>> +>>> info = sruthi.explain('https://suche.staatsarchiv.djiktzh.ch/SRU/') +>>> print(info.server) +{'host': 'https://suche.staatsarchiv.djiktzh.ch/Sru', 'port': 80, 'database': 'sru'} +>>> print(info.database) +{'title': 'Staatsarchiv Zürich Online Search', 'description': 'Durchsuchen der Bestände des Staatsarchiv Zürichs.', 'contact': 'staatsarchivzh@ji.zh.ch'} +>>> print(info.index) +{'isad': {'title': 'Title', 'reference': 'Reference Code', 'date': 'Date', 'descriptionlevel': 'Level'}} +>>> print(info.schema) +{'isad': {'identifier': 'http://www.expertisecentrumdavid.be/xmlschemas/isad.xsd', 'name': 'isad', 'title': 'ISAD(G)'}} ``` ## Schemas From 5972361e3f7b53cfc5959c3cf05d8df7f7e3211a Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 10:52:37 +0100 Subject: [PATCH 16/23] Add SRU 1.1 example to README --- README.md | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a197ccc..fab2fdf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Currently only **SRU 1.1 and 1.2** is supported. * [Usage](#usage) * [`searchretrieve` operation](#searchretrieve-operation) * [`explain` operation](#explain-operation) + * [Request for SRU 1.1](#request-for-sru-11) * [Schemas](#schemas) * [Development](#development) * [Release](#release) @@ -79,18 +80,43 @@ for records in records[:5]: ```python >>> import sruthi ->>> >>> info = sruthi.explain('https://suche.staatsarchiv.djiktzh.ch/SRU/') ->>> print(info.server) +>>> info.server {'host': 'https://suche.staatsarchiv.djiktzh.ch/Sru', 'port': 80, 'database': 'sru'} ->>> print(info.database) +>>> info.database {'title': 'Staatsarchiv Zürich Online Search', 'description': 'Durchsuchen der Bestände des Staatsarchiv Zürichs.', 'contact': 'staatsarchivzh@ji.zh.ch'} ->>> print(info.index) +>>> info.index {'isad': {'title': 'Title', 'reference': 'Reference Code', 'date': 'Date', 'descriptionlevel': 'Level'}} ->>> print(info.schema) +>>> info.schema {'isad': {'identifier': 'http://www.expertisecentrumdavid.be/xmlschemas/isad.xsd', 'name': 'isad', 'title': 'ISAD(G)'}} ``` +### Request for SRU 1.1 + +By default sruthi uses SRU 1.2 to make requests, but you can specify the SRU version for each call or when you create a new client instance: + +```python +>>> import sruthi +>>> # create a client +>>> client = sruthi.Client( +... 'https://services.dnb.de/sru/dnb', +... record_schema='oai_dc', +... sru_version='1.1' +>>> ) +>>> records = client.searchretrieve(query="Zurich") +>>> records.count +8985 +>>> # ...or pass the version directly to the call +>>> records = sruthi.searchretrieve( +... 'https://services.dnb.de/sru/dnb', +... query="Zurich", +... record_schema='oai_dc', +... sru_version='1.1' +>>> ) +>>> records.count +8985 +``` + ## Schemas sruthi does not make any assumptions about the record data schema. From 70c34b6b371de2468bde0d33c337f3ae96433cf8 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 11:16:52 +0100 Subject: [PATCH 17/23] Add SRU 1.1 tests --- tests/client_test.py | 17 +++ tests/fixtures/response_single_sru11.xml | 14 +++ tests/fixtures/test_searchretrieve_sru11.xml | 120 +++++++++++++++++++ tests/response_test.py | 9 ++ 4 files changed, 160 insertions(+) create mode 100644 tests/fixtures/response_single_sru11.xml create mode 100644 tests/fixtures/test_searchretrieve_sru11.xml diff --git a/tests/client_test.py b/tests/client_test.py index a7d29e2..c3c548e 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -71,6 +71,23 @@ def test_searchretrieve_slice(self): self.assertEqual(res[1]['id'], '075640988') self.assertEqual(res[2]['id'], '113008686') + def test_searchretrieve_sru11(self): + client = Client('http://my-param.com/sru', sru_version='1.1') + + r = client.searchretrieve('test-query') + self.assertEqual(r.count, 790) + self.assertEqual(len(r.records), 12) + self.session_mock.return_value.get.assert_called_once_with( + 'http://my-param.com/sru', + params={ + 'operation': 'searchRetrieve', + 'version': '1.1', + 'query': 'test-query', + 'startRecord': 1, + 'maximumRecords': 10, + } + ) + def test_explain(self): client = Client('https://test.com/sru') info = client.explain() diff --git a/tests/fixtures/response_single_sru11.xml b/tests/fixtures/response_single_sru11.xml new file mode 100644 index 0000000..5e0b171 --- /dev/null +++ b/tests/fixtures/response_single_sru11.xml @@ -0,0 +1,14 @@ + +1.18985oai_dcxml + Moving Art : East Asian Objects and Their Journeys to the West + Thomsen, Hans Bjarne + Berlin : De Gruyter + 2024 + eng + 978-3-11-042629-8 : EUR 102.80 (AT) (freier Preis), EUR 99.95 (DE) (freier Preis), GBP 74.99 (GB) (freier Preis) + 3-11-042629-3 + http://www.degruyter.com/search?f_0=isbnissn&q_0=9783110426298&searchTitles=true + 1091078653 + 700 Künste, Bildende Kunst allgemein + 336 Seiten +121.1Zurich1oai_dc \ No newline at end of file diff --git a/tests/fixtures/test_searchretrieve_sru11.xml b/tests/fixtures/test_searchretrieve_sru11.xml new file mode 100644 index 0000000..9f41c1e --- /dev/null +++ b/tests/fixtures/test_searchretrieve_sru11.xml @@ -0,0 +1,120 @@ + +1.1790oai_dcxml + 2021,Nr.1 + 2021 + ger + 1229450084 + http://d-nb.info/102636051X +10oai_dcxml + 2021,Nr.2 + 2021 + ger + 1234718057 + http://d-nb.info/102636051X +11oai_dcxml + 2021,Nr.3 + 2021 + ger + 1238377068 + http://d-nb.info/102636051X +12oai_dcxml + 2021,Nr.4 + 2021 + ger + 1241982570 + http://d-nb.info/102636051X +13oai_dcxml + 2021,Nr.5 + 2021 + ger + 1245478710 + http://d-nb.info/102636051X +14oai_dcxml + Seeuferweg : der Zürichsee im Brennpunkt gegensätzlicher Interessen / Willy A. Rüegg + Rüegg, Willy A. [Verfasser] + Wädenswil : Stutz Medien AG + 2021 + ger + 978-3-85928-111-0 Festeinband : CHF 29.00 (freier Preis) + 3-85928-111-9 + 1231000384 + 333.7 Natürliche Ressourcen, Energie und Umwelt + 230 Seiten +15oai_dcxml + Singletrail Book 13: Zentralschweiz : Die 25 besten Mountainbike-Touren zwischen Gotthardpass und Einsiedeln beim Zürichsee / Thomas Giger + Giger, Thomas [Verfasser] + Chur : Swiss Sports Publishing + 2021 + eng + 978-3-905898-33-0 : EUR 25.00 (DE) (freier Preis), EUR 25.70 (AT) (freier Preis), CHF 29.00 (freier Preis) + 3-905898-33-0 + 1235086356 + 796 Sport + 160 Seiten +16oai_dcxml + Ulrich von Lilienfeld, "Concordantiae caritatis" / Martin Roland + Roland, Martin [Verfasser] + Heidelberg : arthistoricum.net + 2021 + ger + urn:nbn:de:bsz:16-artdok-75206 + http://nbn-resolving.de/urn:nbn:de:bsz:16-artdok-75206 + http://d-nb.info/1246820757/34 + http://archiv.ub.uni-heidelberg.de/artdok/volltexte/2021/7520 + 1246820757 + 740 Grafik, angewandte Kunst + lizenzfrei + Online-Ressource +17oai_dcxml + Vom Zürichsee / Peter Angst + Angst, Peter [Verfasser] + Münchenstein : Wolfbach + 2021 + ger + 978-3-906929-52-1 (Preis in Vorbereitung) + 3-906929-52-3 + 123156251X + 830 Deutsche Literatur + B Belletristik + 184 Seiten +18oai_dcxml + Wanderparadies Schweiz Wanderführer : 100 Top Touren: Berner Oberland, Bodensee und Zürichsee, Vierwaldstättersee, Graubünden und Engadin, Tessin, Wallis, Jura und Seeland + Hallwag Kümmerly + Frey + Kümmerly+Frey AG + Urtenen-Schönbühl : Kümmerly + Frey + 2021 + ger + 978-3-259-03766-9 Festeinband : EUR 24.90 (DE), EUR 24.90 (AT), CHF 24.90 (freier Preis) + 3-259-03766-7 + 1225885620 + 796 Sport + 252 Seiten +19oai_dcxml + Concordia / Tonio Hölscher + Hölscher, Tonio [Verfasser] + Heidelberg : Propylaeum + 2020 + ger + urn:nbn:de:bsz:16-propylaeumdok-49654 + http://nbn-resolving.de/urn:nbn:de:bsz:16-propylaeumdok-49654 + http://d-nb.info/1236410505/34 + http://archiv.ub.uni-heidelberg.de/propylaeumdok/volltexte/2020/4965 + 1236410505 + 730 Plastik, Numismatik, Keramik, Metallkunst + lizenzfrei + Online-Ressource +20oai_dcxml + Concordia apostolorum - eine gotische Skulptur in Liegnitz / Andrzej Grzybkowski + Grzybkowski, Andrzej [Verfasser] + Heidelberg : arthistoricum.net + 2020 + ger + urn:nbn:de:bsz:16-artdok-68892 + http://nbn-resolving.de/urn:nbn:de:bsz:16-artdok-68892 + http://d-nb.info/1211589692/34 + http://archiv.ub.uni-heidelberg.de/artdok/volltexte/2020/6889 + 1211589692 + 220 Bibel + lizenzfrei + Online-Ressource +21221.1Zürichsee1012oai_dc \ No newline at end of file diff --git a/tests/response_test.py b/tests/response_test.py index e857e2b..1970c2f 100644 --- a/tests/response_test.py +++ b/tests/response_test.py @@ -20,6 +20,15 @@ def test_response_single(self): self.assertEqual(res.sru_version, '1.2') self.assertIsNone(res.next_start_record) + def test_response_single_sru11(self): + data_loader = self._data_loader_mock(['response_single_sru11.xml']) + res = SearchRetrieveResponse(data_loader) + + self.assertEqual(res.count, 8985) + self.assertEqual(res.__length_hint__(), 8985) + self.assertEqual(res.sru_version, '1.1') + self.assertEqual(res.next_start_record, 2) + def test_response_multi(self): data_loader = self._data_loader_mock(['response_multiple_1.xml']) res = SearchRetrieveResponse(data_loader) From 80dcce3c4a2c1405019aaec20268360eae30b5a6 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 11:23:16 +0100 Subject: [PATCH 18/23] Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b55c94..57f3f0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project follows [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Add support for SRU 1.1 by passing `sru_version='1.1'` to the client or the operation calls. + ### Changed - Add MarcXchange (ISO 25577) namespace [#35](https://github.com/metaodi/sruthi/pull/35) (thanks [danmichaelo](https://github.com/danmichaelo)!) From 70b0c66654357ec6fa5c165c1e67b705b43e6260 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 14:13:23 +0100 Subject: [PATCH 19/23] Get rid of sru module --- sruthi/__init__.py | 21 +++++++++++++++++++-- sruthi/sru.py | 21 --------------------- 2 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 sruthi/sru.py diff --git a/sruthi/__init__.py b/sruthi/__init__.py index ea9355d..6b6cc2f 100644 --- a/sruthi/__init__.py +++ b/sruthi/__init__.py @@ -1,7 +1,24 @@ __version__ = '0.1.2' -__all__ = ['client', 'errors', 'response', 'sru', 'xmlparse'] +__all__ = ['client', 'errors', 'response', 'xmlparse'] from .errors import SruthiError, ServerIncompatibleError, SruError, NoMoreRecordsError # noqa from .errors import SruthiWarning, WrongNamespaceWarning # noqa -from .sru import searchretrieve, explain # noqa from .client import Client # noqa + + +def searchretrieve(url, query, **kwargs): + search_params = ['query', 'start_record', 'requests_kwargs'] + search_kwargs = {k: v for k, v in kwargs.items() if k in search_params} + search_kwargs['query'] = query + + # assume all others kwargs are for the client + client_kwargs = {k: v for k, v in kwargs.items() if k not in search_params} + client_kwargs['url'] = url + + c = Client(**client_kwargs) + return c.searchretrieve(**search_kwargs) + + +def explain(url, **kwargs): + c = Client(url, **kwargs) + return c.explain() diff --git a/sruthi/sru.py b/sruthi/sru.py deleted file mode 100644 index 0e3f2b5..0000000 --- a/sruthi/sru.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import client - - -def searchretrieve(url, query, **kwargs): - search_params = ['query', 'start_record', 'requests_kwargs'] - search_kwargs = {k: v for k, v in kwargs.items() if k in search_params} - search_kwargs['query'] = query - - # assume all others kwargs are for the client - client_kwargs = {k: v for k, v in kwargs.items() if k not in search_params} - client_kwargs['url'] = url - - c = client.Client(**client_kwargs) - return c.searchretrieve(**search_kwargs) - - -def explain(url, **kwargs): - c = client.Client(url, **kwargs) - return c.explain() From cb5faa181c663d96a9f12cf065756d67ffbe063b Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 14:15:14 +0100 Subject: [PATCH 20/23] Return dict-like object from `explain` operation --- CHANGELOG.md | 2 ++ README.md | 9 +++++++-- sruthi/client.py | 3 ++- sruthi/response.py | 15 +++++++++++++++ tests/sru_test.py | 4 +++- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f3f0a..f7e4501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed - Add MarcXchange (ISO 25577) namespace [#35](https://github.com/metaodi/sruthi/pull/35) (thanks [danmichaelo](https://github.com/danmichaelo)!) +- Moved `sru` module in `__init__` +- `explain` now returns a dict-like object (still with backwards-compatible attribute-access) ### Fixed - Fix parsing of non-standard namespaces for explain response diff --git a/README.md b/README.md index fab2fdf..9f7bf0b 100644 --- a/README.md +++ b/README.md @@ -78,16 +78,21 @@ for records in records[:5]: ### `explain` operation +The `explain` operation returns a dict-like object. +The values can either be accessed as keys `info['sru_version']` or as attributes `info.sru_version`. + ```python >>> import sruthi >>> info = sruthi.explain('https://suche.staatsarchiv.djiktzh.ch/SRU/') +>>> info +{'sru_version': '1.2', 'server': {'host': 'https://suche.staatsarchiv.djiktzh.ch/Sru', 'port': 80, 'database': 'sru'}, 'database': {'title': 'Staatsarchiv Zürich Online Search', 'description': 'Durchsuchen der Bestände des Staatsarchiv Zürichs.', 'contact': 'staatsarchivzh@ji.zh.ch'}, 'index': {'isad': {'title': 'Title', 'reference': 'Reference Code', 'date': 'Date', 'descriptionlevel': 'Level'}}, 'schema': {'isad': {'identifier': 'http://www.expertisecentrumdavid.be/xmlschemas/isad.xsd', 'name': 'isad', 'title': 'ISAD(G)'}}, 'config': {'maximumRecords': 99, 'defaults': {'numberOfRecords': 99}}} >>> info.server {'host': 'https://suche.staatsarchiv.djiktzh.ch/Sru', 'port': 80, 'database': 'sru'} >>> info.database {'title': 'Staatsarchiv Zürich Online Search', 'description': 'Durchsuchen der Bestände des Staatsarchiv Zürichs.', 'contact': 'staatsarchivzh@ji.zh.ch'} ->>> info.index +>>> info['index'] {'isad': {'title': 'Title', 'reference': 'Reference Code', 'date': 'Date', 'descriptionlevel': 'Level'}} ->>> info.schema +>>> info['schema'] {'isad': {'identifier': 'http://www.expertisecentrumdavid.be/xmlschemas/isad.xsd', 'name': 'isad', 'title': 'ISAD(G)'}} ``` diff --git a/sruthi/client.py b/sruthi/client.py index 0d249fb..7d15cf1 100644 --- a/sruthi/client.py +++ b/sruthi/client.py @@ -34,7 +34,8 @@ def explain(self, requests_kwargs=None): 'version': self.sru_version, } data_loader = DataLoader(self.url, params, requests_kwargs) - return response.ExplainResponse(data_loader) + explain_response = response.ExplainResponse(data_loader) + return explain_response.asdict() class DataLoader(object): diff --git a/sruthi/response.py b/sruthi/response.py index 788df76..2ce58d7 100644 --- a/sruthi/response.py +++ b/sruthi/response.py @@ -189,6 +189,16 @@ def __repr__(self): self.config, ) + def asdict(self): + return AttributeDict({ + 'sru_version': self.sru_version, + 'server': self.server, + 'database': self.database, + 'index': self.index, + 'schema': self.schema, + 'config': self.config, + }) + def _parse_content(self, xml): self._check_response_tag(xml, 'explainResponse') @@ -340,3 +350,8 @@ def _parse_index(self, xml): index[name.attrib['set']][name.text.strip()] = title return {k: dict(v) for k, v in dict(index).items()} + + +class AttributeDict(dict): + def __getattr__(self, attr): + return self[attr] diff --git a/tests/sru_test.py b/tests/sru_test.py index 44e9ca1..c0d97ff 100644 --- a/tests/sru_test.py +++ b/tests/sru_test.py @@ -81,7 +81,9 @@ def test_searchretrieve_with_requests_kwargs(self): def test_explain(self): info = sruthi.explain('http://test.com/sru/') - self.assertIsInstance(info, sruthi.response.ExplainResponse) + self.assertEqual(info.sru_version, '1.2'), + self.assertEqual(info['sru_version'], '1.2') + self.assertIsInstance(info, sruthi.response.AttributeDict) self.session_mock.return_value.get.assert_called_once_with( 'http://test.com/sru/', params={ From d9de6c79589733bd7e12bdab2c1428ab1f3ebea6 Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 14:51:30 +0100 Subject: [PATCH 21/23] Add Library of Congress example --- examples/library_of_congress.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 examples/library_of_congress.py diff --git a/examples/library_of_congress.py b/examples/library_of_congress.py new file mode 100644 index 0000000..607b272 --- /dev/null +++ b/examples/library_of_congress.py @@ -0,0 +1,23 @@ +import sruthi + +LOC_BASE = 'http://lx2.loc.gov:210/LCDB?' + +def loc_search(isbn, sru_base): + loc_lcc = None + try: + records = sruthi.searchretrieve(sru_base, query=isbn) + record = records[0] + fields = record.get('datafield', []) + for field in fields: + if field['tag'] != '050': + continue + if len(field.get('subfield', [])) > 0: + loc_lcc = (field['subfield'][0]['text']) + break + except: + return None + return loc_lcc + +isbn = '0062509470' +result = loc_search(isbn, LOC_BASE) +print(f"Tag 050 of ISBN '{isbn}': {result}") From c4887e806fb62633d51a1b4630afe3b2eacab64b Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 14:54:50 +0100 Subject: [PATCH 22/23] Release 1.0.0 --- CHANGELOG.md | 5 ++++- sruthi/__init__.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e4501..85b7a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project follows [Semantic Versioning](http://semver.org/). ## [Unreleased] + +## [1.0.0] - 2021-12-06 ### Added - Add support for SRU 1.1 by passing `sru_version='1.1'` to the client or the operation calls. @@ -74,7 +76,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - `Fixed` for any bug fixes. - `Security` to invite users to upgrade in case of vulnerabilities. -[Unreleased]: https://github.com/metaodi/sruthi/compare/v0.1.2...HEAD +[Unreleased]: https://github.com/metaodi/sruthi/compare/v1.0.0...HEAD +[1.0.0]: https://github.com/metaodi/sruthi/compare/v0.1.2...v1.0.0 [0.1.2]: https://github.com/metaodi/sruthi/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/metaodi/sruthi/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/metaodi/sruthi/compare/v0.0.5...v0.1.0 diff --git a/sruthi/__init__.py b/sruthi/__init__.py index 6b6cc2f..6ebbae3 100644 --- a/sruthi/__init__.py +++ b/sruthi/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.1.2' +__version__ = '1.0.0' __all__ = ['client', 'errors', 'response', 'xmlparse'] from .errors import SruthiError, ServerIncompatibleError, SruError, NoMoreRecordsError # noqa From 7533ffb37dc9ef22dc76076af6e31ccc201d619f Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 6 Dec 2021 15:06:02 +0100 Subject: [PATCH 23/23] Fix linting errors --- examples/library_of_congress.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/library_of_congress.py b/examples/library_of_congress.py index 607b272..036ce8e 100644 --- a/examples/library_of_congress.py +++ b/examples/library_of_congress.py @@ -1,7 +1,9 @@ import sruthi +import sys LOC_BASE = 'http://lx2.loc.gov:210/LCDB?' + def loc_search(isbn, sru_base): loc_lcc = None try: @@ -14,10 +16,12 @@ def loc_search(isbn, sru_base): if len(field.get('subfield', [])) > 0: loc_lcc = (field['subfield'][0]['text']) break - except: + except Exception as e: + print("Error: %s" % e, file=sys.stderr) return None return loc_lcc + isbn = '0062509470' result = loc_search(isbn, LOC_BASE) print(f"Tag 050 of ISBN '{isbn}': {result}")