python-epo-ops-client 3.1.3__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/CHANGELOG.md +14 -1
  2. python-epo-ops-client-3.1.3/LICENSE.txt → python-epo-ops-client-4.1.0/LICENSE +0 -25
  3. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/MANIFEST.in +2 -2
  4. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/Makefile +17 -14
  5. python-epo-ops-client-4.1.0/PKG-INFO +214 -0
  6. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/README.md +5 -5
  7. python-epo-ops-client-3.1.3/AUTHORS.md → python-epo-ops-client-4.1.0/docs/authors.md +12 -3
  8. python-epo-ops-client-4.1.0/docs/backlog.md +35 -0
  9. python-epo-ops-client-4.1.0/docs/contributing.md +87 -0
  10. python-epo-ops-client-4.1.0/docs/sandbox.md +89 -0
  11. python-epo-ops-client-4.1.0/epo_ops/__version__.py +6 -0
  12. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/api.py +8 -5
  13. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/cache/dogpile/dogpile.py +2 -1
  14. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/cache/dogpile/helpers.py +1 -1
  15. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/storages/sqlite.py +9 -4
  16. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/models.py +7 -4
  17. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/utils.py +2 -2
  18. python-epo-ops-client-4.1.0/pyproject.toml +95 -0
  19. python-epo-ops-client-4.1.0/python_epo_ops_client.egg-info/PKG-INFO +214 -0
  20. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/python_epo_ops_client.egg-info/SOURCES.txt +11 -6
  21. python-epo-ops-client-4.1.0/python_epo_ops_client.egg-info/requires.txt +22 -0
  22. python-epo-ops-client-4.1.0/setup.py +96 -0
  23. python-epo-ops-client-4.1.0/tests/test_api.py +117 -0
  24. python-epo-ops-client-4.1.0/tests/test_models.py +87 -0
  25. python-epo-ops-client-4.1.0/tests/test_ops_quota.py +67 -0
  26. python-epo-ops-client-4.1.0/tests/test_utils.py +23 -0
  27. python-epo-ops-client-3.1.3/CONTRIBUTING.md +0 -138
  28. python-epo-ops-client-3.1.3/PKG-INFO +0 -307
  29. python-epo-ops-client-3.1.3/TODOS.md +0 -23
  30. python-epo-ops-client-3.1.3/__version__.py +0 -1
  31. python-epo-ops-client-3.1.3/epo_ops/__version__.py +0 -1
  32. python-epo-ops-client-3.1.3/python_epo_ops_client.egg-info/PKG-INFO +0 -307
  33. python-epo-ops-client-3.1.3/python_epo_ops_client.egg-info/requires.txt +0 -3
  34. python-epo-ops-client-3.1.3/setup.py +0 -64
  35. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/__init__.py +0 -0
  36. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/exceptions.py +0 -0
  37. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/__init__.py +0 -0
  38. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/cache/__init__.py +0 -0
  39. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/cache/dogpile/__init__.py +0 -0
  40. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/middleware.py +0 -0
  41. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/__init__.py +0 -0
  42. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/storages/__init__.py +0 -0
  43. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/storages/storage.py +0 -0
  44. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/throttler.py +0 -0
  45. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/epo_ops/middlewares/throttle/utils.py +0 -0
  46. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/python_epo_ops_client.egg-info/dependency_links.txt +0 -0
  47. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/python_epo_ops_client.egg-info/not-zip-safe +0 -0
  48. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/python_epo_ops_client.egg-info/top_level.txt +0 -0
  49. {python-epo-ops-client-3.1.3 → python-epo-ops-client-4.1.0}/setup.cfg +0 -0
@@ -1,5 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.1.0 (2024-01-25)
4
+
5
+ - Configure HTTP client to use a network timeout of 10 seconds
6
+ - Verify support for Python 3.10, 3.11, and 3.12
7
+ - Project: Use `versioningit` for versioning
8
+ - Tests: Remove dependency on Apiary Mock Server API
9
+
10
+ ## 4.0.0 (2021-09-19)
11
+
12
+ - Upgrade dependencies
13
+ - Drop support for Python 2.7 and Python 3.5
14
+ - Add support for Python 3.9
15
+
3
16
  ## 3.1.3 (2020-09-23)
