Skip to content

Commit 24f015a

Browse files
committed
[wip] update code to use cornice/colander validators as expected (relates to #615)
1 parent 031f3fc commit 24f015a

File tree

7 files changed

+417
-249
lines changed

7 files changed

+417
-249
lines changed

weaver/processes/constants.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,20 @@ class JobInputsOutputsSchema(Constants):
295295
CWL_RequirementToolTimeLimitType,
296296
CWL_RequirementWorkReuseType,
297297
]
298-
ProcessSchemaType = Literal["OGC", "ogc", "OLD", "old", "WPS", "wps"]
299-
JobInputsOutputsSchemaType = Literal[
300-
"ogc+strict",
301-
"OGC+STRICT",
302-
"old+strict",
303-
"OLD+STRICT",
304-
"ogc",
305-
"OGC",
306-
"old",
307-
"OLD",
298+
ProcessSchemaType = Union[
299+
ProcessSchema,
300+
Literal["OGC", "ogc", "OLD", "old", "WPS", "wps"]
301+
]
302+
JobInputsOutputsSchemaType = Union[
303+
JobInputsOutputsSchema,
304+
Literal[
305+
"ogc+strict",
306+
"OGC+STRICT",
307+
"old+strict",
308+
"OLD+STRICT",
309+
"ogc",
310+
"OGC",
311+
"old",
312+
"OLD",
313+
]
308314
]

weaver/tweens.py

+21-89
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import colander
21
import logging
32
import sys
43
from typing import TYPE_CHECKING
54

5+
import colander
6+
from cornice.renderer import JSONError
67
from pyramid.httpexceptions import (
78
HTTPException,
89
HTTPInternalServerError,
@@ -80,26 +81,23 @@ def validate_format(request):
8081
def http_apply_response_format_tween_factory(handler, registry): # noqa: F811
8182
# type: (ViewHandler, Registry) -> Callable[[PyramidRequest], AnyViewResponse]
8283
"""
83-
Tween factory that applies the response ``Content-Type`` according to the requested format.
84+
Tween factory that applies the request ``Accept`` header according to the requested format.
8485
85-
Format can be provided by ``Accept`` header or ``format`` query.
86+
Format can be provided by ``Accept`` header or ``format`` query. The resulting request will unify the format
87+
under the ``Accept`` header, such that a single reference can be considered by the following code.
8688
87-
The target ``Content-Type`` is expected to have been validated by :func:`validate_accept_header_tween` beforehand
88-
to handle not-acceptable errors. If an invalid format is detected at this stage, JSON is used by default.
89-
This can be the case for example for :func:`validate_accept_header_tween` itself that raises the error about
90-
the invalid ``Accept`` header or ``format`` query, but detects these inadequate parameters from incoming request.
89+
If validation of allowed ``Accept`` header values must be done, it is expected to be validated by
90+
:func:`cornice.validators.colander_headers_validator` or :func:`cornice.validators.colander_validator`
91+
with the relevant `validators` definition applied onto the :class:`cornice.service.Service` decorating
92+
the specific view.
9193
92-
The tween also ensures that additional request metadata extracted from :func:`get_request_info` is applied to
93-
the response body if not already provided by a previous operation.
94+
Since browsers will typically inject :term:`HTML`-related media-types in the ``Accept` header, specific
95+
combinations of browser ``User-Agent`` will ignore those values to provide :term:`JSON` by default, unless
96+
an explicit ``text/html`` or ``f=html`` is specified. In the case of non-browser ``User-Agent``, headers will
97+
be interpreted normally.
9498
"""
9599
def apply_format(request):
96100
# type: (PyramidRequest) -> HTTPException
97-
"""
98-
Validates the specified request according to its ``Accept`` header, ignoring UI related routes that request more
99-
content-types than the ones supported by the application for display purposes (styles, images etc.).
100-
101-
Alternatively, if no ``Accept`` header is found, look for equivalent value provided via query parameter.
102-
"""
103101
content_type = guess_target_format(request)
104102
# NOTE:
105103
# enforce the accept header in case it was specified with format query, since some renderer implementations
@@ -123,77 +121,6 @@ def apply_format(request):
123121
return apply_format
124122

125123

126-
# def generate_response_http_format(http_class, http_kwargs, content, content_type=None):
127-
# # type: (Type[HTTPException], Optional[Dict[str, Any]], Union[JSON, str], Optional[str]) -> HTTPException
128-
# """
129-
# Formats the HTTP response content according to desired ``content_type`` using provided HTTP code and content.
130-
#
131-
# :param http_class: `HTTPException` derived class to use for output (code, generic title/explanation, etc.)
132-
# :param http_kwargs: additional keyword arguments to pass to `http_class` when called
133-
# :param content: formatted JSON content or literal string content providing additional details for the response
134-
# :param content_type: One of the supported types by the application.
135-
# :return: `http_class` instance with requested information and content type if creation succeeds
136-
# :raises: `HTTPInternalServerError` instance details about requested information and content type if creation fails
137-
# """
138-
# content = str(content) if not isinstance(content, six.string_types) else content
139-
#
140-
# # adjust additional keyword arguments and try building the http response class with them
141-
# http_kwargs = {} if http_kwargs is None else http_kwargs
142-
# http_headers = http_kwargs.get("headers", {})
143-
# # omit content-type and related headers that we override
144-
# for header in dict(http_headers):
145-
# if header.lower().startswith("content-"):
146-
# http_headers.pop(header, None)
147-
#
148-
# try:
149-
# # Pass down Location if it is provided and should be given as input parameter for this HTTP class.
150-
# # Omitting this step would inject a (possibly extra) empty Location that defaults to the current application.
151-
# # When resolving HTTP redirects, injecting this extra Location when the requested one is not the current
152-
# # application will lead to redirection failures because all locations are appended in the header as CSV list.
153-
# if issubclass(http_class, HTTPRedirection):
154-
# location = get_header("Location", http_headers, pop=True)
155-
# if location and "location" not in http_kwargs:
156-
# http_kwargs["location"] = location
157-
#
158-
# # directly output json
159-
# if content_type == ContentType.APP_JSON:
160-
# content_type = "{}; charset=UTF-8".format(CONTENT_TYPE_JSON)
161-
# http_response = http_class(body=content, content_type=content_type, **http_kwargs)
162-
#
163-
# # otherwise json is contained within the html <body> section
164-
# elif content_type == ContentType.TEXT_HTML:
165-
# if http_class is HTTPOk:
166-
# http_class.explanation = "Operation successful."
167-
# if not http_class.explanation:
168-
# http_class.explanation = http_class.title # some don't have any defined
169-
# # add preformat <pre> section to output as is within the <body> section
170-
# html_status = "Exception" if http_class.code >= 400 else "Response"
171-
# html_header = "{}<br><h2>{} Details</h2>".format(http_class.explanation, html_status)
172-
# html_template = "<pre style='word-wrap: break-word; white-space: pre-wrap;'>{}</pre>"
173-
# content_type = "{}; charset=UTF-8".format(CONTENT_TYPE_HTML)
174-
# if json_content:
175-
# html_body = html_template.format(json.dumps(json_content, indent=True, ensure_ascii=False))
176-
# else:
177-
# html_body = html_template.format(content)
178-
# html_body = html_header + html_body
179-
# http_response = http_class(body_template=html_body, content_type=content_type, **http_kwargs)
180-
#
181-
# elif content_type in [CONTENT_TYPE_APP_XML, CONTENT_TYPE_TXT_XML]:
182-
# xml_body = OutputFormat.convert(json_content, ContentType.APP_XML, item_root="response")
183-
# http_response = http_class(body=xml_body, content_type=CONTENT_TYPE_TXT_XML, **http_kwargs)
184-
#
185-
# # default back to plain text
186-
# else:
187-
# http_response = http_class(body=content, content_type=CONTENT_TYPE_PLAIN, **http_kwargs)
188-
#
189-
# return http_response
190-
# except Exception as exc: # pylint: disable=W0703
191-
# raise HTTPInternalServerError(json={
192-
# "detail": "Failed to build HTTP response",
193-
# "cause": repr(exc),
194-
# "value": str(content_type),
195-
# })
196-
197124
# FIXME:
198125
# https://github.com/crim-ca/weaver/issues/215
199126
# define common Exception classes that won't require this type of conversion
@@ -208,7 +135,12 @@ def error_repr(http_err):
208135
if not isinstance(http_err, (HTTPException, OWSException)):
209136
return f"({err_type}) {http_err!s}"
210137
err_code = getattr(http_err, "code", getattr(http_err, "status_code", 500))
211-
err_repr = str(http_err)
138+
# in some cases, cornice will wrap HTTPError incorrectly without 'detail'
139+
# (see https://github.com/Cornices/cornice/issues/586)
140+
try:
141+
err_repr = str(http_err)
142+
except (AttributeError, NameError):
143+
err_repr = err_type
212144
try:
213145
# FIXME: handle colander invalid directly in tween (https://github.com/crim-ca/weaver/issues/112)
214146
# specific cleanup in case of string representation of colander.Invalid to help debug logged errors
@@ -301,7 +233,7 @@ def handle_ows_tween(request):
301233
# names must differ to avoid conflicting configuration error
302234
OWS_RESPONSE_EXCVIEW = fully_qualified_name(ows_response_tween_factory_excview)
303235
OWS_RESPONSE_INGRESS = fully_qualified_name(ows_response_tween_factory_ingress)
304-
HTTP_FORMAT_VALIDATE = fully_qualified_name(http_validate_response_format_tween_factory)
236+
#HTTP_FORMAT_VALIDATE = fully_qualified_name(http_validate_response_format_tween_factory)
305237
HTTP_FORMAT_RESPONSE = fully_qualified_name(http_apply_response_format_tween_factory)
306238

307239

@@ -312,7 +244,7 @@ def includeme(config):
312244
config.add_tween(OWS_RESPONSE_INGRESS, under=INGRESS)
313245

314246
# intermediate tweens to modify the request/response
315-
config.add_tween(HTTP_FORMAT_VALIDATE, over=MAIN)
247+
#config.add_tween(HTTP_FORMAT_VALIDATE, over=MAIN)
316248
config.add_tween(HTTP_FORMAT_RESPONSE, over=OWS_RESPONSE_EXCVIEW)
317249

318250
# using 'EXCVIEW' to run over any other 'valid' exception raised to adjust formatting and log

0 commit comments

Comments
 (0)