Skip to content

Commit 4b822aa

Browse files
committed
feat: Make raise_for_status configurable
Defaults to the original behaviour of raising for status when making a request to the EPO OPS API
1 parent dd09ea7 commit 4b822aa

4 files changed

Lines changed: 95 additions & 12 deletions

File tree

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ you'll interact with mostly.
6767

6868
When you issue a request, the response is a [requests.Response][] object. If
6969
`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. The
71-
one case that's handled is when the access token has expired: in this case, the
72-
client will automatically handle the HTTP 400 status and renew the token.
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.
7375

7476
Note that the Client does not attempt to interpret the data supplied by OPS, so
7577
it's your responsibility to parse the XML or JSON payload for your own purpose.

epo_ops/api.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,13 @@
1010

1111
from . import exceptions
1212
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
2014

2115
log = logging.getLogger(__name__)
2216

2317
DEFAULT_NETWORK_TIMEOUT = 10.0
2418

19+
2520
class Client(object):
2621
__auth_url__ = "https://ops.epo.org/3.2/auth/accesstoken"
2722
__service_url_prefix__ = "https://ops.epo.org/3.2/rest-services"
@@ -35,7 +30,15 @@ class Client(object):
3530
__register_path__ = "register"
3631
__register_search_path__ = "register/search"
3732

38-
def __init__(self, key, secret, accept_type="xml", middlewares=None, timeout=DEFAULT_NETWORK_TIMEOUT):
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+
):
3942
self.accept_type = "application/{0}".format(accept_type)
4043
self.middlewares = middlewares
4144
if middlewares is None:
@@ -44,6 +47,7 @@ def __init__(self, key, secret, accept_type="xml", middlewares=None, timeout=DEF
4447
self.key = key
4548
self.secret = secret
4649
self.timeout = timeout
50+
self.raise_for_status = raise_for_status
4751
self._access_token = None
4852

4953
def family(
@@ -154,6 +158,7 @@ def legal(
154158
input=input,
155159
)
156160
)
161+
157162
def number(
158163
self,
159164
reference_type: str,
@@ -395,7 +400,8 @@ def _make_request(
395400
)
396401
response = self._check_for_expired_token(response)
397402
response = self._check_for_exceeded_quota(response)
398-
response.raise_for_status()
403+
if self.raise_for_status:
404+
response.raise_for_status()
399405
return response
400406

401407
# info: {

tests/test_api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ def test_instantiate_simple_client():
2828
client = Client("key", "secret")
2929
assert len(client.middlewares) == 1
3030
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
3137

3238

3339
def test_family(all_clients):
@@ -45,9 +51,11 @@ def test_family_legal(all_clients):
4551
def test_image(all_clients):
4652
assert_image_success(all_clients)
4753

54+
4855
def test_legal(all_clients):
4956
assert_legal_success(all_clients)
5057

58+
5159
def test_published_data(all_clients):
5260
assert_published_data_success(all_clients)
5361

tests/test_raise_for_status.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)