Skip to content

Commit

Permalink
store query and path parameters equally
Browse files Browse the repository at this point in the history
  • Loading branch information
Rollmops committed Mar 12, 2020
1 parent 133cf09 commit f76ebc2
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 35 deletions.
4 changes: 2 additions & 2 deletions restit/internal/string_type_converter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Type, List
from typing import Type


class StringTypeConverter:
@staticmethod
def convert(string: str, into_type: Type):
if getattr(into_type, "_gorg", None) == List:
if getattr(into_type, "_name", None) == "List":
# noinspection PyUnresolvedReferences
return StringTypeConverter._convert_iterable(string, into_type.__args__[0], "[]", list)
if into_type == list:
Expand Down
15 changes: 9 additions & 6 deletions restit/open_api_documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,13 @@ def _add_query_parameters(method_spec: dict, method_object: object, resource: Re

@staticmethod
def _add_path_parameters(method_spec: dict, resource: Resource, inferred_path_parameters: List[PathParameter]):
parameter_definitions = resource.get_path_parameters()
for inferred_path_parameter in inferred_path_parameters:
if inferred_path_parameter.name not in parameter_definitions:
parameter_definitions[inferred_path_parameter.name] = inferred_path_parameter
parameter_definitions = getattr(resource, "__path_parameters__", [])
path_parameters = {
path_parameter.name: path_parameter for path_parameter in inferred_path_parameters
}
path_parameters.update({
path_parameter.name: path_parameter for path_parameter in parameter_definitions
})

method_spec["parameters"].extend([
{
Expand All @@ -89,7 +92,7 @@ def _add_path_parameters(method_spec: dict, resource: Resource, inferred_path_pa
"description": path_parameter.description,
"schema": OpenApiDocumentation._get_schema_from_type_and_default(path_parameter.type, None)

} for name, path_parameter in parameter_definitions.items()
} for name, path_parameter in path_parameters.items()
])

@staticmethod
Expand All @@ -105,7 +108,7 @@ def _infer_path_params_and_open_api_path_syntax(path: str) -> Tuple[str, List[Pa

def _handle_path_parameter(match: Match) -> str:
path_parameter_list.append(
PathParameter(match.group(1), eval(match.group(2)) if match.group(2) else str, None, None)
PathParameter(match.group(1), None, eval(match.group(2)) if match.group(2) else str)
)
return "{%s}" % match.group(1)

Expand Down
19 changes: 14 additions & 5 deletions restit/path_parameter_decorator.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
from typing import Type
import logging
from collections import namedtuple
from typing import Type, List

from restit.resource import Resource, PathParameter
LOGGER = logging.getLogger(__name__)

PathParameter = namedtuple("PathParameter", ["name", "description", "type"])


# noinspection PyShadowingBuiltins
def path_parameter(name: str, type=str, description: str = None, format: str = None):
def decorator(clazz: Type[Resource]):
clazz.add_path_parameter(PathParameter(name, type, description, format))
def path_parameter(name: str, description: str, type: Type = str):
def decorator(clazz):
_path_parameter = PathParameter(name, description, type)

registered_path_parameters: List[PathParameter] = getattr(clazz, "__path_parameters__", [])
LOGGER.debug("Registering path parameter %s for %s", _path_parameter, clazz.__name__)
registered_path_parameters.append(_path_parameter)
setattr(clazz, "__path_parameters__", registered_path_parameters)
return clazz

return decorator
1 change: 1 addition & 0 deletions restit/query_parameter_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
QueryParameter = namedtuple("QueryParameter", ["name", "description", "type", "required", "default"])


# noinspection PyShadowingBuiltins
def query_parameter(name: str, description: str, type: Type = str, required: bool = True, default: Any = None):
def decorator(func):
_query_parameter = QueryParameter(name, description, type, required, default)
Expand Down
16 changes: 2 additions & 14 deletions restit/resource.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
from collections import namedtuple, defaultdict
from typing import Tuple, AnyStr, Dict, Union

from werkzeug.exceptions import MethodNotAllowed, BadRequest

from restit.internal.resource_path import ResourcePath
from restit.internal.string_type_converter import StringTypeConverter
from restit.path_parameter_decorator import PathParameter
from restit.query_parameter_decorator import QueryParameter
from restit.request import Request
from restit.response import Response

PathParameter = namedtuple("PathParameter", ["name", "type", "description", "format"])

_PATH_PARAMETER_MAPPING = defaultdict(dict)


class Resource:
__request_mapping__ = None

def __init__(self):
self._resource_path = None

@classmethod
def add_path_parameter(cls, path_parameter: PathParameter):
_PATH_PARAMETER_MAPPING[cls][path_parameter.name] = path_parameter

@classmethod
def get_path_parameters(cls) -> dict:
return _PATH_PARAMETER_MAPPING[cls]

def init(self):
self._resource_path = ResourcePath(self.__request_mapping__)

Expand Down Expand Up @@ -83,7 +71,7 @@ def _process_query_parameters(method_object, request):
request.query_parameters[query_parameter.name] = StringTypeConverter.convert(value, query_parameter.type)

def _collect_and_convert_path_parameters(self, path_params: dict):
for path_parameter in _PATH_PARAMETER_MAPPING[self.__class__].values():
for path_parameter in getattr(self, "__path_parameters__", []): # type: PathParameter
try:
path_parameter_value = path_params[path_parameter.name]
except KeyError:
Expand Down
2 changes: 0 additions & 2 deletions test/restit/internal/open_api_spec_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ def test_serve_open_api(self):
OpenApiDocumentation(title="First documentation", description="", version="1.2.3")
)

restit_app.start_development_server()

with restit_app.start_development_server_in_context(port=0) as port:
response = requests.get(f"http://127.0.0.1:{port}/api")
self.assertEqual(200, response.status_code)
Expand Down
10 changes: 4 additions & 6 deletions test/restit/path_parameter_decorator_test.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import unittest
from collections import namedtuple

from restit import request_mapping, Request, Response, path_parameter, RestitApp, RestitTestApp
from restit.resource import Resource

PathParam = namedtuple("PathParam", ["name", "schema", "description"])


@request_mapping("/path/:id1/and/:id2/and/:id3")
@path_parameter("id1", type=int, description="First path parameter")
@path_parameter("id2", type=float, description="Second path parameter")
@path_parameter("id3")
@path_parameter("id3", description="Id3")
class Resource1(Resource):
def get(self, request: Request, **path_params) -> Response:
return Response(path_params)
Expand All @@ -32,7 +29,8 @@ def test_conversion_exception(self):
self.assertEqual(
"<title>400 Bad Request</title>\n"
"<h1>Bad Request</h1>\n"
"<p>Path parameter value 'hans' is not matching 'PathParameter(name='id2', type=<class 'float'>, "
"description='Second path parameter', format=None)' (could not convert string to float: 'hans')</p>\n",
"<p>Path parameter value 'hans' is not matching 'PathParameter(name='id2', "
"description='Second path parameter', type=<class 'float'>)' "
"(could not convert string to float: 'hans')</p>\n",
response.text
)

0 comments on commit f76ebc2

Please sign in to comment.