py2http 0.1.60__tar.gz → 0.1.62__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py2http-0.1.60 → py2http-0.1.62}/PKG-INFO +16 -4
- {py2http-0.1.60 → py2http-0.1.62}/py2http/__init__.py +6 -6
- {py2http-0.1.60 → py2http-0.1.62}/py2http/bottle_plugins.py +18 -19
- {py2http-0.1.60 → py2http-0.1.62}/py2http/config.py +20 -19
- {py2http-0.1.60 → py2http-0.1.62}/py2http/constants.py +6 -5
- {py2http-0.1.60 → py2http-0.1.62}/py2http/decorators.py +131 -75
- {py2http-0.1.60 → py2http-0.1.62}/py2http/default_configs.py +38 -38
- {py2http-0.1.60 → py2http-0.1.62}/py2http/diagnosis.py +1 -2
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/example_service.py +2 -2
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/example_service_bottle.py +5 -5
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/example_service_flask.py +3 -3
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/object_dispatch.py +13 -10
- {py2http-0.1.60 → py2http-0.1.62}/py2http/middleware.py +21 -20
- {py2http-0.1.60 → py2http-0.1.62}/py2http/openapi_utils.py +82 -82
- {py2http-0.1.60 → py2http-0.1.62}/py2http/route_utils.py +11 -10
- {py2http-0.1.60 → py2http-0.1.62}/py2http/schema_tools.py +96 -54
- {py2http-0.1.60 → py2http-0.1.62}/py2http/service.py +112 -95
- py2http-0.1.62/py2http/tests/example_service_test.py +33 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/simple_run_process_test.py +9 -6
- py2http-0.1.62/py2http/tests/test_binary_req.py +114 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/test_decorators.py +9 -9
- py2http-0.1.62/py2http/tests/test_not_set_defaults.py +73 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/test_p2h2p.py +14 -15
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/utils_for_testing.py +4 -4
- {py2http-0.1.60 → py2http-0.1.62}/py2http/types.py +6 -4
- {py2http-0.1.60 → py2http-0.1.62}/py2http/util.py +45 -39
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/PKG-INFO +16 -4
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/SOURCES.txt +2 -0
- {py2http-0.1.60 → py2http-0.1.62}/setup.cfg +1 -2
- py2http-0.1.60/py2http/tests/example_service_test.py +0 -33
- {py2http-0.1.60 → py2http-0.1.62}/LICENSE +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/README.md +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/__init__.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/custom_input_mapper.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/examples/custom_input_mappers.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/__init__.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/objects_for_testing.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http/tests/test_flask.py +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/dependency_links.txt +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/not-zip-safe +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/requires.txt +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/py2http.egg-info/top_level.txt +0 -0
- {py2http-0.1.60 → py2http-0.1.62}/setup.py +0 -0
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: py2http
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.62
|
|
4
4
|
Summary: Declarative HTTP service entry point.
|
|
5
5
|
Home-page: https://github.com/i2mint/py2http
|
|
6
|
-
Author: Otosense
|
|
7
6
|
License: MIT
|
|
8
7
|
Keywords: http service,web service
|
|
9
8
|
Platform: any
|
|
10
9
|
Description-Content-Type: text/markdown
|
|
11
|
-
Provides-Extra: testing
|
|
12
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: bottle
|
|
12
|
+
Requires-Dist: PyJWT[crypto]
|
|
13
|
+
Requires-Dist: aiohttp
|
|
14
|
+
Requires-Dist: i2
|
|
15
|
+
Requires-Dist: glom
|
|
16
|
+
Requires-Dist: gunicorn
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: strand
|
|
19
|
+
Requires-Dist: swagger-ui-py
|
|
20
|
+
Requires-Dist: pycparser
|
|
21
|
+
Requires-Dist: http2py
|
|
22
|
+
Provides-Extra: testing
|
|
23
|
+
Requires-Dist: http2py; extra == "testing"
|
|
24
|
+
Dynamic: license-file
|
|
13
25
|
|
|
14
26
|
[Documentation here](https://i2mint.github.io/py2http/)
|
|
15
27
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""This module provides functionality to easily create HTTP services from Python
|
|
2
|
-
functions and class methods. It includes features such as method transformation,
|
|
3
|
-
input mapping, output mapping, error handling, and client generation.
|
|
4
|
-
The module also allows for customization through various configuration options
|
|
5
|
-
and provides the ability to generate OpenAPI specifications for the created HTTP
|
|
6
|
-
services. Additionally, it includes middleware, plugins, and decorators to enhance
|
|
1
|
+
"""This module provides functionality to easily create HTTP services from Python
|
|
2
|
+
functions and class methods. It includes features such as method transformation,
|
|
3
|
+
input mapping, output mapping, error handling, and client generation.
|
|
4
|
+
The module also allows for customization through various configuration options
|
|
5
|
+
and provides the ability to generate OpenAPI specifications for the created HTTP
|
|
6
|
+
services. Additionally, it includes middleware, plugins, and decorators to enhance
|
|
7
7
|
the functionality of the HTTP services."""
|
|
8
8
|
|
|
9
9
|
from .middleware import mk_jwt_middleware, mk_superadmin_middleware
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""Plugins for adding middleware functionality to Bottle apps.
|
|
2
|
-
"""
|
|
1
|
+
"""Plugins for adding middleware functionality to Bottle apps."""
|
|
3
2
|
|
|
4
3
|
from bottle import request, response, abort
|
|
5
4
|
from functools import wraps
|
|
@@ -9,7 +8,7 @@ from typing import Iterable
|
|
|
9
8
|
from warnings import warn
|
|
10
9
|
from py2http.constants import JSON_CONTENT_TYPE
|
|
11
10
|
|
|
12
|
-
OPTIONS =
|
|
11
|
+
OPTIONS = "OPTIONS"
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class JWTPlugin:
|
|
@@ -21,7 +20,7 @@ class JWTPlugin:
|
|
|
21
20
|
|
|
22
21
|
def __init__(
|
|
23
22
|
self,
|
|
24
|
-
secret: str =
|
|
23
|
+
secret: str = "",
|
|
25
24
|
verify: bool = True,
|
|
26
25
|
mapper: dict = None,
|
|
27
26
|
ignore_methods: Iterable[str] = None,
|
|
@@ -39,7 +38,7 @@ class JWTPlugin:
|
|
|
39
38
|
self._verify = verify
|
|
40
39
|
self._mapper = mapper if mapper else {}
|
|
41
40
|
self._ignore_methods = ignore_methods if ignore_methods else []
|
|
42
|
-
self._algorithms = algorithms if algorithms else [
|
|
41
|
+
self._algorithms = algorithms if algorithms else ["HS256"]
|
|
43
42
|
|
|
44
43
|
def __call__(self, handler):
|
|
45
44
|
if self._ignore_methods and handler.method_name in self._ignore_methods:
|
|
@@ -49,13 +48,13 @@ class JWTPlugin:
|
|
|
49
48
|
def wrapped_handler(*args, **kwargs):
|
|
50
49
|
if request.method == OPTIONS:
|
|
51
50
|
return handler(*args, *kwargs)
|
|
52
|
-
auth_header = request.headers.get(
|
|
51
|
+
auth_header = request.headers.get("Authorization", "")
|
|
53
52
|
token = auth_header[7:]
|
|
54
53
|
try:
|
|
55
54
|
decoded = jwt.decode(
|
|
56
55
|
token,
|
|
57
56
|
self._secret,
|
|
58
|
-
options={
|
|
57
|
+
options={"verify_signature": self._verify},
|
|
59
58
|
algorithms=self._algorithms,
|
|
60
59
|
)
|
|
61
60
|
for k, v in self._mapper.items():
|
|
@@ -69,10 +68,10 @@ class JWTPlugin:
|
|
|
69
68
|
response.content_type = JSON_CONTENT_TYPE
|
|
70
69
|
return json.dumps(
|
|
71
70
|
{
|
|
72
|
-
|
|
71
|
+
"error": f'Invalid authentication token "{token}", {str(error)}'
|
|
73
72
|
}
|
|
74
73
|
)
|
|
75
|
-
warn(f
|
|
74
|
+
warn(f"Invalid JWT: {token}")
|
|
76
75
|
return handler(*args, **kwargs)
|
|
77
76
|
|
|
78
77
|
return wrapped_handler
|
|
@@ -84,12 +83,12 @@ class ApiKeyAuthPlugin:
|
|
|
84
83
|
|
|
85
84
|
def __call__(self, handler):
|
|
86
85
|
def wrapped_handler(*args, **kwargs):
|
|
87
|
-
auth_header = request.headers.get(
|
|
86
|
+
auth_header = request.headers.get("Authorization", "")
|
|
88
87
|
if auth_header == self._api_key:
|
|
89
88
|
return handler(*args, **kwargs)
|
|
90
89
|
response.status = 401
|
|
91
90
|
response.content_type = JSON_CONTENT_TYPE
|
|
92
|
-
return json.dumps({
|
|
91
|
+
return json.dumps({"error": "invalid API key"})
|
|
93
92
|
|
|
94
93
|
return wrapped_handler
|
|
95
94
|
|
|
@@ -97,18 +96,18 @@ class ApiKeyAuthPlugin:
|
|
|
97
96
|
# from https://stackoverflow.com/questions/17262170/bottle-py-enabling-cors-for-jquery-ajax-requests
|
|
98
97
|
# TODO: accept lists of headers and methods as init args
|
|
99
98
|
class CorsPlugin:
|
|
100
|
-
def __init__(self, origins: str =
|
|
99
|
+
def __init__(self, origins: str = "*"):
|
|
101
100
|
self._origins = origins
|
|
102
101
|
|
|
103
102
|
def __call__(self, handler):
|
|
104
103
|
def wrapped_handler(*args, **kwargs):
|
|
105
|
-
response.headers[
|
|
106
|
-
response.headers[
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
response.headers[
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
response.headers["Access-Control-Allow-Origin"] = self._origins
|
|
105
|
+
response.headers["Access-Control-Allow-Methods"] = (
|
|
106
|
+
"GET, POST, PUT, DELETE, OPTIONS"
|
|
107
|
+
)
|
|
108
|
+
response.headers["Access-Control-Allow-Headers"] = (
|
|
109
|
+
"Origin, Accept, Content-Type, X-Requested-With, Authorization, X-api-key"
|
|
110
|
+
)
|
|
112
111
|
if request.method != OPTIONS:
|
|
113
112
|
return handler(*args, **kwargs)
|
|
114
113
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
"""The code module provides functions for retrieving configuration values for a
|
|
2
|
-
function based on a hierarchy of sources, including function properties,
|
|
3
|
-
configuration dictionaries, and default values. The `get_result` function is used to
|
|
4
|
-
allow nested configurations by function name, with an example provided in the docstring
|
|
5
|
-
for illustration.
|
|
1
|
+
"""The code module provides functions for retrieving configuration values for a
|
|
2
|
+
function based on a hierarchy of sources, including function properties,
|
|
3
|
+
configuration dictionaries, and default values. The `get_result` function is used to
|
|
4
|
+
allow nested configurations by function name, with an example provided in the docstring
|
|
5
|
+
for illustration.
|
|
6
6
|
|
|
7
|
-
The `mk_config` function is used to get a configuration value for a function by checking
|
|
8
|
-
the function properties, configuration dictionaries, and default values. It also allows
|
|
9
|
-
for specifying the expected type of the output, with options to provide additional
|
|
10
|
-
options such as the function name and expected type.
|
|
7
|
+
The `mk_config` function is used to get a configuration value for a function by checking
|
|
8
|
+
the function properties, configuration dictionaries, and default values. It also allows
|
|
9
|
+
for specifying the expected type of the output, with options to provide additional
|
|
10
|
+
options such as the function name and expected type.
|
|
11
11
|
|
|
12
|
-
Overall, the module helps manage and retrieve configuration values for functions,
|
|
12
|
+
Overall, the module helps manage and retrieve configuration values for functions,
|
|
13
13
|
ensuring they are appropriately set and validated based on the function's requirements.
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
from typing import Callable
|
|
16
17
|
|
|
17
|
-
AIOHTTP =
|
|
18
|
-
BOTTLE =
|
|
19
|
-
FLASK =
|
|
18
|
+
AIOHTTP = "aiohttp"
|
|
19
|
+
BOTTLE = "bottle"
|
|
20
|
+
FLASK = "flask"
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def get_result(configs, func, funcname, key, options):
|
|
@@ -41,9 +42,9 @@ def get_result(configs, func, funcname, key, options):
|
|
|
41
42
|
dict_value = result.get(funcname, None)
|
|
42
43
|
if dict_value:
|
|
43
44
|
result = dict_value
|
|
44
|
-
elif
|
|
45
|
-
result = result[
|
|
46
|
-
elif options.get(
|
|
45
|
+
elif "$else" in result:
|
|
46
|
+
result = result["$else"]
|
|
47
|
+
elif options.get("type", None) is not dict:
|
|
47
48
|
result = None
|
|
48
49
|
return result
|
|
49
50
|
|
|
@@ -66,12 +67,12 @@ def mk_config(key, func, configs, defaults, **options):
|
|
|
66
67
|
* *type*
|
|
67
68
|
The expected type of the output (use Callable for functions)
|
|
68
69
|
"""
|
|
69
|
-
funcname = options.get(
|
|
70
|
+
funcname = options.get("funcname", getattr(func, "__name__", None))
|
|
70
71
|
|
|
71
72
|
result = get_result(configs, func, funcname, key, options)
|
|
72
73
|
|
|
73
74
|
if result:
|
|
74
|
-
expected_type = options.get(
|
|
75
|
+
expected_type = options.get("type", None) # align names expected_type <-> type
|
|
75
76
|
if not expected_type:
|
|
76
77
|
assert key in defaults, f'Missing default value for key "{key}"'
|
|
77
78
|
default_value = defaults.get(key)
|
|
@@ -81,7 +82,7 @@ def mk_config(key, func, configs, defaults, **options):
|
|
|
81
82
|
expected_type = type(default_value)
|
|
82
83
|
assert expected_type == type(None) or isinstance(
|
|
83
84
|
result, expected_type
|
|
84
|
-
), f
|
|
85
|
+
), f"Config {key} does not match type {expected_type}."
|
|
85
86
|
else:
|
|
86
87
|
result = defaults.get(key, None)
|
|
87
88
|
return result
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""This module provides functionality for dispatching Python functions as HTTP services. It allows users to create a basic HTTP server from a list of functions or instance methods, customize input and output mapping, handle errors, generate client code from an OpenAPI specification, and configure various aspects of the server setup. The module includes features for transforming class methods, mapping input and output data, handling errors, and generating client code. It also supports configuration options for the HTTP framework, input and output mappers, error handlers, openAPI specifications, logging, middleware, plugins, CORS, SSL certificates, and more."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
JSON_CONTENT_TYPE = "application/json"
|
|
4
|
+
BINARY_CONTENT_TYPE = "application/octet-stream"
|
|
5
|
+
FORM_CONTENT_TYPE = "multipart/form-data"
|
|
6
|
+
RAW_CONTENT_TYPE = "text/plain"
|
|
7
|
+
HTML_CONTENT_TYPE = "text/html"
|