Skip to content

Commit 6933dc8

Browse files
authored
add-adapter-and-tests (#8)
1 parent 5b9b175 commit 6933dc8

17 files changed

+2236
-48
lines changed

.coveragerc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[run]
2+
omit =
3+
*/test*

setup.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ test =
3030
pytest-mock==2.0.0
3131
pytest-cov==2.8.1
3232
pyramid==1.10.4
33+
Flask==1.1.2
3334

3435
[options.packages.find]
3536
where = src

src/snosearch/adapters/exceptions.py

+47-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,49 @@
1-
from pyramid.httpexceptions import HTTPBadRequest
1+
def flask_exception_adapter(error):
2+
def wrapper(explanation):
3+
return error(explanation)
4+
return wrapper
25

36

4-
def get_default_exception():
5-
return HTTPBadRequest
7+
class BadRequestFactory():
8+
9+
def __init__(self, name=None):
10+
self.name = name
11+
12+
def _get_exception_from_pyramid(self):
13+
from pyramid.httpexceptions import HTTPBadRequest
14+
return HTTPBadRequest
15+
16+
def _maybe_get_exception_from_pyramid(self):
17+
try:
18+
return self._get_exception_from_pyramid()
19+
except ModuleNotFoundError:
20+
return None
21+
22+
def _get_exception_from_flask(self):
23+
from werkzeug.exceptions import BadRequest
24+
return flask_exception_adapter(BadRequest)
25+
26+
def _maybe_get_exception_from_flask(self):
27+
try:
28+
return self._get_exception_from_flask()
29+
except ModuleNotFoundError:
30+
return None
31+
32+
def _get_exception_by_name(self):
33+
if not self.name:
34+
return None
35+
if self.name == 'flask':
36+
return self._get_exception_from_flask()
37+
return self._get_exception_from_pyramid()
38+
39+
def _get_bad_request(self):
40+
return (
41+
self._get_exception_by_name()
42+
or self._maybe_get_exception_from_pyramid()
43+
or self._maybe_get_exception_from_flask()
44+
)
45+
46+
47+
def get_default_exception(name=None):
48+
br = BadRequestFactory(name)
49+
return br._get_bad_request()

src/snosearch/adapters/flask/__init__.py

Whitespace-only changes.
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
class ArgsAdapter:
2+
3+
def __init__(self, args):
4+
self.args = args
5+
6+
def __iter__(self):
7+
return self.args.__iter__()
8+
9+
def items(self):
10+
return self.args.items(multi=True)
11+
12+
def getall(self, key):
13+
return self.args.getlist(key)
14+
15+
16+
class RequestAdapter:
17+
18+
__parent__ = None
19+
20+
def __init__(self, request):
21+
self._request = request
22+
23+
@property
24+
def params(self):
25+
return ArgsAdapter(
26+
self._request.args
27+
)
28+
29+
def copy(self, environ=None):
30+
return RequestAdapter(
31+
self._request.__class__(
32+
environ or self._request.environ.copy()
33+
)
34+
)
35+
36+
@property
37+
def effective_principals(self):
38+
return ['system.Everyone']
39+
40+
def has_permission(self, action):
41+
return True
42+
43+
def route_path(self, context):
44+
raise NotImplementedError
45+
46+
@property
47+
def path_qs(self):
48+
return self._request.full_path
49+
50+
@property
51+
def path(self):
52+
return self._request.path
53+
54+
@property
55+
def query_string(self):
56+
return self._request.query_string.decode('utf-8')
57+
58+
@query_string.setter
59+
def query_string(self, query_string):
60+
environ = self._request.environ.copy()
61+
environ.update(
62+
{
63+
'QUERY_STRING': query_string,
64+
}
65+
)
66+
self._request = self.copy(
67+
environ=environ
68+
)._request
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from flask import Response
2+
3+
4+
class ResponseAdapter(Response):
5+
6+
@property
7+
def status_code(self):
8+
return super().status_code
9+
10+
@status_code.setter
11+
def status_code(self, code):
12+
self.status = code
13+
14+
@property
15+
def app_iter(self):
16+
return None
17+
18+
@app_iter.setter
19+
def app_iter(self, generator):
20+
self.response = generator

src/snosearch/adapters/requests.py

-30
This file was deleted.

src/snosearch/adapters/responses.py

+40-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
1-
from pyramid.response import Response
1+
class ResponseFactory():
2+
def __init__(self, name=None):
3+
self.name = name
4+
5+
def _get_response_from_pyramid(self):
6+
from pyramid.response import Response
7+
return Response()
8+
9+
def _get_response_from_flask(self):
10+
from flask import Response
11+
from snosearch.adapters.flask.responses import ResponseAdapter
12+
return ResponseAdapter()
13+
14+
def _maybe_get_response_from_pyramid(self):
15+
try:
16+
return self._get_response_from_pyramid()
17+
except ModuleNotFoundError:
18+
return None
19+
20+
def _maybe_get_response_from_flask(self):
21+
try:
22+
return self._get_response_from_flask()
23+
except ModuleNotFoundError:
24+
return None
25+
26+
def _get_response_by_name(self):
27+
if not self.name:
28+
return None
29+
if self.name == 'flask':
30+
return self._get_response_from_flask()
31+
return self._get_response_from_pyramid()
32+
33+
def _get_response(self):
34+
return (
35+
self._get_response_by_name()
36+
or self._maybe_get_response_from_pyramid()
37+
or self._maybe_get_response_from_flask()
38+
)
239

340

441
def get_response():
5-
return Response()
42+
rf = ResponseFactory()
43+
return rf._get_response()

src/snosearch/tests/__init__.py

Whitespace-only changes.

src/snosearch/tests/conftest.py

+27-3
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,37 @@ def dummy_registry(testing_types, testing_configs):
2424

2525

2626
@pytest.fixture
27-
def dummy_request(dummy_registry):
28-
from snosearch.adapters.requests import DummyRequest
29-
dummy_request = DummyRequest({}).blank('/dummy')
27+
def pyramid_dummy_request(dummy_registry):
28+
from snosearch.tests.dummy_requests import PyramidDummyRequest
29+
dummy_request = PyramidDummyRequest({}).blank('/dummy')
3030
dummy_request.registry = dummy_registry
3131
return dummy_request
3232

3333

34+
@pytest.fixture
35+
def flask_dummy_request(dummy_registry):
36+
from snosearch.tests.dummy_requests import FlaskDummyRequestAdapter
37+
from flask import Request
38+
from flask import Response
39+
dummy_request = FlaskDummyRequestAdapter(
40+
Request(
41+
{
42+
'PATH_INFO': '/dummy'
43+
}
44+
)
45+
)
46+
dummy_request.registry = dummy_registry
47+
dummy_request.response = Response()
48+
return dummy_request
49+
50+
51+
@pytest.fixture
52+
def dummy_request(request, pyramid_dummy_request, flask_dummy_request):
53+
if hasattr(request, 'param') and request.param == 'flask':
54+
return flask_dummy_request
55+
return pyramid_dummy_request
56+
57+
3458
@pytest.fixture
3559
def testing_search_schema_type():
3660
return {

src/snosearch/tests/dummy_requests.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from pyramid.request import Request
2+
from snosearch.adapters.flask.requests import RequestAdapter
3+
from snosearch.interfaces import JSONLD_CONTEXT
4+
from werkzeug.datastructures import ImmutableOrderedMultiDict
5+
6+
7+
class FlaskDummyRequestAdapter(RequestAdapter):
8+
9+
def __setitem__(self, key, value):
10+
self._request.__class__.parameter_storage_class = ImmutableOrderedMultiDict
11+
environ = self._request.environ.copy()
12+
environ.update({key: value})
13+
self._request = self._request.__class__(environ)
14+
15+
def __getitem__(self, key):
16+
return self._request.environ[key]
17+
18+
@property
19+
def environ(self):
20+
return self
21+
22+
@property
23+
def effective_principals(self):
24+
if self._request.environ.get('REMOTE_USER') == 'TEST_SUBMITTER':
25+
return ['group.submitter']
26+
return super().effective_principals
27+
28+
def has_permission(self, action):
29+
principals = self.effective_principals
30+
acls = getattr(
31+
self.context,
32+
'__acl__',
33+
lambda: []
34+
)
35+
for principal in principals:
36+
for acl in acls():
37+
if acl[1] == principal and acl[2] == action:
38+
return acl[0]
39+
return False
40+
41+
42+
class PyramidDummyRequest(Request):
43+
44+
__parent__ = None
45+
46+
@property
47+
def effective_principals(self):
48+
if self.environ.get('REMOTE_USER') == 'TEST_SUBMITTER':
49+
return ['group.submitter']
50+
return super().effective_principals
51+
52+
def has_permission(self, action):
53+
principals = self.effective_principals
54+
acls = getattr(
55+
self.context,
56+
'__acl__',
57+
lambda: []
58+
)
59+
for principal in principals:
60+
for acl in acls():
61+
if acl[1] == principal and acl[2] == action:
62+
return acl[0]
63+
return False
64+
65+
def route_path(self, context):
66+
if context == JSONLD_CONTEXT:
67+
return '/terms/'

0 commit comments

Comments
 (0)