From 6a05f27bbf98e658d4c7839ec9e279b49af1bf14 Mon Sep 17 00:00:00 2001 From: Matt Keanny Date: Sun, 28 Jan 2024 19:20:43 +0100 Subject: [PATCH 1/8] type annotation for family api, py3.8 --- epo_ops/api.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index 785c8c2..92433a2 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import logging from base64 import b64encode +from typing import List, Optional, Union from xml.etree import ElementTree as ET import requests @@ -8,7 +9,14 @@ from . import exceptions from .middlewares import Throttler -from .models import NETWORK_TIMEOUT, AccessToken, Request +from .models import ( + NETWORK_TIMEOUT, + AccessToken, + Docdb, + Epodoc, + Original, + Request, +) log = logging.getLogger(__name__) @@ -35,13 +43,32 @@ def __init__(self, key, secret, accept_type="xml", middlewares=None): self.secret = secret self._access_token = None - def family(self, reference_type, input, endpoint=None, constituents=None): + def family( + self, + reference_type: str, + input: Union[Docdb, Epodoc], + endpoint=None, + constituents: Optional[List[str]] = None, + ): + """ + Retrieves the patent numbers of the extended patent family related to the input (INPADOC family). + + Args: + reference_type (str): Any of "publication", "application", or "priority". + input (Epodoc or Docdb): The document number. Cannot be Original. + endpoint (optional): None. Not applicable for family service. + constituents (list[str], optional): List of 'biblio', 'legal' or both. + Defaults to None. + + Returns: + Response: a requests.Response object + """ url = self._make_request_url( dict( service=self.__family_path__, reference_type=reference_type, input=input, - endpoint=endpoint, + endpoint=None, constituents=constituents, use_get=True, ) From 1006f880dd344a03dbd7402ec0f7aed24cddebd0 Mon Sep 17 00:00:00 2001 From: Matt Keanny Date: Sun, 28 Jan 2024 20:07:05 +0100 Subject: [PATCH 2/8] removed unused parameter from family(), compliant with ops specs. --- epo_ops/api.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index 92433a2..e3a9a8f 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -47,7 +47,6 @@ def family( self, reference_type: str, input: Union[Docdb, Epodoc], - endpoint=None, constituents: Optional[List[str]] = None, ): """ @@ -56,7 +55,6 @@ def family( Args: reference_type (str): Any of "publication", "application", or "priority". input (Epodoc or Docdb): The document number. Cannot be Original. - endpoint (optional): None. Not applicable for family service. constituents (list[str], optional): List of 'biblio', 'legal' or both. Defaults to None. From 37fe93f93362823938cb579da35d529a713c0615 Mon Sep 17 00:00:00 2001 From: Matt Keanny Date: Sun, 28 Jan 2024 20:21:17 +0100 Subject: [PATCH 3/8] fixed linter error --- epo_ops/api.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index e3a9a8f..903087b 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -9,14 +9,7 @@ from . import exceptions from .middlewares import Throttler -from .models import ( - NETWORK_TIMEOUT, - AccessToken, - Docdb, - Epodoc, - Original, - Request, -) +from .models import NETWORK_TIMEOUT, AccessToken, Docdb, Epodoc, Request log = logging.getLogger(__name__) From 5e40b072c48a28beb4b2663205e480eb02db8ff9 Mon Sep 17 00:00:00 2001 From: mattkeanny Date: Mon, 29 Jan 2024 13:48:53 +0000 Subject: [PATCH 4/8] restored method signature for family(), added deprecation warning. --- epo_ops/api.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index 903087b..90e1c70 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import logging +import warnings from base64 import b64encode from typing import List, Optional, Union from xml.etree import ElementTree as ET @@ -40,20 +41,29 @@ def family( self, reference_type: str, input: Union[Docdb, Epodoc], + endpoint=None, constituents: Optional[List[str]] = None, - ): + ) -> requests.Response: """ Retrieves the patent numbers of the extended patent family related to the input (INPADOC family). Args: reference_type (str): Any of "publication", "application", or "priority". input (Epodoc or Docdb): The document number. Cannot be Original. + endpoint (optional): None. Not applicable for family service. constituents (list[str], optional): List of 'biblio', 'legal' or both. Defaults to None. Returns: - Response: a requests.Response object + requests.Response: a requests.Response object. """ + if endpoint is not None: + warnings.warn( + "The `endpoint` argument is not used in this context and will be removed.", + DeprecationWarning, + stacklevel=2, + ) + url = self._make_request_url( dict( service=self.__family_path__, From 912fae0a28115e5484c7fcc2f491a80943f9b33c Mon Sep 17 00:00:00 2001 From: mattkeanny Date: Mon, 29 Jan 2024 14:14:08 +0000 Subject: [PATCH 5/8] added example to docstring --- epo_ops/api.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/epo_ops/api.py b/epo_ops/api.py index 90e1c70..073b6eb 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -56,6 +56,19 @@ def family( Returns: requests.Response: a requests.Response object. + + Examples: + >>> response = client.family('publication', epo_ops.models.Epodoc('EP1000000')) + >>> response + + >>> len(response.text) + 8790 + + >>> response_with_constituents = client.family('publication', epo_ops.models.Epodoc('EP1000000'), None, ['biblio', 'legal']) + >>> response_with_constituents + + >>> len(response_with_constituents.text) + 160206 """ if endpoint is not None: warnings.warn( From 988c5ba0eea06cb13e0d046b2e6cd3bedb828331 Mon Sep 17 00:00:00 2001 From: mattkeanny Date: Mon, 29 Jan 2024 14:17:14 +0000 Subject: [PATCH 6/8] minor reformatting of docstring --- epo_ops/api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index 073b6eb..a02c4d2 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -51,20 +51,20 @@ def family( reference_type (str): Any of "publication", "application", or "priority". input (Epodoc or Docdb): The document number. Cannot be Original. endpoint (optional): None. Not applicable for family service. - constituents (list[str], optional): List of 'biblio', 'legal' or both. + constituents (list[str], optional): List of "biblio", "legal" or both. Defaults to None. Returns: requests.Response: a requests.Response object. Examples: - >>> response = client.family('publication', epo_ops.models.Epodoc('EP1000000')) + >>> response = client.family("publication", epo_ops.models.Epodoc("EP1000000")) >>> response >>> len(response.text) 8790 - >>> response_with_constituents = client.family('publication', epo_ops.models.Epodoc('EP1000000'), None, ['biblio', 'legal']) + >>> response_with_constituents = client.family("publication", epo_ops.models.Epodoc("EP1000000"), None, ["biblio", "legal"]) >>> response_with_constituents >>> len(response_with_constituents.text) From 8932d839053ce326170296dc43f0e0520668e6bb Mon Sep 17 00:00:00 2001 From: mattkeanny Date: Tue, 30 Jan 2024 21:32:21 +0000 Subject: [PATCH 7/8] added type hints to public api of ops client --- epo_ops/api.py | 109 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index a02c4d2..e58446a 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -10,7 +10,14 @@ from . import exceptions from .middlewares import Throttler -from .models import NETWORK_TIMEOUT, AccessToken, Docdb, Epodoc, Request +from .models import ( + NETWORK_TIMEOUT, + AccessToken, + Docdb, + Epodoc, + Original, + Request, +) log = logging.getLogger(__name__) @@ -51,7 +58,7 @@ def family( reference_type (str): Any of "publication", "application", or "priority". input (Epodoc or Docdb): The document number. Cannot be Original. endpoint (optional): None. Not applicable for family service. - constituents (list[str], optional): List of "biblio", "legal" or both. + constituents (List[str], optional): List of "biblio", "legal" or both. Defaults to None. Returns: @@ -89,10 +96,32 @@ def family( ) return self._make_request(url, None, params=input.as_api_input(), use_get=True) - def image(self, path, range=1, document_format="application/tiff"): + def image( + self, path: str, range: int = 1, document_format: str = "application/tiff" + ) -> requests.Response: + """ + Retrieve the image page for a given path, one page at a time. + The path needs to be retrieved from the xml resulting from a prior inquiry using + the published_data() service with the endpoint='images'. + """ return self._image_request(path, range, document_format) - def number(self, reference_type, input, output_format): + def number( + self, + reference_type: str, + input: Union[Original, Docdb, Epodoc], + output_format: Union[Original, Docdb, Epodoc], + ) -> requests.Response: + """ + This service converts a patent number from one input format into another format. + + Use-cases: Given that other OPS services use only the Epodoc or Docdb format, + the general use-case of this method would be to convert the Original format + into either the Docdb or the Epodoc format. + + Note: It is especially important to include the date in number requests whenever + possible because number formatting may vary depending on the date. + """ possible_conversions = { "docdb": ["original", "epodoc"], "epodoc": ["original"], @@ -114,8 +143,32 @@ def number(self, reference_type, input, output_format): ) def published_data( - self, reference_type, input, endpoint="biblio", constituents=None - ): + self, + reference_type: str, + input: Union[Docdb, Epodoc], + endpoint="biblio", + constituents: Optional[List[str]] = None, + ) -> requests.Response: + """ + Retrieval service for published data. + + Args: + reference_type (str): Any of "publication", "application", or "priority". + input (Epodoc or Docdb): The document number as a Epodoc or Docdb data object. + endpoint (str, optional): "biblio", "equivalents", "abstract", "claims", "description", + "fulltext", "images". Defaults to "biblio". + constituents (list[str], optional): List of "biblio", "abstract", "images", "full cycle". + + Returns: + requests.Response: a requests.Response object + + Note: + 1) input cannot be a models.Original + 2) only the endpoint "biblio" or "equivalents" use the constituents parameter. + 3) the images and fulltext retrieval require a two-step process: inquiry, then retrieval, e.g. + - client.published_data(..., endpoint='images',...) to retrieve the image path, then + - client.image(path=...) + """ return self._service_request( dict( service=self.__published_data_path__, @@ -127,8 +180,16 @@ def published_data( ) def published_data_search( - self, cql, range_begin=1, range_end=25, constituents=None - ): + self, + cql: str, + range_begin: int = 1, + range_end: int = 25, + constituents: Optional[List[str]] = None, + ) -> requests.Response: + """ + Performs a bibliographic search ussing common query language (CQL) to retrieve the data. + Possible constituents: "abstract", "biblio" and/or "full-cycle". + """ range = dict(key="X-OPS-Range", begin=range_begin, end=range_end) return self._search_request( dict( @@ -138,7 +199,24 @@ def published_data_search( range, ) - def register(self, reference_type, input, constituents=None): + def register( + self, + reference_type: str, + input: Epodoc, + constituents: Optional[List[str]] = None, + ) -> requests.Response: + """ + Provides the interface for the European Patent Register online service for retrieving all + the publicly available information on published European patent applications and + international PCT applications designating the EPO as they pass through the grant procedure. + + Possible constituents: "biblio", "events", "procedural-steps" or "upp". + + Notes: + 1) Only the Epodoc input format is supported + 2) the default behaviour of the register retrieval is biblio, so you don't have to add the + biblio constituent if you want to retrieve only bibliographic data. + """ # TODO: input can only be Epodoc, not Docdb constituents = constituents or ["biblio"] return self._service_request( @@ -150,7 +228,18 @@ def register(self, reference_type, input, constituents=None): ) ) - def register_search(self, cql, range_begin=1, range_end=25): + def register_search( + self, cql: str, range_begin: int = 1, range_end: int = 25 + ) -> requests.Response: + """ + Use this service to find specific register data + that is part of the public aspect of the patent lifecycle. + + Example: + >>> response = client.register_search(cql="pa=IBM", range_begin=1, range_end=25) + >>> print(response.text) + + """ range = dict(key="Range", begin=range_begin, end=range_end) return self._search_request( {"service": self.__register_search_path__}, cql, range From 6baeba6ce7dd169b83ba07a60c2649890c965fd6 Mon Sep 17 00:00:00 2001 From: mattkeanny Date: Sat, 3 Feb 2024 11:33:17 +0000 Subject: [PATCH 8/8] added examples to docstring --- epo_ops/api.py | 57 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/epo_ops/api.py b/epo_ops/api.py index e58446a..042b12c 100644 --- a/epo_ops/api.py +++ b/epo_ops/api.py @@ -102,7 +102,15 @@ def image( """ Retrieve the image page for a given path, one page at a time. The path needs to be retrieved from the xml resulting from a prior inquiry using - the published_data() service with the endpoint='images'. + the published_data() service with the 'endpoint="images"' argument. + + Args: + path (str): contained in the 'link' attribute of the document instance element (inquiry xml). + range (int, optional): the number of the image page to be fetched. Defaults to 1. + document_format (str, optional): depends on the inquiry response. Defaults to "application/tiff". + + Returns: + requests.Response: a requests.Response object. """ return self._image_request(path, range, document_format) @@ -110,17 +118,50 @@ def number( self, reference_type: str, input: Union[Original, Docdb, Epodoc], - output_format: Union[Original, Docdb, Epodoc], + output_format: str, ) -> requests.Response: """ This service converts a patent number from one input format into another format. - Use-cases: Given that other OPS services use only the Epodoc or Docdb format, - the general use-case of this method would be to convert the Original format - into either the Docdb or the Epodoc format. + Args: + reference_type (str): Any of "publication", "application", or "priority". + input (Original, Epodoc or Docdb): The document number as a data object. + output_format (str): Any of "original", "epodoc" or "docdb". - Note: It is especially important to include the date in number requests whenever - possible because number formatting may vary depending on the date. + Returns: + requests.Response: a requests.Response object. + + + Examples: + # from JP original to docdb + >>> response = client.number( + "application", + Original(number="2006-147056", country_code="JP", kind_code="A", date="20060526"), + "docdb, + ) + + # from US original to epodoc + >>> response = client.number( + "application", + Original("08/921,321", "US", "A", "19970829"), + "epodoc", + ) + + # from PCT original to docdb + >>> response = client.number( + "application", + Original("PCT/GB02/04635", date="19970829"), + "docdb", + ) + + Use-cases: + Given that other OPS services use only the Epodoc or Docdb format, + the general use-case of this method is to convert the Original format + into either the Docdb or the Epodoc format. + + Note: + It is especially important to include the date of publication in the input + whenever possible because number formatting may vary depending on the date. """ possible_conversions = { "docdb": ["original", "epodoc"], @@ -160,7 +201,7 @@ def published_data( constituents (list[str], optional): List of "biblio", "abstract", "images", "full cycle". Returns: - requests.Response: a requests.Response object + requests.Response: a requests.Response object. Note: 1) input cannot be a models.Original