4
17
 
5
18
  - Upgrade dependencies
@@ -11,7 +24,7 @@
11
24
  ## 3.1.1 (2019-10-28)
12
25
 
13
26
  - GET instead of POST for family services, thanks to [amotl][]. See
14
- [#33](https://github.com/gsong/python-epo-ops-client/issues/33) for more
27
+ [#33](https://github.com/ip-tools/python-epo-ops-client/issues/33) for more
15
28
  info.
16
29
 
17
30
  ## 3.1.0 (2019-10-27)
@@ -174,28 +174,3 @@
174
174
  of your accepting any such warranty or additional liability.
175
175
 
176
176
  END OF TERMS AND CONDITIONS
177
-
178
- APPENDIX: How to apply the Apache License to your work.
179
-
180
- To apply the Apache License to your work, attach the following
181
- boilerplate notice, with the fields enclosed by brackets "[]"
182
- replaced with your own identifying information. (Don't include
183
- the brackets!) The text should be enclosed in the appropriate
184
- comment syntax for the file format. We also recommend that a
185
- file or class name and description of purpose be included on the
186
- same "printed page" as the copyright notice for easier
187
- identification within third-party archives.
188
-
189
- Copyright [yyyy] [name of copyright owner]
190
-
191
- Licensed under the Apache License, Version 2.0 (the "License");
192
- you may not use this file except in compliance with the License.
193
- You may obtain a copy of the License at
194
-
195
- http://www.apache.org/licenses/LICENSE-2.0
196
-
197
- Unless required by applicable law or agreed to in writing, software
198
- distributed under the License is distributed on an "AS IS" BASIS,
199
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
- See the License for the specific language governing permissions and
201
- limitations under the License.
@@ -1,5 +1,5 @@
1
1
  include *.md
2
- include *.txt
2
+ include LICENSE
3
3
  include Makefile
4
- include __version__.py
5
4
  recursive-include epo_ops *.py
5
+ recursive-include docs *.md
@@ -15,38 +15,41 @@ help: ## Display this help message
15
15
  @echo "Please use \`make <target>' where <target> is one of the following:"
16
16
  @perl -nle'print $& if m{^[\.a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}'
17
17
 
18
- seed-isort-config: ## Update known third party dependencies
19
- seed-isort-config --application-directories .:epo_ops --exclude setup.py
20
-
21
- pip-compile: ## Update compiled requirement files
22
- bin/pip-compile.sh
18
+ install-develop: ## Install project into sandbox.
19
+ pip install --use-pep517 --prefer-binary --editable=.[develop,docs,test]
23
20
 
24
21
  clean: clean-build clean-pyc
25
22
 
26
23
  clean-build:
27
24
  rm -fr build/
28
25
  rm -fr dist/
29
- rm -fr *.egg-info
30
26
 
31
27
  clean-pyc:
32
28
  find . -name '*.pyc' -exec rm -f {} +
33
29
  find . -name '*.pyo' -exec rm -f {} +
34
30
  find . -name '*~' -exec rm -f {} +
35
31
 
36
- lint: ## flake8 lint the project
37
- flake8 epo_ops tests
32
+ check: lint test ## Run linter and software tests
33
+ check-ci: lint test-ci ## Run linter and software tests on CI
34
+
35
+ lint: ## lint the project
36
+ ruff .
37
+ black --check .
38
+
39
+ format: ## Run code formatting
40
+ # Configure Ruff not to auto-fix (remove!):
41
+ # Ignore unused imports (F401), unused variables (F841), `print` statements (T201), and commented-out code (ERA001).
42
+ ruff --fix --ignore=ERA --ignore=F401 --ignore=F841 --ignore=T20 --ignore=ERA001 .
43
+ black .
38
44
 
39
45
  test: clean ## Run tests with virtualenv Python
40
- py.test -s -v --lf --cov-report term --cov epo_ops tests
46
+ py.test -s -v --lf --cov epo_ops tests --cov-report term-missing --cov-report xml
41
47
 
42
48
  test-ci: clean ## Run tests in CI environment with virtualenv Python
43
- py.test -v --cov epo_ops --cov-report term-missing
44
-
45
- tox: clean ## Run tests with all supported Python versions
46
- tox
49
+ py.test -v --cov epo_ops tests --cov-report term-missing --cov-report xml
47
50
 
48
51
  coverage: clean ## Check code coverage locally
49
- py.test -s -v --cov-report html --cov-report term --cov epo_ops tests
52
+ py.test -s -v --cov epo_ops tests --cov-report term-missing --cov-report xml --cov-report html
50
53
  open htmlcov/index.html
51
54
 
52
55
  release: clean # Package and upload a release to PyPI
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.1
2
+ Name: python-epo-ops-client
3
+ Version: 4.1.0
4
+ Summary: Python client for EPO OPS, the European Patent Office's Open Patent Services API.
5
+ Home-page: https://github.com/ip-tools/python-epo-ops-client
6
+ Download-URL: https://pypi.org/project/python-epo-ops-client/#files
7
+ Author: George Song
8
+ Author-email: george@monozuku.com
9
+ Maintainer: Andreas Motl
10
+ Maintainer-email: andreas.motl@ip-tools.org
11
+ Keywords: ops,epo,epo-ops,patent-data,patent-office,patent-data-api,european patent office,open patent services
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Natural Language :: English
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3.6
18
+ Classifier: Programming Language :: Python :: 3.7
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Software Development :: Libraries
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: dogpile.cache<1.2
29
+ Requires-Dist: importlib-metadata; python_version < "3.8"
30
+ Requires-Dist: python-dateutil<2.9
31
+ Requires-Dist: requests<3,>=2.27
32
+ Requires-Dist: six<2
33
+ Provides-Extra: develop
34
+ Requires-Dist: black<24; extra == "develop"
35
+ Requires-Dist: ruff==0.0.285; python_version >= "3.7" and extra == "develop"
36
+ Requires-Dist: twine<5; extra == "develop"
37
+ Requires-Dist: wheel<1; extra == "develop"
38
+ Provides-Extra: test
39
+ Requires-Dist: pytest<8; extra == "test"
40
+ Requires-Dist: pytest-cache<2; extra == "test"
41
+ Requires-Dist: pytest-cov<4.2; extra == "test"
42
+ Requires-Dist: python-dotenv<0.20; extra == "test"
43
+ Requires-Dist: responses<0.24; extra == "test"
44
+
45
+ # python-epo-ops-client
46
+
47
+ [![PyPI](https://img.shields.io/pypi/v/python-epo-ops-client)](https://pypi.org/project/python-epo-ops-client/)
48
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-epo-ops-client)](https://pypi.org/project/python-epo-ops-client/)
49
+ [![GHA](https://github.com/ip-tools/python-epo-ops-client/actions/workflows/main.yml/badge.svg)](https://github.com/ip-tools/python-epo-ops-client/actions/workflows/main.yml)
50
+ [![Codecov](https://codecov.io/gh/ip-tools/python-epo-ops-client/branch/main/graph/badge.svg)](https://codecov.io/gh/ip-tools/python-epo-ops-client)
51
+
52
+ python-epo-ops-client is an [Apache2 licensed][apache license] client library
53
+ for accessing the [European Patent Office][epo]'s ("EPO") [Open Patent
54
+ Services][ops] ("OPS") v.3.2 (based on [v 1.3.16 of the reference guide][ops guide]).
55
+
56
+ ```python
57
+ import epo_ops
58
+
59
+ client = epo_ops.Client(key='abc', secret='xyz') # Instantiate client
60
+ response = client.published_data( # Retrieve bibliography data
61
+ reference_type = 'publication', # publication, application, priority
62
+ input = epo_ops.models.Docdb('1000000', 'EP', 'A1'), # original, docdb, epodoc
63
+ endpoint = 'biblio', # optional, defaults to biblio in case of published_data
64
+ constituents = [] # optional, list of constituents
65
+ )
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Features
71
+
72
+ `python-epo-ops-client` abstracts away the complexities of accessing EPO OPS:
73
+
74
+ - Format the requests properly
75
+ - Bubble up quota problems as proper HTTP errors
76
+ - Handle token authentication and renewals automatically
77
+ - Handle throttling properly
78
+ - Add optional caching to minimize impact on the OPS servers
79
+
80
+ There are two main layers to `python-epo-ops-client`: Client and Middleware.
81
+
82
+ ### Client
83
+
84
+ The Client contains all the formatting and token handling logic and is what
85
+ you'll interact with mostly.
86
+
87
+ When you issue a request, the response is a [requests.Response][] object. If
88
+ `response.status_code != 200` then a `requests.HTTPError` exception will be
89
+ raised — it's your responsibility to handle those exceptions if you want to. The
90
+ one case that's handled is when the access token has expired: in this case, the
91
+ client will automatically handle the HTTP 400 status and renew the token.
92
+
93
+ Note that the Client does not attempt to interpret the data supplied by OPS, so
94
+ it's your responsibility to parse the XML or JSON payload for your own purpose.
95
+
96
+ The following custom exceptions are raised for cases when OPS quotas are
97
+ exceeded, they are all in the `epo_ops.exceptions` module and are subclasses of
98
+ `requests.HTTPError`, and therefore offer the same behaviors:
99
+
100
+ - IndividualQuotaPerHourExceeded
101
+ - RegisteredQuotaPerWeekExceeded
102
+
103
+ Again, it's up to you to parse the response and decide what to do.
104
+
105
+ Currently the Client knows how to issue request for the following services:
106
+
107
+ | Client method | API end point | throttle |
108
+ | ----------------------------------------------------------------------------- | --------------------- | --------- |
109
+ | `family(reference_type, input, endpoint=None, constituents=None)` | family | inpadoc |
110
+ | `image(path, range=1, extension='tiff')` | published-data/images | images |
111
+ | `number(reference_type, input, output_format)` | number-service | other |
112
+ | `published_data(reference_type, input, endpoint='biblio', constituents=None)` | published-data | retrieval |
113
+ | `published_data_search(cql, range_begin=1, range_end=25, constituents=None)` | published-data/search | search |
114
+ | `register(reference_type, input, constituents=['biblio'])` | register | other |
115
+ | `register_search(cql, range_begin=1, range_end=25)` | register/search | other |
116
+ | `register_search(cql, range_begin=1, range_end=25)` | register/search | other |
117
+
118
+ Bulk operations can be achieved by passing a list of valid models to the
119
+ published_data input field.
120
+
121
+ See the [OPS guide][] or use the [Developer's Area][] for more information on
122
+ how to use each service.
123
+
124
+ Please submit pull requests for the following services by enhancing the
125
+ `epo_ops.api.Client` class:
126
+
127
+ - Legal service
128
+
129
+ ### Middleware
130
+
131
+ All requests and responses are passed through each middleware object listed in
132
+ `client.middlewares`. Requests are processed in the order listed, and responses
133
+ are processed in the _reverse_ order.
134
+
135
+ Each middleware should subclass `middlewares.Middleware` and implement the
136
+ `process_request` and `process_response` methods.
137
+
138
+ There are two middleware classes out of the box: Throttler and Dogpile.
139
+ Throttler is in charge of the OPS throttling rules and will delay requests
140
+ accordingly. Dogpile is an optional cache which will cache all HTTP status 200,
141
+ 404, 405, and 413 responses.
142
+
143
+ By default, only the Throttler middleware is enabled, if you want to enable
144
+ caching:
145
+
146
+ ```python
147
+ import epo_ops
148
+
149
+ middlewares = [
150
+ epo_ops.middlewares.Dogpile(),
151
+ epo_ops.middlewares.Throttler(),
152
+ ]
153
+ client = epo_ops.Client(
154
+ key='key',
155
+ secret='secret',
156
+ middlewares=middlewares,
157
+ )
158
+ ```
159
+
160
+ You'll also need to install caching dependencies in your projects, such as `pip install dogpile.cache`.
161
+
162
+ _Note that caching middleware should be first in most cases._
163
+
164
+ #### Dogpile
165
+
166
+ Dogpile is based on (surprise) [dogpile.cache][]. By default it is instantiated
167
+ with a DBMBackend region with timeout of 2 weeks.
168
+
169
+ Dogpile takes three optional instantiation parameters:
170
+
171
+ - `region`: You can pass whatever valid [dogpile.cache Region][] you want to
172
+ backend the cache
173
+ - `kwargs_handlers`: A list of keyword argument handlers, which it will use to
174
+ process the kwargs passed to the request object in order to extract elements
175
+ for generating the cache key. Currently one handler is implemented (and
176
+ instantiated by default) to make sure that the range request header is part of
177
+ the cache key.
178
+ - `http_status_codes`: A list of HTTP status codes that you would like to have
179
+ cached. By default 200, 404, 405, and 413 responses are cached.
180
+
181
+ **Note**: dogpile.cache is not installed by default, if you want to use it, `pip install dogpile.cache` in your project.
182
+
183
+ #### Throttler
184
+
185
+ Throttler contains all the logic for handling different throttling scenarios.
186
+ Since OPS throttling is based on a one minute rolling window, we must persist
187
+ historical (at least for the past minute) throtting data in order to know what
188
+ the proper request frequency is. Each Throttler must be instantiated with a
189
+ Storage object.
190
+
191
+ ##### Storage
192
+
193
+ The Storage object is responsible for:
194
+
195
+ 1. Knowing how to update the historical record with each request
196
+ (`Storage.update()`), making sure to observe the one minute rolling window
197
+ rule.
198
+ 2. Calculating how long to wait before issuing the next request
199
+ (`Storage.delay_for()`).
200
+
201
+ Currently the only Storage backend provided is SQLite, but you can easily write
202
+ your own Storage backend (such as file, Redis, etc.). To use a custom Storage
203
+ type, just pass the Storage object when you're instantiating a Throttler object.
204
+ See `epo_ops.middlewares.throttle.storages.Storage` for more implementation
205
+ details.
206
+
207
+ [apache license]: http://www.apache.org/licenses/LICENSE-2.0
208
+ [developer's area]: https://developers.epo.org/ops-v3-2/apis
209
+ [dogpile.cache region]: http://dogpilecache.readthedocs.org/en/latest/api.html#module-dogpile.cache.region
210
+ [dogpile.cache]: https://bitbucket.org/zzzeek/dogpile.cache
211
+ [epo]: http://epo.org
212
+ [ops guide]: https://link.epo.org/web/ops_v3.2_documentation_-_version_1.3.19_en.pdf
213
+ [ops]: https://www.epo.org/searching-for-patents/data/web-services/ops.html
214
+ [requests.response]: http://requests.readthedocs.org/en/latest/user/advanced/#request-and-response-objects
@@ -2,12 +2,12 @@
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/python-epo-ops-client)](https://pypi.org/project/python-epo-ops-client/)
4
4
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-epo-ops-client)](https://pypi.org/project/python-epo-ops-client/)
5
- [![Travis.org](https://img.shields.io/travis/gsong/python-epo-ops-client)](https://travis-ci.org/gsong/python-epo-ops-client)
6
- [![Coveralls github](https://img.shields.io/coveralls/github/gsong/python-epo-ops-client)](https://coveralls.io/github/gsong/python-epo-ops-client)
5
+ [![GHA](https://github.com/ip-tools/python-epo-ops-client/actions/workflows/main.yml/badge.svg)](https://github.com/ip-tools/python-epo-ops-client/actions/workflows/main.yml)
6
+ [![Codecov](https://codecov.io/gh/ip-tools/python-epo-ops-client/branch/main/graph/badge.svg)](https://codecov.io/gh/ip-tools/python-epo-ops-client)
7
7
 
8
8
  python-epo-ops-client is an [Apache2 licensed][apache license] client library
9
9
  for accessing the [European Patent Office][epo]'s ("EPO") [Open Patent
10
- Services][ops] ("OPS") v.3.2 (based on [v 1.3.15 of the reference guide][ops guide]).
10
+ Services][ops] ("OPS") v.3.2 (based on [v 1.3.16 of the reference guide][ops guide]).
11
11
 
12
12
  ```python
13
13
  import epo_ops
@@ -165,6 +165,6 @@ details.
165
165
  [dogpile.cache region]: http://dogpilecache.readthedocs.org/en/latest/api.html#module-dogpile.cache.region
166
166
  [dogpile.cache]: https://bitbucket.org/zzzeek/dogpile.cache
167
167
  [epo]: http://epo.org
168
- [ops guide]: http://documents.epo.org/projects/babylon/eponet.nsf/0/F3ECDCC915C9BCD8C1258060003AA712/$FILE/ops_v3.2_documentation%20_version_1.3.4_en.pdf
169
- [ops]: http://www.epo.org/searching/free/ops.html
168
+ [ops guide]: https://link.epo.org/web/ops_v3.2_documentation_-_version_1.3.19_en.pdf
169
+ [ops]: https://www.epo.org/searching-for-patents/data/web-services/ops.html
170
170
  [requests.response]: http://requests.readthedocs.org/en/latest/user/advanced/#request-and-response-objects
@@ -1,14 +1,23 @@
1
- # Credits
1
+ # Authors
2
2
 
3
- ## Development Lead
3
+ The following people contributed to the software in one way or another,
4
+ thank you so much. The list is alphabetically sorted.
5
+
6
+ ## Development Leads
4
7
 
5
8
  - [George Song](https://github.com/gsong)
6
9
 
7
- ## Contributors
10
+ ## Maintainers
8
11
 
9
12
  - [Andreas Motl](https://github.com/amotl)
13
+
14
+ ## Contributors
15
+
16
+ - [Alexander Meinhardt Scheurer](https://github.com/BeneCollyridam)
10
17
  - [Daniel Blasco](https://github.com/dablak)
18
+ - [fe60](https://github.com/fe60)
11
19
  - [Felipe Eltermann](https://github.com/eltermann)
20
+ - [Geoffrey Cline](https://github.com/geoffcline)
12
21
  - [Hiro Kobashi](https://github.com/kobaski)
13
22
  - [Mike Matheson](https://github.com/mmath)
14
23
  - [Roberto Faga](https://github.com/rfaga)
@@ -0,0 +1,35 @@
1
+ # Backlog
2
+
3
+
4
+ ## Iteration +1
5
+
6
+ - Improve and clean up README
7
+ - Set up project documentation on Read the Docs
8
+ - Switch to `pyproject.toml`
9
+
10
+
11
+ ## Iteration +2
12
+
13
+ This is the content of the original `TODOS.md` file.
14
+
15
+ - Feature: Should the non-standard oAuth be coded as a requests plug-in?
16
+ - Dogpile caching
17
+ - Generate the key based on a SortedDict of some kind to make sure the exact
18
+ same request with different argument order are still a hit
19
+ - Additional services
20
+ - Legal service
21
+ - Makefile: Comma in `echo` statements?
22
+
23
+
24
+ ## Done
25
+
26
+ - Use new organization name `ip-tools`
27
+ - CI: Add GHA recipe, dissolve Travis configuration
28
+ - Dissolve `requirements` files, and inline them into `setup.py`
29
+ - Add support for Python 3.10 and 3.11
30
+ - Use `ruff` linter, dissolve `flake8` and `isort`
31
+ - Use `versioningit` for versioning, dissolve `bumpversion`
32
+ - Replace Apiary Mock server
33
+ https://github.com/ip-tools/python-epo-ops-client/issues/65
34
+ - Testing: Replace Apiary tests with monkeypatch? Or
35
+ <https://pypi.python.org/pypi/pytest-localserver>.
@@ -0,0 +1,87 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome, and they are greatly appreciated. Every bit
4
+ helps, and credit will always be given. You can contribute in many ways.
5
+
6
+ ## Types of Contributions
7
+
8
+ ### Report Bugs
9
+
10
+ Report bugs at <https://github.com/ip-tools/python-epo-ops-client/issues>.
11
+
12
+ If you are reporting a bug, please include:
13
+
14
+ - Your operating system name and version.
15
+ - Any details about your local setup that might be helpful in troubleshooting.
16
+ - Detailed steps to reproduce the bug.
17
+
18
+ ### Fix Bugs
19
+
20
+ Look through the GitHub issues for bugs. Anything tagged with "bug" is open to
21
+ whoever wants to fix it.
22
+
23
+ ### Implement Features
24
+
25
+ We are tracking all sorts of tasks within the [backlog](backlog.md) file and
26
+ as issues on GitHub. Just pick one, submit a corresponding patch, or start
27
+ a discussion around it. Anything tagged with "feature" is open to whoever wants
28
+ to implement it.
29
+
30
+ ### Write Documentation
31
+
32
+ python-epo-ops-client could always use more documentation, whether as part of
33
+ the official python-epo-ops-client docs, in docstrings, or even on the web in
34
+ blog posts, articles, and such.
35
+
36
+ ### Submit Feedback
37
+
38
+ The best way to send feedback is to file an issue at
39
+ https://github.com/ip-tools/python-epo-ops-client/issues.
40
+
41
+ If you are proposing a feature:
42
+
43
+ - Explain in detail how it would work.
44
+ - Keep the scope as narrow as possible, to make it easier to implement.
45
+ - Remember that this is a volunteer-driven project, and that contributions are
46
+ welcome. 😊
47
+
48
+ ## Get Started!
49
+
50
+ Ready to contribute? Here's how to set up `python-epo-ops-client` for local
51
+ development. Before going into the forking process, you should first [install
52
+ a development sandbox](sandbox.md).
53
+
54
+ 1. Fork the `python-epo-ops-client` repository on GitHub and clone your fork.
55
+ ```shell
56
+ git clone git@github.com:[your_name_here]/python-epo-ops-client.git
57
+ cd python-epo-ops-client/
58
+ ```
59
+
60
+ 4. Create a branch for local development:
61
+ ```shell
62
+ git switch -c <branchname>
63
+ ```
64
+ Now, make your changes within your working tree.
65
+
66
+ 5. After making changes to the code base, you may want to check that your
67
+ changes pass test and linting procedures. For that purpose, run
68
+ `make check`.
69
+
70
+ 6. Commit your changes and push your branch to GitHub.
71
+
72
+ ```shell
73
+ git add .
74
+ git commit -m "A detailed description of your changes."
75
+ git push origin <branchname>
76
+ ```
77
+
78
+ 7. Submit a pull request through the GitHub website.
79
+
80
+ ## Pull Request Guidelines
81
+
82
+ Before you submit a pull request, check that it meets these guidelines:
83
+
84
+ 1. The pull request should include tests.
85
+ 2. If the pull request adds functionality, the docs should be updated. Put your
86
+ new functionality into a function with a docstring, and add the feature to
87
+ the list in README.md.
@@ -0,0 +1,89 @@
1
+ # Development Sandbox
2
+
3
+ Ready to contribute? This page describes how to set up `python-epo-ops-client`
4
+ for local development.
5
+
6
+ In order to learn how to fork the project, and submit changes back to mainline
7
+ on behalf of a pull request, see the [contributing guidelines](contributing.md).
8
+
9
+
10
+ ## Sandbox Setup
11
+
12
+ 1. Acquire sources:
13
+ ```shell
14
+ git clone https://github.com/ip-tools/python-epo-ops-client
15
+ cd python-epo-ops-client/
16
+ ```
17
+
18
+ 2. Install your local copy into a Python virtualenv, in order to isolate
19
+ it from your system Python.
20
+ ```shell
21
+ python3 -m venv .venv
22
+ source .venv/bin/activate
23
+ ```
24
+
25
+ 3. Install required Python packages into development sandbox.
26
+ ```shell
27
+ make install-develop
28
+ ```
29
+
30
+
31
+ ## Software Tests
32
+
33
+
34
+ ### OPS Account Setup
35
+
36
+ Running the software tests require a working OPS account.
37
+
38
+ 1. [Sign up for an OPS user login with EPO][ops registration].
39
+ 2. Create an App at the OPS Console, which will provide you with a corresponding
40
+ pair of authentication credentials, the OPS application key and its secret.
41
+
42
+
43
+ ### Prerequisites
44
+
45
+ Before running the software tests, you will need to define the
46
+ `OPS_KEY`, and `OPS_SECRET` environment variables.
47
+
48
+ You can either define them interactively using `export VARNAME=VALUE`, or store
49
+ them into an `.env` file within the same directory you are running the tests from.
50
+ See `example.env` for a blueprint.
51
+
52
+ ```shell
53
+ export OPS_KEY=NKdGMmedZBGLRxTrUwCZMQCYp7Ak5a0u
54
+ export OPS_SECRET=v3vARPu7DFPEDB8i
55
+ ```
56
+
57
+ _Note that the OPS credentials have been invalidated for demonstration purposes._
58
+
59
+
60
+ ### Basics
61
+
62
+ ```shell
63
+ make check
64
+ ```
65
+
66
+ ⚠️ Note that the software tests need a working internet connection, in order to
67
+ access the OPS service.
68
+
69
+
70
+ ### Advanced Usage
71
+
72
+ In order to run either the linter, or the software tests exclusively,
73
+ use `make lint` vs. `make test`.
74
+
75
+ To focus on specific parts of the code base, you run a subset of the software
76
+ tests.
77
+
78
+ Run all tests in a specific module.
79
+ ```shell
80
+ pytest tests/test_utils.py
81
+ ```
82
+
83
+ Run all tests containing "api".
84
+ ```shell
85
+ pytest -k api
86
+ ```
87
+
88
+
89
+ [ops registration]: https://developers.epo.org/user/register
@@ -0,0 +1,6 @@
1
+ try:
2
+ from importlib.metadata import version
3
+ except ImportError: # pragma: nocover
4
+ from importlib_metadata import version # type: ignore[no-redef]
5
+
6
+ __version__ = version("python-epo-ops-client")
@@ -8,7 +8,7 @@ from requests.exceptions import HTTPError
8
8
 
9
9
  from . import exceptions
10
10
  from .middlewares import Throttler
11
- from .models import AccessToken, Request
11
+ from .models import NETWORK_TIMEOUT, AccessToken, Request
12
12
 
13
13
  log = logging.getLogger(__name__)
14
14
 
@@ -134,7 +134,9 @@ class Client(object):
134
134
  "Content-Type": "application/x-www-form-urlencoded",
135
135
  }
136
136
  payload = {"grant_type": "client_credentials"}
137
- response = requests.post(self.__auth_url__, headers=headers, data=payload)
137
+ response = requests.post(
138
+ self.__auth_url__, headers=headers, data=payload, timeout=NETWORK_TIMEOUT
139
+ )
138
140
  response.raise_for_status()
139
141
  self._access_token = AccessToken(response)
140
142
 
@@ -201,13 +203,13 @@ class Client(object):
201
203
  else:
202
204
  parts = parts_pre + parts_post
203
205
 
204
- return u"/".join(filter(None, parts))
206
+ return "/".join(filter(None, parts))
205
207
 
206
208
  # Service requests
207
209
  # info: {service, reference_type, input, endpoint, constituents}
208
210
  def _service_request(self, info):
209
211
  _input = info["input"]
210
- if type(_input) == list:
212
+ if isinstance(_input, list):
211
213
  data = "\n".join([i.as_api_input() for i in _input])
212
214
  info["input"] = _input[0]
213
215
  else:
@@ -235,7 +237,8 @@ class Client(object):
235
237
  if response.status_code != requests.codes.bad:
236
238
  return response
237
239
 
238
- message = ET.fromstring(response.content)
240
+ # FIXME: S314 Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents
241
+ message = ET.fromstring(response.content) # noqa: S314
239
242
  if message.findtext("message") == "invalid_access_token":
240
243
  self._acquire_token()
241
244
  response = self._make_request(response.request.url, response.request.body)
@@ -15,7 +15,8 @@ from .helpers import kwarg_range_header_handler
15
15
 
16
16
  log = logging.getLogger(__name__)
17
17
 
18
- DEFAULT_DBM_PATH = "/var/tmp/python-epo-ops-client/cache.dbm"
18
+ # FIXME: S108 Probable insecure usage of temporary file or directory: "/var/tmp/python-epo-ops-client/cache.dbm"
19
+ DEFAULT_DBM_PATH = "/var/tmp/python-epo-ops-client/cache.dbm" # noqa: S108
19
20
  DEFAULT_TIMEOUT = 60 * 60 * 24 * 7 * 2 # 2 weeks in seconds
20
21
 
21
22