python-epo-ops-client 4.2.1__tar.gz → 4.2.2__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.
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/CHANGELOG.md +5 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/Makefile +1 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/PKG-INFO +16 -11
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/README.md +5 -3
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/api.py +15 -9
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/pyproject.toml +52 -67
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/PKG-INFO +16 -11
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/SOURCES.txt +1 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/requires.txt +7 -6
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/setup.py +13 -10
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/tests/test_api.py +8 -0
- python_epo_ops_client-4.2.2/tests/test_raise_for_status.py +67 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/LICENSE +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/MANIFEST.in +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/docs/authors.md +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/docs/backlog.md +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/docs/contributing.md +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/docs/release.md +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/docs/sandbox.md +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/__version__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/exceptions.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/cache/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/cache/dogpile/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/cache/dogpile/dogpile.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/cache/dogpile/helpers.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/middleware.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/storages/__init__.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/storages/sqlite.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/storages/storage.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/throttler.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/utils.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/models.py +1 -1
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/utils.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/dependency_links.txt +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/not-zip-safe +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/top_level.txt +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/setup.cfg +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/tests/test_models.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/tests/test_ops_quota.py +0 -0
- {python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/tests/test_utils.py +0 -0
|
@@ -37,6 +37,7 @@ lint: ## lint the project
|
|
|
37
37
|
ruff format --check .
|
|
38
38
|
|
|
39
39
|
format: ## Run code formatting
|
|
40
|
+
pyproject-fmt --keep-full-version pyproject.toml
|
|
40
41
|
ruff format .
|
|
41
42
|
# Configure Ruff not to auto-fix (remove!):
|
|
42
43
|
# Ignore unused imports (F401), unused variables (F841), `print` statements (T201), and commented-out code (ERA001).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-epo-ops-client
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.2
|
|
4
4
|
Summary: Python client for EPO OPS, the European Patent Office's Open Patent Services API.
|
|
5
5
|
Home-page: https://github.com/ip-tools/python-epo-ops-client
|
|
6
6
|
Download-URL: https://pypi.org/project/python-epo-ops-client/#files
|
|
@@ -8,11 +8,11 @@ Author: George Song
|
|
|
8
8
|
Author-email: george@monozuku.com
|
|
9
9
|
Maintainer: Andreas Motl
|
|
10
10
|
Maintainer-email: andreas.motl@ip-tools.org
|
|
11
|
+
License: Apache-2.0
|
|
11
12
|
Keywords: ops,epo,epo-ops,patent-data,patent-office,patent-data-api,european patent office,open patent services
|
|
12
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
14
15
|
Classifier: Natural Language :: English
|
|
15
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.6
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -22,25 +22,27 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: Topic :: Software Development :: Libraries
|
|
26
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
28
29
|
License-File: LICENSE
|
|
29
|
-
Requires-Dist: dogpile.cache<1.
|
|
30
|
+
Requires-Dist: dogpile.cache<1.6
|
|
30
31
|
Requires-Dist: importlib-metadata; python_version < "3.8"
|
|
31
32
|
Requires-Dist: python-dateutil<2.10
|
|
32
33
|
Requires-Dist: requests<3,>=2.27
|
|
33
34
|
Requires-Dist: six<2
|
|
34
35
|
Provides-Extra: develop
|
|
35
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: pyproject-fmt<3; extra == "develop"
|
|
37
|
+
Requires-Dist: ruff<0.16; python_version >= "3.7" and extra == "develop"
|
|
36
38
|
Requires-Dist: twine<7; extra == "develop"
|
|
37
39
|
Requires-Dist: wheel<1; extra == "develop"
|
|
38
40
|
Provides-Extra: test
|
|
39
|
-
Requires-Dist: pytest<
|
|
41
|
+
Requires-Dist: pytest<10; extra == "test"
|
|
40
42
|
Requires-Dist: pytest-cache<2; extra == "test"
|
|
41
|
-
Requires-Dist: pytest-cov<7.
|
|
42
|
-
Requires-Dist: python-dotenv<1.
|
|
43
|
-
Requires-Dist: responses<0.
|
|
43
|
+
Requires-Dist: pytest-cov<7.2; extra == "test"
|
|
44
|
+
Requires-Dist: python-dotenv<1.3; extra == "test"
|
|
45
|
+
Requires-Dist: responses<0.27; extra == "test"
|
|
44
46
|
Dynamic: author
|
|
45
47
|
Dynamic: author-email
|
|
46
48
|
Dynamic: classifier
|
|
@@ -49,6 +51,7 @@ Dynamic: description-content-type
|
|
|
49
51
|
Dynamic: download-url
|
|
50
52
|
Dynamic: home-page
|
|
51
53
|
Dynamic: keywords
|
|
54
|
+
Dynamic: license
|
|
52
55
|
Dynamic: license-file
|
|
53
56
|
Dynamic: maintainer
|
|
54
57
|
Dynamic: maintainer-email
|
|
@@ -125,9 +128,11 @@ you'll interact with mostly.
|
|
|
125
128
|
|
|
126
129
|
When you issue a request, the response is a [requests.Response][] object. If
|
|
127
130
|
`response.status_code != 200` then a `requests.HTTPError` exception will be
|
|
128
|
-
raised — it's your responsibility to handle those exceptions if you want to.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
raised — it's your responsibility to handle those exceptions if you want to.
|
|
132
|
+
This default can be disabled by passing `raise_for_status=False` when
|
|
133
|
+
constructing the client. The one case that's handled is when the access token
|
|
134
|
+
has expired: in this case, the client will automatically handle the HTTP 400
|
|
135
|
+
status and renew the token.
|
|
131
136
|
|
|
132
137
|
Note that the Client does not attempt to interpret the data supplied by OPS, so
|
|
133
138
|
it's your responsibility to parse the XML or JSON payload for your own purpose.
|
|
@@ -67,9 +67,11 @@ you'll interact with mostly.
|
|
|
67
67
|
|
|
68
68
|
When you issue a request, the response is a [requests.Response][] object. If
|
|
69
69
|
`response.status_code != 200` then a `requests.HTTPError` exception will be
|
|
70
|
-
raised — it's your responsibility to handle those exceptions if you want to.
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
raised — it's your responsibility to handle those exceptions if you want to.
|
|
71
|
+
This default can be disabled by passing `raise_for_status=False` when
|
|
72
|
+
constructing the client. The one case that's handled is when the access token
|
|
73
|
+
has expired: in this case, the client will automatically handle the HTTP 400
|
|
74
|
+
status and renew the token.
|
|
73
75
|
|
|
74
76
|
Note that the Client does not attempt to interpret the data supplied by OPS, so
|
|
75
77
|
it's your responsibility to parse the XML or JSON payload for your own purpose.
|
|
@@ -10,18 +10,13 @@ from requests.exceptions import HTTPError
|
|
|
10
10
|
|
|
11
11
|
from . import exceptions
|
|
12
12
|
from .middlewares import Throttler
|
|
13
|
-
from .models import
|
|
14
|
-
AccessToken,
|
|
15
|
-
Docdb,
|
|
16
|
-
Epodoc,
|
|
17
|
-
Original,
|
|
18
|
-
Request,
|
|
19
|
-
)
|
|
13
|
+
from .models import AccessToken, Docdb, Epodoc, Original, Request
|
|
20
14
|
|
|
21
15
|
log = logging.getLogger(__name__)
|
|
22
16
|
|
|
23
17
|
DEFAULT_NETWORK_TIMEOUT = 10.0
|
|
24
18
|
|
|
19
|
+
|
|
25
20
|
class Client(object):
|
|
26
21
|
__auth_url__ = "https://ops.epo.org/3.2/auth/accesstoken"
|
|
27
22
|
__service_url_prefix__ = "https://ops.epo.org/3.2/rest-services"
|
|
@@ -35,7 +30,15 @@ class Client(object):
|
|
|
35
30
|
__register_path__ = "register"
|
|
36
31
|
__register_search_path__ = "register/search"
|
|
37
32
|
|
|
38
|
-
def __init__(
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
key,
|
|
36
|
+
secret,
|
|
37
|
+
accept_type="xml",
|
|
38
|
+
middlewares=None,
|
|
39
|
+
timeout=DEFAULT_NETWORK_TIMEOUT,
|
|
40
|
+
raise_for_status=True,
|
|
41
|
+
):
|
|
39
42
|
self.accept_type = "application/{0}".format(accept_type)
|
|
40
43
|
self.middlewares = middlewares
|
|
41
44
|
if middlewares is None:
|
|
@@ -44,6 +47,7 @@ class Client(object):
|
|
|
44
47
|
self.key = key
|
|
45
48
|
self.secret = secret
|
|
46
49
|
self.timeout = timeout
|
|
50
|
+
self.raise_for_status = raise_for_status
|
|
47
51
|
self._access_token = None
|
|
48
52
|
|
|
49
53
|
def family(
|
|
@@ -154,6 +158,7 @@ class Client(object):
|
|
|
154
158
|
input=input,
|
|
155
159
|
)
|
|
156
160
|
)
|
|
161
|
+
|
|
157
162
|
def number(
|
|
158
163
|
self,
|
|
159
164
|
reference_type: str,
|
|
@@ -395,7 +400,8 @@ class Client(object):
|
|
|
395
400
|
)
|
|
396
401
|
response = self._check_for_expired_token(response)
|
|
397
402
|
response = self._check_for_exceeded_quota(response)
|
|
398
|
-
|
|
403
|
+
if self.raise_for_status:
|
|
404
|
+
response.raise_for_status()
|
|
399
405
|
return response
|
|
400
406
|
|
|
401
407
|
# info: {
|
|
@@ -1,63 +1,45 @@
|
|
|
1
|
-
# ==================
|
|
2
|
-
# Build system setup
|
|
3
|
-
# ==================
|
|
4
|
-
|
|
5
1
|
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
6
3
|
requires = [
|
|
7
4
|
"setuptools>=42", # At least v42 of setuptools required!
|
|
8
5
|
"versioningit",
|
|
9
6
|
]
|
|
10
|
-
build-backend = "setuptools.build_meta"
|
|
11
|
-
|
|
12
|
-
[tool.pytest.ini_options]
|
|
13
|
-
minversion = "2.0"
|
|
14
|
-
addopts = """
|
|
15
|
-
-rsfEX -p pytester --strict-markers --verbosity=3
|
|
16
|
-
--cov=epo_ops tests --cov-report=term-missing --cov-report=xml
|
|
17
|
-
"""
|
|
18
|
-
log_level = "DEBUG"
|
|
19
|
-
log_cli_level = "DEBUG"
|
|
20
|
-
testpaths = ["tests"]
|
|
21
|
-
xfail_strict = true
|
|
22
|
-
markers = []
|
|
23
7
|
|
|
24
8
|
[tool.ruff]
|
|
25
9
|
line-length = 80
|
|
26
|
-
|
|
10
|
+
extend-exclude = [ "__init__.py" ]
|
|
27
11
|
lint.select = [
|
|
28
|
-
# Bandit
|
|
29
|
-
"S",
|
|
30
|
-
# Bugbear
|
|
31
|
-
"B",
|
|
32
12
|
# Builtins
|
|
33
13
|
"A",
|
|
14
|
+
# Bugbear
|
|
15
|
+
"B",
|
|
16
|
+
"B9",
|
|
34
17
|
# comprehensions
|
|
35
18
|
"C",
|
|
19
|
+
# Pycodestyle
|
|
20
|
+
"E",
|
|
36
21
|
# eradicate
|
|
37
22
|
"ERA",
|
|
38
|
-
#
|
|
39
|
-
"
|
|
23
|
+
# Pyflakes
|
|
24
|
+
"F",
|
|
40
25
|
# isort
|
|
41
26
|
"I",
|
|
42
27
|
# pandas-vet
|
|
43
28
|
"PD",
|
|
44
|
-
# print
|
|
45
|
-
"T20",
|
|
46
|
-
# Pycodestyle
|
|
47
|
-
"E",
|
|
48
|
-
"W",
|
|
49
|
-
# Pyflakes
|
|
50
|
-
"F",
|
|
51
29
|
# return
|
|
52
30
|
"RET",
|
|
31
|
+
# Bandit
|
|
32
|
+
"S",
|
|
53
33
|
# from `.flake8` file
|
|
54
|
-
"T",
|
|
55
|
-
|
|
34
|
+
"T", # T4
|
|
35
|
+
# print
|
|
36
|
+
"T20",
|
|
37
|
+
"W",
|
|
38
|
+
# flake8-2020
|
|
39
|
+
"YTT",
|
|
56
40
|
]
|
|
57
|
-
|
|
58
|
-
extend-exclude = ["__init__.py"]
|
|
59
|
-
|
|
60
41
|
lint.ignore = [
|
|
42
|
+
"B905", # B905 `zip()` without an explicit `strict=` parameter
|
|
61
43
|
"E203",
|
|
62
44
|
"E266",
|
|
63
45
|
"E501",
|
|
@@ -65,12 +47,25 @@ lint.ignore = [
|
|
|
65
47
|
"RET505", # Unnecessary `else` after `return` statement
|
|
66
48
|
# "W503", # Unknown rule selector
|
|
67
49
|
]
|
|
68
|
-
|
|
50
|
+
# FIXME: Improve this situation wrt. SQL injection, even it is not be an actual attack vector.
|
|
51
|
+
lint.per-file-ignores."*sqlite.py" = [
|
|
52
|
+
"S608", # Possible SQL injection vector through string-based query construction
|
|
53
|
+
]
|
|
54
|
+
lint.per-file-ignores."epo_ops/api.py" = [
|
|
55
|
+
"A001", # Variable `range` is shadowing a Python builtin
|
|
56
|
+
"A002", # Argument `input` is shadowing a Python builtin
|
|
57
|
+
"C408", # Unnecessary `dict` call (rewrite as a literal)
|
|
58
|
+
]
|
|
59
|
+
lint.per-file-ignores."tests/*" = [
|
|
60
|
+
"S101", # Use of `assert` detected
|
|
61
|
+
]
|
|
62
|
+
lint.per-file-ignores."tests/middlewares/throttle/conftest.py" = [
|
|
63
|
+
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
|
|
64
|
+
]
|
|
69
65
|
# from `.isort.cfg` file
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
known-third-party = [
|
|
66
|
+
lint.isort.combine-as-imports = true
|
|
67
|
+
lint.isort.force-wrap-aliases = true
|
|
68
|
+
lint.isort.known-third-party = [
|
|
74
69
|
"dateutil",
|
|
75
70
|
"dogpile",
|
|
76
71
|
"dotenv",
|
|
@@ -78,34 +73,24 @@ known-third-party = [
|
|
|
78
73
|
"requests",
|
|
79
74
|
"six",
|
|
80
75
|
]
|
|
81
|
-
split-on-trailing-comma = false
|
|
82
|
-
|
|
76
|
+
lint.isort.split-on-trailing-comma = false
|
|
83
77
|
# from `.flake8` file
|
|
84
|
-
[tool.ruff.lint.mccabe]
|
|
85
78
|
# Flag errors (`C901`) whenever the complexity level exceeds the configured value.
|
|
86
|
-
max-complexity = 7
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
[tool.ruff.lint.per-file-ignores]
|
|
90
|
-
"tests/*" = [
|
|
91
|
-
"S101", # Use of `assert` detected
|
|
92
|
-
]
|
|
93
|
-
"epo_ops/api.py" = [
|
|
94
|
-
"A001", # Variable `range` is shadowing a Python builtin
|
|
95
|
-
"A002", # Argument `input` is shadowing a Python builtin
|
|
96
|
-
"C408", # Unnecessary `dict` call (rewrite as a literal)
|
|
97
|
-
]
|
|
98
|
-
# FIXME: Improve this situation wrt. SQL injection, even it is not be an actual attack vector.
|
|
99
|
-
"*sqlite.py" = [
|
|
100
|
-
"S608", # Possible SQL injection vector through string-based query construction
|
|
101
|
-
]
|
|
102
|
-
"tests/middlewares/throttle/conftest.py" = [
|
|
103
|
-
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
|
|
104
|
-
]
|
|
79
|
+
lint.mccabe.max-complexity = 7
|
|
105
80
|
|
|
81
|
+
[tool.pytest]
|
|
82
|
+
ini_options.minversion = "2.0"
|
|
83
|
+
ini_options.addopts = """
|
|
84
|
+
-rsfEX -p pytester --strict-markers --verbosity=3
|
|
85
|
+
--cov=epo_ops tests --cov-report=term-missing --cov-report=xml
|
|
86
|
+
"""
|
|
87
|
+
ini_options.log_level = "DEBUG"
|
|
88
|
+
ini_options.log_cli_level = "DEBUG"
|
|
89
|
+
ini_options.testpaths = [ "tests" ]
|
|
90
|
+
ini_options.xfail_strict = true
|
|
91
|
+
ini_options.markers = []
|
|
106
92
|
|
|
107
93
|
[tool.versioningit]
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
default-tag = "0.0.0"
|
|
94
|
+
vcs.method = "git-archive"
|
|
95
|
+
vcs.default-tag = "v0.0.0"
|
|
96
|
+
vcs.describe-subst = "$Format:%(describe:tags,match=v*)$"
|
{python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/python_epo_ops_client.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-epo-ops-client
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.2
|
|
4
4
|
Summary: Python client for EPO OPS, the European Patent Office's Open Patent Services API.
|
|
5
5
|
Home-page: https://github.com/ip-tools/python-epo-ops-client
|
|
6
6
|
Download-URL: https://pypi.org/project/python-epo-ops-client/#files
|
|
@@ -8,11 +8,11 @@ Author: George Song
|
|
|
8
8
|
Author-email: george@monozuku.com
|
|
9
9
|
Maintainer: Andreas Motl
|
|
10
10
|
Maintainer-email: andreas.motl@ip-tools.org
|
|
11
|
+
License: Apache-2.0
|
|
11
12
|
Keywords: ops,epo,epo-ops,patent-data,patent-office,patent-data-api,european patent office,open patent services
|
|
12
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
14
15
|
Classifier: Natural Language :: English
|
|
15
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.6
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -22,25 +22,27 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: Topic :: Software Development :: Libraries
|
|
26
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
28
29
|
License-File: LICENSE
|
|
29
|
-
Requires-Dist: dogpile.cache<1.
|
|
30
|
+
Requires-Dist: dogpile.cache<1.6
|
|
30
31
|
Requires-Dist: importlib-metadata; python_version < "3.8"
|
|
31
32
|
Requires-Dist: python-dateutil<2.10
|
|
32
33
|
Requires-Dist: requests<3,>=2.27
|
|
33
34
|
Requires-Dist: six<2
|
|
34
35
|
Provides-Extra: develop
|
|
35
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: pyproject-fmt<3; extra == "develop"
|
|
37
|
+
Requires-Dist: ruff<0.16; python_version >= "3.7" and extra == "develop"
|
|
36
38
|
Requires-Dist: twine<7; extra == "develop"
|
|
37
39
|
Requires-Dist: wheel<1; extra == "develop"
|
|
38
40
|
Provides-Extra: test
|
|
39
|
-
Requires-Dist: pytest<
|
|
41
|
+
Requires-Dist: pytest<10; extra == "test"
|
|
40
42
|
Requires-Dist: pytest-cache<2; extra == "test"
|
|
41
|
-
Requires-Dist: pytest-cov<7.
|
|
42
|
-
Requires-Dist: python-dotenv<1.
|
|
43
|
-
Requires-Dist: responses<0.
|
|
43
|
+
Requires-Dist: pytest-cov<7.2; extra == "test"
|
|
44
|
+
Requires-Dist: python-dotenv<1.3; extra == "test"
|
|
45
|
+
Requires-Dist: responses<0.27; extra == "test"
|
|
44
46
|
Dynamic: author
|
|
45
47
|
Dynamic: author-email
|
|
46
48
|
Dynamic: classifier
|
|
@@ -49,6 +51,7 @@ Dynamic: description-content-type
|
|
|
49
51
|
Dynamic: download-url
|
|
50
52
|
Dynamic: home-page
|
|
51
53
|
Dynamic: keywords
|
|
54
|
+
Dynamic: license
|
|
52
55
|
Dynamic: license-file
|
|
53
56
|
Dynamic: maintainer
|
|
54
57
|
Dynamic: maintainer-email
|
|
@@ -125,9 +128,11 @@ you'll interact with mostly.
|
|
|
125
128
|
|
|
126
129
|
When you issue a request, the response is a [requests.Response][] object. If
|
|
127
130
|
`response.status_code != 200` then a `requests.HTTPError` exception will be
|
|
128
|
-
raised — it's your responsibility to handle those exceptions if you want to.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
raised — it's your responsibility to handle those exceptions if you want to.
|
|
132
|
+
This default can be disabled by passing `raise_for_status=False` when
|
|
133
|
+
constructing the client. The one case that's handled is when the access token
|
|
134
|
+
has expired: in this case, the client will automatically handle the HTTP 400
|
|
135
|
+
status and renew the token.
|
|
131
136
|
|
|
132
137
|
Note that the Client does not attempt to interpret the data supplied by OPS, so
|
|
133
138
|
it's your responsibility to parse the XML or JSON payload for your own purpose.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
dogpile.cache<1.
|
|
1
|
+
dogpile.cache<1.6
|
|
2
2
|
python-dateutil<2.10
|
|
3
3
|
requests<3,>=2.27
|
|
4
4
|
six<2
|
|
@@ -7,15 +7,16 @@ six<2
|
|
|
7
7
|
importlib-metadata
|
|
8
8
|
|
|
9
9
|
[develop]
|
|
10
|
+
pyproject-fmt<3
|
|
10
11
|
twine<7
|
|
11
12
|
wheel<1
|
|
12
13
|
|
|
13
14
|
[develop:python_version >= "3.7"]
|
|
14
|
-
ruff<0.
|
|
15
|
+
ruff<0.16
|
|
15
16
|
|
|
16
17
|
[test]
|
|
17
|
-
pytest<
|
|
18
|
+
pytest<10
|
|
18
19
|
pytest-cache<2
|
|
19
|
-
pytest-cov<7.
|
|
20
|
-
python-dotenv<1.
|
|
21
|
-
responses<0.
|
|
20
|
+
pytest-cov<7.2
|
|
21
|
+
python-dotenv<1.3
|
|
22
|
+
responses<0.27
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import codecs
|
|
2
2
|
from os import path
|
|
3
3
|
|
|
4
|
-
from setuptools import setup
|
|
4
|
+
from setuptools import find_packages, setup
|
|
5
5
|
from versioningit import get_cmdclasses
|
|
6
6
|
|
|
7
7
|
here = path.abspath(path.dirname(__file__))
|
|
@@ -15,6 +15,7 @@ setup(
|
|
|
15
15
|
description=(
|
|
16
16
|
"Python client for EPO OPS, the European Patent Office's Open Patent Services API."
|
|
17
17
|
),
|
|
18
|
+
license="Apache-2.0",
|
|
18
19
|
long_description_content_type="text/markdown",
|
|
19
20
|
long_description=readme,
|
|
20
21
|
author="George Song",
|
|
@@ -23,11 +24,12 @@ setup(
|
|
|
23
24
|
maintainer_email="andreas.motl@ip-tools.org",
|
|
24
25
|
url="https://github.com/ip-tools/python-epo-ops-client",
|
|
25
26
|
download_url="https://pypi.org/project/python-epo-ops-client/#files",
|
|
26
|
-
packages=
|
|
27
|
-
|
|
27
|
+
packages=find_packages(
|
|
28
|
+
include=["epo_ops*"],
|
|
29
|
+
),
|
|
28
30
|
include_package_data=True,
|
|
29
31
|
install_requires=[
|
|
30
|
-
"dogpile.cache<1.
|
|
32
|
+
"dogpile.cache<1.6",
|
|
31
33
|
"importlib-metadata; python_version<'3.8'",
|
|
32
34
|
"python-dateutil<2.10",
|
|
33
35
|
"requests>=2.27,<3",
|
|
@@ -35,16 +37,17 @@ setup(
|
|
|
35
37
|
],
|
|
36
38
|
extras_require={
|
|
37
39
|
"develop": [
|
|
38
|
-
"
|
|
40
|
+
"pyproject-fmt<3",
|
|
41
|
+
"ruff<0.16; python_version >= '3.7'",
|
|
39
42
|
"twine<7",
|
|
40
43
|
"wheel<1",
|
|
41
44
|
],
|
|
42
45
|
"test": [
|
|
43
|
-
"pytest<
|
|
46
|
+
"pytest<10",
|
|
44
47
|
"pytest-cache<2",
|
|
45
|
-
"pytest-cov<7.
|
|
46
|
-
"python-dotenv<1.
|
|
47
|
-
"responses<0.
|
|
48
|
+
"pytest-cov<7.2",
|
|
49
|
+
"python-dotenv<1.3",
|
|
50
|
+
"responses<0.27",
|
|
48
51
|
],
|
|
49
52
|
},
|
|
50
53
|
zip_safe=False,
|
|
@@ -52,7 +55,6 @@ setup(
|
|
|
52
55
|
"Development Status :: 5 - Production/Stable",
|
|
53
56
|
"Intended Audience :: Developers",
|
|
54
57
|
"Natural Language :: English",
|
|
55
|
-
"License :: OSI Approved :: Apache Software License",
|
|
56
58
|
"Programming Language :: Python",
|
|
57
59
|
"Programming Language :: Python :: 3.6",
|
|
58
60
|
"Programming Language :: Python :: 3.7",
|
|
@@ -62,6 +64,7 @@ setup(
|
|
|
62
64
|
"Programming Language :: Python :: 3.11",
|
|
63
65
|
"Programming Language :: Python :: 3.12",
|
|
64
66
|
"Programming Language :: Python :: 3.13",
|
|
67
|
+
"Programming Language :: Python :: 3.14",
|
|
65
68
|
"Topic :: Software Development :: Libraries",
|
|
66
69
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
67
70
|
],
|
|
@@ -28,6 +28,12 @@ def test_instantiate_simple_client():
|
|
|
28
28
|
client = Client("key", "secret")
|
|
29
29
|
assert len(client.middlewares) == 1
|
|
30
30
|
assert client.middlewares[0].history.db_path == sqlite.DEFAULT_DB_PATH
|
|
31
|
+
assert client.raise_for_status is True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_instantiate_client_without_raise_for_status():
|
|
35
|
+
client = Client("key", "secret", raise_for_status=False)
|
|
36
|
+
assert client.raise_for_status is False
|
|
31
37
|
|
|
32
38
|
|
|
33
39
|
def test_family(all_clients):
|
|
@@ -45,9 +51,11 @@ def test_family_legal(all_clients):
|
|
|
45
51
|
def test_image(all_clients):
|
|
46
52
|
assert_image_success(all_clients)
|
|
47
53
|
|
|
54
|
+
|
|
48
55
|
def test_legal(all_clients):
|
|
49
56
|
assert_legal_success(all_clients)
|
|
50
57
|
|
|
58
|
+
|
|
51
59
|
def test_published_data(all_clients):
|
|
52
60
|
assert_published_data_success(all_clients)
|
|
53
61
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import responses
|
|
3
|
+
from pytest import raises
|
|
4
|
+
from requests.exceptions import HTTPError
|
|
5
|
+
|
|
6
|
+
from epo_ops.api import Client
|
|
7
|
+
from epo_ops.models import Docdb
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def ops_backend_413():
|
|
12
|
+
"""
|
|
13
|
+
Emulate an OPS backend returning 413 on the fulltext endpoint for an
|
|
14
|
+
ambiguous input. The real upstream returns 413 for e.g. EP.0536425/fulltext.
|
|
15
|
+
"""
|
|
16
|
+
token = responses.Response(
|
|
17
|
+
responses.POST,
|
|
18
|
+
url="https://ops.epo.org/3.2/auth/accesstoken",
|
|
19
|
+
status=200,
|
|
20
|
+
json={"access_token": "foo", "expires_in": 42},
|
|
21
|
+
)
|
|
22
|
+
fulltext_413 = responses.Response(
|
|
23
|
+
responses.POST,
|
|
24
|
+
url="https://ops.epo.org/3.2/rest-services/published-data/publication/docdb/fulltext",
|
|
25
|
+
status=413,
|
|
26
|
+
headers={"Content-Type": "application/xml"},
|
|
27
|
+
body=(
|
|
28
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'
|
|
29
|
+
' <fault xmlns="http://ops.epo.org">\n'
|
|
30
|
+
" <code>CLIENT.AmbiguousRequest</code>\n"
|
|
31
|
+
" <message>The request was ambiguous</message>\n"
|
|
32
|
+
" <details>\n"
|
|
33
|
+
" <cause>Ambiguous input: publication/docdb/EP.0536425</cause>\n"
|
|
34
|
+
" <resolution>publication/docdb/EP.0536425.A1</resolution>\n"
|
|
35
|
+
" <resolution>publication/docdb/EP.0536425.A4</resolution>\n"
|
|
36
|
+
" <resolution>publication/docdb/EP.0536425.B1</resolution>\n"
|
|
37
|
+
" <resolution>publication/docdb/EP.0536425.B2</resolution>\n"
|
|
38
|
+
" </details>\n"
|
|
39
|
+
" </fault>"
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
for response in [token, fulltext_413]:
|
|
43
|
+
responses.add(response)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _issue_fulltext_request(client):
|
|
47
|
+
return client.published_data(
|
|
48
|
+
"publication",
|
|
49
|
+
Docdb("0536425", "EP", "B1"),
|
|
50
|
+
endpoint="fulltext",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@responses.activate
|
|
55
|
+
def test_413_raises_by_default(ops_backend_413):
|
|
56
|
+
client = Client("key", "secret", middlewares=[])
|
|
57
|
+
with raises(HTTPError):
|
|
58
|
+
_issue_fulltext_request(client)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@responses.activate
|
|
62
|
+
def test_413_returned_when_raise_for_status_disabled(ops_backend_413):
|
|
63
|
+
client = Client("key", "secret", middlewares=[], raise_for_status=False)
|
|
64
|
+
response = _issue_fulltext_request(client)
|
|
65
|
+
assert response.status_code == 413
|
|
66
|
+
assert "CLIENT.AmbiguousRequest" in response.text
|
|
67
|
+
assert "publication/docdb/EP.0536425.B1" in response.text
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/cache/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/middleware.py
RENAMED
|
File without changes
|
{python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_epo_ops_client-4.2.1 → python_epo_ops_client-4.2.2}/epo_ops/middlewares/throttle/utils.py
RENAMED
|
File without changes
|
|
@@ -10,6 +10,7 @@ from .utils import quote, validate_date
|
|
|
10
10
|
|
|
11
11
|
log = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
def _prepare_part(part):
|
|
14
15
|
return "({0})".format(quote(part))
|
|
15
16
|
|
|
@@ -107,7 +108,6 @@ class Request(object):
|
|
|
107
108
|
self.reset_env()
|
|
108
109
|
return response
|
|
109
110
|
|
|
110
|
-
|
|
111
111
|
def _post_callback(self, url, data, **kwargs):
|
|
112
112
|
return requests.post(url, data, **kwargs, timeout=self.timeout)
|
|
113
113
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|