From 0d9aa2f2f654892aa294ea20a7b1e4319a3bcdd1 Mon Sep 17 00:00:00 2001 From: rahul-kumi Date: Wed, 20 Mar 2019 13:40:26 +0530 Subject: [PATCH 1/4] normalize response variable naming --- olclient/openlibrary.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/olclient/openlibrary.py b/olclient/openlibrary.py index 51e7af83..e3aa9ec5 100644 --- a/olclient/openlibrary.py +++ b/olclient/openlibrary.py @@ -198,8 +198,8 @@ def editions(self): """ url = '%s/works/%s/editions.json' % (self.OL.base_url, self.olid) try: - r = self.OL.session.get(url) - editions = r.json().get('entries', []) + response = self.OL.session.get(url) + editions = response.json().get('entries', []) except Exception as e: return [] @@ -246,12 +246,12 @@ def add_author(self, author): def add_bookcover(self, url): _url = '%s/works/%s/-/add-cover' % (self.OL.base_url, self.olid) - r = self.OL.session.post(_url, files={ + response = self.OL.session.post(_url, files={ 'file': '', 'url': url, 'upload': 'submit' }) - return r + return response def add_subject(self, subject, comment=''): return self.add_subjects([subject], comment) @@ -267,8 +267,8 @@ def add_subjects(self, subjects, comment=''): def rm_subjects(self, subjects, comment=''): url = self.OL.base_url + "/works/" + self.olid + ".json" - r = self.OL.session.get(url) - data = r.json() + response = self.OL.session.get(url) + data = response.json() data['_comment'] = comment or ('rm subjects: %s' % ', '.join(subjects)) data['subjects'] = list(set(data['subjects']) - set(subjects)) return self.OL.session.put(url, json.dumps(data)) @@ -296,8 +296,8 @@ def get(cls, olid): >>> ol.Work.get('OL26278461W') """ path = '/works/%s.json' % olid - r = cls.OL._get_ol_response(path) - return cls(olid, **r.json()) + response = cls.OL._get_ol_response(path) + return cls(olid, **response.json()) @classmethod def search(cls, title=None, author=None): @@ -430,12 +430,12 @@ def add_bookcover(self, url): """Adds a cover image to this edition""" metadata = self.get_metadata('OLID', self.olid) _url = '%s/add-cover' % metadata['preview_url'] - r = self.OL.session.post(_url, files={ + response = self.OL.session.post(_url, files={ 'file': '', 'url': url, 'upload': 'submit' }) - return r + return response def save(self, comment): """Saves this edition back to Open Library using the JSON API.""" @@ -719,9 +719,9 @@ def get(cls, olid): >>> ol.Author.get('OL39307A') """ path = '/authors/%s.json' % olid - r = cls.OL._get_ol_response(path) + response = cls.OL._get_ol_response(path) try: - data = r.json() + data = response.json() olid = cls.OL._extract_olid_from_url(data.pop('key', u''), url_type='authors') except: From f8847aae786ab499b93eed4ab815ff32b4c01112 Mon Sep 17 00:00:00 2001 From: rahul-kumi Date: Wed, 20 Mar 2019 19:31:58 +0530 Subject: [PATCH 2/4] update README.md with updated CLI prompts --- README.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8ec1d01b..54cee614 100644 --- a/README.md +++ b/README.md @@ -120,26 +120,31 @@ Installing the openlibrary-client library will also install the `ol` command lin ``` $ ol -usage: ol [-h] [-v] [--configure] [--get-work] [--get-book] [--get-olid] - [--olid OLID] [--isbn ISBN] [--create CREATE] [--title TITLE] +usage: ol [-h] [-v] [--configure] [--get-work] [--get-author-works] + [--get-book] [--get-olid] [--olid OLID] [--isbn ISBN] + [--create CREATE] [--title TITLE] [--author-name AUTHOR_NAME] [--baseurl BASEURL] [--email EMAIL] olclient optional arguments: - -h, --help show this help message and exit - -v Displays the currently installed version of ol - --configure Configure ol client with credentials - --get-work Get a work by --title, --olid - --get-book Get a book by --isbn, --olid - --get-olid Get an olid by --title or --isbn - --olid OLID Specify an olid as an argument - --isbn ISBN Specify an isbn as an argument - --create CREATE Create a new work from json - --title TITLE Specify a title as an argument - --baseurl BASEURL Which OL backend to use - --email EMAIL An IA email for requests which require authentication. - You will be prompted discretely for a password + -h, --help show this help message and exit + -v Displays the currently installed version of ol + --configure Configure ol client with credentials + --get-work Get a work by --title, --olid + --get-author-works Get a works of an author providing author's --olid, + --author-name + --get-book Get a book by --isbn, --olid + --get-olid Get an olid by --title or --isbn + --olid OLID Specify an olid as an argument + --isbn ISBN Specify an isbn as an argument + --create CREATE Create a new work from json + --title TITLE Specify a title as an argument + --author-name AUTHOR_NAME + Specify an author as an argument + --baseurl BASEURL Which OL backend to use + --email EMAIL An IA email for requests which require authentication. + You will be prompted discretely for a password ``` You can create a new work from the command line using the following syntax. It's almost identical to the olclient.common.Book object construction, except instead of providing an Author object, you instead pass a key for "author" and a corresponding value: From 5c4588f5b9ec14ae0d5b3b9eb87a9b723f550a9f Mon Sep 17 00:00:00 2001 From: rahul-kumi Date: Thu, 21 Mar 2019 11:26:28 +0530 Subject: [PATCH 3/4] handle errors with descriptive prompt --- olclient/openlibrary.py | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/olclient/openlibrary.py b/olclient/openlibrary.py index e3aa9ec5..1249c545 100644 --- a/olclient/openlibrary.py +++ b/olclient/openlibrary.py @@ -83,11 +83,24 @@ def login(self, credentials): @backoff.on_exception(on_giveup=err, **self.BACKOFF_KWARGS) def _login(url, headers, data): """Makes best effort to perform request w/ exponential backoff""" - return self.session.post(url, data=data, headers=headers) + try: + return self.session.post(url, data=data, headers=headers) + except requests.exceptions.ConnectionError as e: + print(str(e) + '\n' + 'Login request failed to process due to connectivity issue.') + except requests.exceptions.Timeout as e: + print(str(e) + '\n' + 'Login request exceeded timeout limit to return response.') + except requests.exceptions.HTTPError as e: + if e.response.status_code == 404: + error_message = 'The generated URL does not seem to point to an available resource.' + else: + error_message = 'An invalid HTTP response was returned.' + print(str(e) + '\n' + error_message) + response = _login(url, headers, data) - if not self.session.cookies: + # if response: + if not (self.session.cookies and response): raise ValueError("No cookie set") def validate(self, doc, schema_name): @@ -135,9 +148,20 @@ def save_many(self, docs, comment): @backoff.on_exception(on_giveup=err, **BACKOFF_KWARGS) def _get_ol_response(self, path): """Makes best effort to perform request w/ exponential backoff""" - response = self.session.get(self.base_url + path) - response.raise_for_status() - return response + try: + response = self.session.get(self.base_url + path) + response.raise_for_status() + return response + except requests.exceptions.ConnectionError as e: + print(str(e) + '\n' + 'Request failed to process due to connectivity issue.') + except requests.exceptions.Timeout as e: + print(str(e) + '\n' + 'Request exceeded timeout limit to return response.') + except requests.exceptions.HTTPError as e: + if e.response.status_code == 404: + error_message = 'The generated URL does not seem to point to an available resource.' + else: + error_message = 'An invalid HTTP response was returned.' + print(str(e) + '\n' + error_message) @property def Work(ol_self): From c0d06e28a0bd4042249d9621b843dd0654a6c900 Mon Sep 17 00:00:00 2001 From: rahul-kumi Date: Thu, 16 May 2019 07:12:59 +0530 Subject: [PATCH 4/4] intermediate commit --- olclient/openlibrary.py | 84 +++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/olclient/openlibrary.py b/olclient/openlibrary.py index 1249c545..0a09d379 100644 --- a/olclient/openlibrary.py +++ b/olclient/openlibrary.py @@ -47,6 +47,28 @@ class OpenLibrary(object): """ VALID_IDS = ['isbn_10', 'isbn_13', 'lccn', 'ocaid'] + + def err_descriptor_ConnectionError(e): + logger.exception('Request failed to process due to connectivity issues.') + def err_descriptor_TimeoutError(e): + logger.exception('Request exceeded timeout limit to return response.') + def err_descriptor_HTTPError(e): + print(e) + logger.exception('An invalid HTTP response was returned.') + + def err_descriptor(e): + error_message = '' + if e is requests.exceptions.ConnectionError: + error_message = 'Request failed to process due to connectivity issue.' + if e is requests.exceptions.Timeout: + error_message = 'Request exceeded timeout limit to return response.' + if e is requests.exceptions.HTTPError : + if e.response.status_code == 404: + error_message = 'The generated URL does not seem to point to an available resource.' + else: + error_message = 'An invalid HTTP response was returned.' + return error_message + BACKOFF_KWARGS = { 'wait_gen': backoff.expo, 'exception': requests.exceptions.RequestException, @@ -80,21 +102,22 @@ def login(self, credentials): url = self.base_url + '/account/login' err = lambda e: logger.exception("Error at login: %s", e) - @backoff.on_exception(on_giveup=err, **self.BACKOFF_KWARGS) + @backoff.on_exception(on_giveup= err, **self.BACKOFF_KWARGS) + def _login(url, headers, data): """Makes best effort to perform request w/ exponential backoff""" - try: - return self.session.post(url, data=data, headers=headers) - except requests.exceptions.ConnectionError as e: - print(str(e) + '\n' + 'Login request failed to process due to connectivity issue.') - except requests.exceptions.Timeout as e: - print(str(e) + '\n' + 'Login request exceeded timeout limit to return response.') - except requests.exceptions.HTTPError as e: - if e.response.status_code == 404: - error_message = 'The generated URL does not seem to point to an available resource.' - else: - error_message = 'An invalid HTTP response was returned.' - print(str(e) + '\n' + error_message) + # try: + return self.session.post(url, data=data, headers=headers) + # except requests.exceptions.ConnectionError as e: + # print(str(e) + '\n' + 'Login request failed to process due to connectivity issue.') + # except requests.exceptions.Timeout as e: + # print(str(e) + '\n' + 'Login request exceeded timeout limit to return response.') + # except requests.exceptions.HTTPError as e: + # if e.response.status_code == 404: + # error_message = 'The generated URL does not seem to point to an available resource.' + # else: + # error_message = 'An invalid HTTP response was returned.' + # print(str(e) + '\n' + error_message) response = _login(url, headers, data) @@ -144,24 +167,27 @@ def save_many(self, docs, comment): doc_json = [doc.json() for doc in docs] return self.session.post('%s/api/save_many' % self.base_url, json.dumps(doc_json), headers=headers) - err = lambda e: logger.exception("Error retrieving OpenLibrary response: %s", e) - @backoff.on_exception(on_giveup=err, **BACKOFF_KWARGS) + # err = lambda e: logger.exception("Error retrieving OpenLibrary response: %s", e) + # @backoff.on_exception(on_giveup=err, **BACKOFF_KWARGS) + @backoff.on_exception(wait_gen=backoff.expo,exception=requests.exceptions.ConnectionError, max_tries= 5, on_giveup=err_descriptor_ConnectionError) + @backoff.on_exception(wait_gen=backoff.expo,exception=requests.exceptions.Timeout, max_tries= 5, on_giveup=err_descriptor_TimeoutError) + @backoff.on_exception(wait_gen=backoff.expo,exception=requests.exceptions.HTTPError, max_tries= 5, on_giveup=err_descriptor_HTTPError) def _get_ol_response(self, path): """Makes best effort to perform request w/ exponential backoff""" - try: - response = self.session.get(self.base_url + path) - response.raise_for_status() - return response - except requests.exceptions.ConnectionError as e: - print(str(e) + '\n' + 'Request failed to process due to connectivity issue.') - except requests.exceptions.Timeout as e: - print(str(e) + '\n' + 'Request exceeded timeout limit to return response.') - except requests.exceptions.HTTPError as e: - if e.response.status_code == 404: - error_message = 'The generated URL does not seem to point to an available resource.' - else: - error_message = 'An invalid HTTP response was returned.' - print(str(e) + '\n' + error_message) + # try: + response = self.session.get(self.base_url + path) + response.raise_for_status() + return response + # except requests.exceptions.ConnectionError as e: + # raise Exception(str(e) + '\n' + 'Request failed to process due to connectivity issue.') + # except requests.exceptions.Timeout as e: + # raise Exception(str(e) + '\n' + 'Request exceeded timeout limit to return response.') + # except requests.exceptions.HTTPError as e: + # if e.response.status_code == 404: + # error_message = 'The generated URL does not seem to point to an available resource.' + # else: + # error_message = 'An invalid HTTP response was returned.' + # raise Exception(str(e) + '\n' + error_message) @property def Work(ol_self):