Browse Source

Flask compat: add all new ContextInterface method

Guénaël Muller 6 years ago
parent
commit
54d88e8ca6
1 changed files with 45 additions and 2 deletions
  1. 45 2
      hapic/ext/flask/context.py

+ 45 - 2
hapic/ext/flask/context.py View File

@@ -1,17 +1,28 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import json
3
+import re
3 4
 import typing
4 5
 from http import HTTPStatus
5 6
 
6 7
 from hapic.context import ContextInterface
8
+from hapic.context import RouteRepresentation
9
+from hapic.decorator import DecoratedController
10
+from hapic.decorator import DECORATION_ATTRIBUTE_NAME
7 11
 from hapic.exception import OutputValidationException
8 12
 from hapic.processor import RequestParameters, ProcessValidationError
13
+from flask import Flask
9 14
 
10 15
 if typing.TYPE_CHECKING:
11 16
     from flask import Response
12 17
 
18
+# flask regular expression to locate url parameters
19
+FLASK_RE_PATH_URL = re.compile(r'<(?:[^:<>]+:)?([^<>]+)>')
20
+
13 21
 
14 22
 class FlaskContext(ContextInterface):
23
+    def __init__(self, app: Flask):
24
+        self.app = app
25
+
15 26
     def get_request_parameters(self, *args, **kwargs) -> RequestParameters:
16 27
         from flask import request
17 28
         return RequestParameters(
@@ -56,5 +67,37 @@ class FlaskContext(ContextInterface):
56 67
             status=int(http_code),
57 68
         )
58 69
 
59
-# TODO BS 20171115: Implement other context methods
60
-# (take source in example_a_flask.py)
70
+    def find_route(
71
+        self,
72
+        decorated_controller: 'DecoratedController',
73
+    ):
74
+        reference = decorated_controller.reference
75
+        for route in self.app.url_map.iter_rules():
76
+            if route.endpoint not in self.app.view_functions:
77
+                continue
78
+            route_callback = self.app.view_functions[route.endpoint]
79
+            route_token = getattr(
80
+                route_callback,
81
+                DECORATION_ATTRIBUTE_NAME,
82
+                None,
83
+            )
84
+            match_with_wrapper = route_callback == reference.wrapper
85
+            match_with_wrapped = route_callback == reference.wrapped
86
+            match_with_token = route_token == reference.token
87
+
88
+            # FIXME - G.M - 2017-12-04 - return list instead of one method
89
+            # This fix, return only 1 allowed method, change this when
90
+            # RouteRepresentation is adapted to return multiples methods.
91
+            method = [x for x in route.methods
92
+                      if x not in ['OPTIONS', 'HEAD']][0]
93
+
94
+            if match_with_wrapper or match_with_wrapped or match_with_token:
95
+                return RouteRepresentation(
96
+                    rule=self.get_swagger_path(route.rule),
97
+                    method=method,
98
+                    original_route_object=route,
99
+                )
100
+
101
+    def get_swagger_path(self, contextualised_rule: str) -> str:
102
+        # TODO - G.M - 2017-12-05 Check if all route path are handled correctly
103
+        return FLASK_RE_PATH_URL.sub(r'{\1}', contextualised_rule)