polyapi-python 0.3.13.dev1__py3-none-any.whl → 0.3.14__py3-none-any.whl
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.
- polyapi/__init__.py +106 -44
- polyapi/api.py +19 -0
- polyapi/auth.py +33 -0
- polyapi/cli.py +1 -3
- polyapi/cli_constants.py +10 -0
- polyapi/constants.py +7 -4
- polyapi/execute.py +168 -53
- polyapi/function_cli.py +3 -4
- polyapi/generate.py +2 -2
- polyapi/http_client.py +73 -0
- polyapi/poly_tables.py +111 -43
- polyapi/prepare.py +3 -4
- polyapi/rendered_spec.py +3 -3
- polyapi/server.py +14 -0
- polyapi/sync.py +4 -5
- polyapi/utils.py +16 -3
- polyapi/variables.py +10 -0
- polyapi/webhook.py +1 -5
- {polyapi_python-0.3.13.dev1.dist-info → polyapi_python-0.3.14.dist-info}/METADATA +13 -4
- polyapi_python-0.3.14.dist-info/RECORD +34 -0
- {polyapi_python-0.3.13.dev1.dist-info → polyapi_python-0.3.14.dist-info}/WHEEL +1 -1
- polyapi_python-0.3.13.dev1.dist-info/RECORD +0 -32
- {polyapi_python-0.3.13.dev1.dist-info → polyapi_python-0.3.14.dist-info}/licenses/LICENSE +0 -0
- {polyapi_python-0.3.13.dev1.dist-info → polyapi_python-0.3.14.dist-info}/top_level.txt +0 -0
polyapi/__init__.py
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import copy
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
|
-
import
|
|
4
|
+
from contextvars import ContextVar, Token
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, Dict, Literal, Optional, overload
|
|
7
|
+
|
|
4
8
|
import truststore
|
|
5
|
-
from typing import Any, Dict, Optional, overload, Literal
|
|
6
9
|
from typing_extensions import TypedDict
|
|
10
|
+
|
|
11
|
+
from .cli_constants import CLI_COMMANDS
|
|
12
|
+
|
|
7
13
|
truststore.inject_into_ssl()
|
|
8
|
-
from .cli import CLI_COMMANDS
|
|
9
14
|
|
|
10
15
|
__all__ = ["poly"]
|
|
11
16
|
|
|
@@ -19,83 +24,140 @@ if len(sys.argv) > 1 and sys.argv[1] not in CLI_COMMANDS:
|
|
|
19
24
|
|
|
20
25
|
class PolyCustomDict(TypedDict, total=False):
|
|
21
26
|
"""Type definition for polyCustom dictionary."""
|
|
22
|
-
|
|
27
|
+
|
|
28
|
+
executionId: Optional[str] # Read-only unless explicitly unlocked
|
|
23
29
|
executionApiKey: Optional[str]
|
|
24
|
-
|
|
30
|
+
userSessionId: Optional[str]
|
|
31
|
+
responseStatusCode: Optional[int]
|
|
25
32
|
responseContentType: Optional[str]
|
|
26
|
-
responseHeaders: Dict[str,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
responseHeaders: Dict[str, Any]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class _PolyCustomState:
|
|
38
|
+
internal_store: Dict[str, Any]
|
|
39
|
+
execution_id_locked: bool = False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class PolyCustom:
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
object.__setattr__(
|
|
45
|
+
self,
|
|
46
|
+
"_default_store",
|
|
47
|
+
{
|
|
48
|
+
"executionId": None,
|
|
49
|
+
"executionApiKey": None,
|
|
50
|
+
"userSessionId": None,
|
|
51
|
+
"responseStatusCode": 200,
|
|
52
|
+
"responseContentType": None,
|
|
53
|
+
"responseHeaders": {},
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
object.__setattr__(self, "_state_var", ContextVar("_poly_custom_state", default=None))
|
|
57
|
+
|
|
58
|
+
def _make_state(self) -> _PolyCustomState:
|
|
59
|
+
return _PolyCustomState(internal_store=copy.deepcopy(self._default_store))
|
|
60
|
+
|
|
61
|
+
def _get_state(self) -> _PolyCustomState:
|
|
62
|
+
state = self._state_var.get()
|
|
63
|
+
if state is None:
|
|
64
|
+
state = self._make_state()
|
|
65
|
+
self._state_var.set(state)
|
|
66
|
+
return state
|
|
67
|
+
|
|
68
|
+
def push_scope(self, initial_values: Optional[Dict[str, Any]] = None) -> Token:
|
|
69
|
+
state = self._make_state()
|
|
70
|
+
if initial_values:
|
|
71
|
+
state.internal_store.update(copy.deepcopy(initial_values))
|
|
72
|
+
if state.internal_store.get("executionId") is not None:
|
|
73
|
+
state.execution_id_locked = True
|
|
74
|
+
return self._state_var.set(state)
|
|
75
|
+
|
|
76
|
+
def pop_scope(self, token: Token) -> None:
|
|
77
|
+
self._state_var.reset(token)
|
|
39
78
|
|
|
40
79
|
def set_once(self, key: str, value: Any) -> None:
|
|
41
|
-
|
|
42
|
-
|
|
80
|
+
state = self._get_state()
|
|
81
|
+
if key == "executionId" and state.execution_id_locked:
|
|
43
82
|
return
|
|
44
|
-
|
|
83
|
+
state.internal_store[key] = value
|
|
45
84
|
if key == "executionId":
|
|
46
|
-
|
|
47
|
-
self.lock_execution_id()
|
|
85
|
+
state.execution_id_locked = True
|
|
48
86
|
|
|
49
87
|
def get(self, key: str, default: Any = None) -> Any:
|
|
50
|
-
return self.
|
|
88
|
+
return self._get_state().internal_store.get(key, default)
|
|
51
89
|
|
|
52
90
|
def lock_execution_id(self) -> None:
|
|
53
|
-
self.
|
|
91
|
+
self._get_state().execution_id_locked = True
|
|
54
92
|
|
|
55
93
|
def unlock_execution_id(self) -> None:
|
|
56
|
-
self.
|
|
94
|
+
self._get_state().execution_id_locked = False
|
|
57
95
|
|
|
58
96
|
@overload
|
|
59
97
|
def __getitem__(self, key: Literal["executionId"]) -> Optional[str]: ...
|
|
60
|
-
|
|
98
|
+
|
|
61
99
|
@overload
|
|
62
100
|
def __getitem__(self, key: Literal["executionApiKey"]) -> Optional[str]: ...
|
|
63
|
-
|
|
101
|
+
|
|
64
102
|
@overload
|
|
65
|
-
def __getitem__(self, key: Literal["
|
|
66
|
-
|
|
103
|
+
def __getitem__(self, key: Literal["userSessionId"]) -> Optional[str]: ...
|
|
104
|
+
|
|
105
|
+
@overload
|
|
106
|
+
def __getitem__(self, key: Literal["responseStatusCode"]) -> Optional[int]: ...
|
|
107
|
+
|
|
67
108
|
@overload
|
|
68
109
|
def __getitem__(self, key: Literal["responseContentType"]) -> Optional[str]: ...
|
|
69
110
|
|
|
70
111
|
@overload
|
|
71
|
-
def __getitem__(self, key: Literal["responseHeaders"]) -> Dict[str,
|
|
72
|
-
|
|
112
|
+
def __getitem__(self, key: Literal["responseHeaders"]) -> Dict[str, Any]: ...
|
|
113
|
+
|
|
73
114
|
def __getitem__(self, key: str) -> Any:
|
|
74
115
|
return self.get(key)
|
|
75
116
|
|
|
76
117
|
@overload
|
|
77
118
|
def __setitem__(self, key: Literal["executionApiKey"], value: Optional[str]) -> None: ...
|
|
78
|
-
|
|
119
|
+
|
|
120
|
+
@overload
|
|
121
|
+
def __setitem__(self, key: Literal["userSessionId"], value: Optional[str]) -> None: ...
|
|
122
|
+
|
|
79
123
|
@overload
|
|
80
|
-
def __setitem__(self, key: Literal["responseStatusCode"], value: int) -> None: ...
|
|
81
|
-
|
|
124
|
+
def __setitem__(self, key: Literal["responseStatusCode"], value: Optional[int]) -> None: ...
|
|
125
|
+
|
|
82
126
|
@overload
|
|
83
127
|
def __setitem__(self, key: Literal["responseContentType"], value: Optional[str]) -> None: ...
|
|
84
128
|
|
|
85
129
|
@overload
|
|
86
|
-
def __setitem__(self, key: Literal["responseHeaders"], value: Dict[str,
|
|
87
|
-
|
|
130
|
+
def __setitem__(self, key: Literal["responseHeaders"], value: Dict[str, Any]) -> None: ...
|
|
131
|
+
|
|
88
132
|
def __setitem__(self, key: str, value: Any) -> None:
|
|
89
133
|
self.set_once(key, value)
|
|
90
134
|
|
|
91
|
-
def
|
|
92
|
-
|
|
135
|
+
def __getattr__(self, key: str) -> Any:
|
|
136
|
+
if key in self._default_store:
|
|
137
|
+
return self.get(key)
|
|
138
|
+
raise AttributeError(f"{type(self).__name__!r} object has no attribute {key!r}")
|
|
139
|
+
|
|
140
|
+
def __setattr__(self, key: str, value: Any) -> None:
|
|
141
|
+
if key.startswith("_"):
|
|
142
|
+
object.__setattr__(self, key, value)
|
|
143
|
+
return
|
|
144
|
+
self.set_once(key, value)
|
|
93
145
|
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
146
|
+
def __repr__(self) -> str:
|
|
147
|
+
return f"PolyCustom({self._get_state().internal_store})"
|
|
148
|
+
|
|
149
|
+
def copy(self) -> "PolyCustom":
|
|
150
|
+
new = PolyCustom()
|
|
151
|
+
state = self._get_state()
|
|
152
|
+
new._state_var.set(
|
|
153
|
+
_PolyCustomState(
|
|
154
|
+
internal_store=copy.deepcopy(state.internal_store),
|
|
155
|
+
execution_id_locked=state.execution_id_locked,
|
|
156
|
+
)
|
|
157
|
+
)
|
|
98
158
|
return new
|
|
99
159
|
|
|
100
160
|
|
|
101
|
-
|
|
161
|
+
_PolyCustom = PolyCustom
|
|
162
|
+
|
|
163
|
+
polyCustom: PolyCustom = PolyCustom()
|
polyapi/api.py
CHANGED
|
@@ -35,6 +35,25 @@ def {function_name}(
|
|
|
35
35
|
return {api_response_type}(resp.json()) # type: ignore
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
async def {function_name}_async(
|
|
39
|
+
{args}
|
|
40
|
+
) -> {api_response_type}:
|
|
41
|
+
\"""{function_description}
|
|
42
|
+
|
|
43
|
+
Function ID: {function_id}
|
|
44
|
+
\"""
|
|
45
|
+
if get_direct_execute_config():
|
|
46
|
+
resp = await direct_execute_async("{function_type}", "{function_id}", {data})
|
|
47
|
+
return {api_response_type}({{
|
|
48
|
+
"status": resp.status_code,
|
|
49
|
+
"headers": dict(resp.headers),
|
|
50
|
+
"data": resp.json()
|
|
51
|
+
}}) # type: ignore
|
|
52
|
+
else:
|
|
53
|
+
resp = await execute_async("{function_type}", "{function_id}", {data})
|
|
54
|
+
return {api_response_type}(resp.json()) # type: ignore
|
|
55
|
+
|
|
56
|
+
|
|
38
57
|
"""
|
|
39
58
|
|
|
40
59
|
|
polyapi/auth.py
CHANGED
|
@@ -117,6 +117,16 @@ def introspectToken(token: str) -> AuthFunctionResponse:
|
|
|
117
117
|
url = "/auth-providers/{function_id}/introspect"
|
|
118
118
|
resp = execute_post(url, {{"token": token}})
|
|
119
119
|
return resp.json()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
async def introspectToken_async(token: str) -> AuthFunctionResponse:
|
|
123
|
+
\"""{description}
|
|
124
|
+
|
|
125
|
+
Function ID: {function_id}
|
|
126
|
+
\"""
|
|
127
|
+
url = "/auth-providers/{function_id}/introspect"
|
|
128
|
+
resp = await execute_post_async(url, {{"token": token}})
|
|
129
|
+
return resp.json()
|
|
120
130
|
"""
|
|
121
131
|
|
|
122
132
|
REFRESH_TOKEN_TEMPLATE = """
|
|
@@ -128,6 +138,16 @@ def refreshToken(token: str) -> AuthFunctionResponse:
|
|
|
128
138
|
url = "/auth-providers/{function_id}/refresh"
|
|
129
139
|
resp = execute_post(url, {{"token": token}})
|
|
130
140
|
return resp.json()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
async def refreshToken_async(token: str) -> AuthFunctionResponse:
|
|
144
|
+
\"""{description}
|
|
145
|
+
|
|
146
|
+
Function ID: {function_id}
|
|
147
|
+
\"""
|
|
148
|
+
url = "/auth-providers/{function_id}/refresh"
|
|
149
|
+
resp = await execute_post_async(url, {{"token": token}})
|
|
150
|
+
return resp.json()
|
|
131
151
|
"""
|
|
132
152
|
|
|
133
153
|
REVOKE_TOKEN_TEMPLATE = """
|
|
@@ -142,6 +162,19 @@ def revokeToken(token: str) -> Optional[AuthFunctionResponse]:
|
|
|
142
162
|
return resp.json()
|
|
143
163
|
except:
|
|
144
164
|
return None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def revokeToken_async(token: str) -> Optional[AuthFunctionResponse]:
|
|
168
|
+
\"""{description}
|
|
169
|
+
|
|
170
|
+
Function ID: {function_id}
|
|
171
|
+
\"""
|
|
172
|
+
url = "/auth-providers/{function_id}/revoke"
|
|
173
|
+
resp = await execute_post_async(url, {{"token": token}})
|
|
174
|
+
try:
|
|
175
|
+
return resp.json()
|
|
176
|
+
except:
|
|
177
|
+
return None
|
|
145
178
|
"""
|
|
146
179
|
|
|
147
180
|
|
polyapi/cli.py
CHANGED
|
@@ -3,6 +3,7 @@ import argparse
|
|
|
3
3
|
|
|
4
4
|
from polyapi.utils import print_green, print_red
|
|
5
5
|
|
|
6
|
+
from .cli_constants import CLI_COMMANDS
|
|
6
7
|
from .config import initialize_config, set_api_key_and_url
|
|
7
8
|
from .generate import generate, clear
|
|
8
9
|
from .function_cli import function_add_or_update, function_execute
|
|
@@ -11,9 +12,6 @@ from .prepare import prepare_deployables
|
|
|
11
12
|
from .sync import sync_deployables
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
CLI_COMMANDS = ["setup", "generate", "function", "clear", "help", "update_rendered_spec"]
|
|
15
|
-
|
|
16
|
-
|
|
17
15
|
def _get_version_string():
|
|
18
16
|
"""Get the version string for the package."""
|
|
19
17
|
try:
|
polyapi/cli_constants.py
ADDED
polyapi/constants.py
CHANGED
|
@@ -3,8 +3,8 @@ JSONSCHEMA_TO_PYTHON_TYPE_MAP = {
|
|
|
3
3
|
"number": "float",
|
|
4
4
|
"string": "str",
|
|
5
5
|
"boolean": "bool",
|
|
6
|
-
"array": "
|
|
7
|
-
"object": "
|
|
6
|
+
"array": "list",
|
|
7
|
+
"object": "dict",
|
|
8
8
|
"function": "Callable",
|
|
9
9
|
"void": "None",
|
|
10
10
|
}
|
|
@@ -15,10 +15,13 @@ PYTHON_TO_JSONSCHEMA_TYPE_MAP = {
|
|
|
15
15
|
"float": "number",
|
|
16
16
|
"str": "string",
|
|
17
17
|
"bool": "boolean",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"list": "array",
|
|
19
|
+
"dict": "object",
|
|
20
20
|
"Callable": "function",
|
|
21
21
|
"None": "void",
|
|
22
|
+
# Keep uppercase aliases for backwards compatibility
|
|
23
|
+
"List": "array",
|
|
24
|
+
"Dict": "object",
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
BASIC_PYTHON_TYPES = set(PYTHON_TO_JSONSCHEMA_TYPE_MAP.keys())
|
polyapi/execute.py
CHANGED
|
@@ -1,109 +1,224 @@
|
|
|
1
|
-
|
|
2
|
-
import requests
|
|
1
|
+
import httpx
|
|
3
2
|
import os
|
|
4
3
|
import logging
|
|
5
|
-
from requests import Response
|
|
6
4
|
from polyapi.config import get_api_key_and_url, get_mtls_config
|
|
7
5
|
from polyapi.exceptions import PolyApiException
|
|
6
|
+
from polyapi import http_client
|
|
8
7
|
|
|
9
8
|
logger = logging.getLogger("poly")
|
|
10
9
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
api_key, api_url = get_api_key_and_url()
|
|
15
|
-
headers = {"Authorization": f"Bearer {api_key}"}
|
|
16
|
-
url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
|
|
17
|
-
|
|
18
|
-
endpoint_info = requests.post(url, json=data, headers=headers)
|
|
19
|
-
if endpoint_info.status_code < 200 or endpoint_info.status_code >= 300:
|
|
20
|
-
error_content = endpoint_info.content.decode("utf-8", errors="ignore")
|
|
10
|
+
def _check_response_error(resp, function_type, function_id, data):
|
|
11
|
+
if resp.status_code < 200 or resp.status_code >= 300:
|
|
12
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
21
13
|
if function_type == 'api' and os.getenv("LOGS_ENABLED"):
|
|
22
|
-
|
|
14
|
+
logger.error(f"Error executing api function with id: {function_id}. Status code: {resp.status_code}. Request data: {data}, Response: {error_content}")
|
|
23
15
|
elif function_type != 'api':
|
|
24
|
-
raise PolyApiException(f"{
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _check_endpoint_error(resp, function_type, function_id, data):
|
|
20
|
+
if resp.status_code < 200 or resp.status_code >= 300:
|
|
21
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
22
|
+
if function_type == 'api' and os.getenv("LOGS_ENABLED"):
|
|
23
|
+
raise PolyApiException(f"Error executing api function with id: {function_id}. Status code: {resp.status_code}. Request data: {data}, Response: {error_content}")
|
|
24
|
+
elif function_type != 'api':
|
|
25
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _build_direct_execute_params(endpoint_info_data):
|
|
27
29
|
request_params = endpoint_info_data.copy()
|
|
28
30
|
request_params.pop("url", None)
|
|
29
|
-
|
|
30
31
|
if "maxRedirects" in request_params:
|
|
31
|
-
request_params["
|
|
32
|
-
|
|
32
|
+
request_params["follow_redirects"] = request_params.pop("maxRedirects") > 0
|
|
33
|
+
return request_params
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _sync_direct_execute(function_type, function_id, data) -> httpx.Response:
|
|
37
|
+
api_key, api_url = get_api_key_and_url()
|
|
38
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
39
|
+
url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
|
|
40
|
+
|
|
41
|
+
endpoint_info = http_client.post(url, json=data, headers=headers)
|
|
42
|
+
_check_endpoint_error(endpoint_info, function_type, function_id, data)
|
|
43
|
+
|
|
44
|
+
endpoint_info_data = endpoint_info.json()
|
|
45
|
+
request_params = _build_direct_execute_params(endpoint_info_data)
|
|
46
|
+
|
|
33
47
|
has_mtls, cert_path, key_path, ca_path = get_mtls_config()
|
|
34
|
-
|
|
48
|
+
|
|
49
|
+
# Direct-execute hits URL that may need custom TLS
|
|
50
|
+
# settings (mTLS certs or disabled verification). httpx Client.request()
|
|
51
|
+
# doesn't accept per-request transport kwargs, so use one-off calls.
|
|
35
52
|
if has_mtls:
|
|
36
|
-
resp =
|
|
53
|
+
resp = httpx.request(
|
|
37
54
|
url=endpoint_info_data["url"],
|
|
38
55
|
cert=(cert_path, key_path),
|
|
39
56
|
verify=ca_path,
|
|
57
|
+
timeout=None,
|
|
40
58
|
**request_params
|
|
41
59
|
)
|
|
42
60
|
else:
|
|
43
|
-
resp =
|
|
61
|
+
resp = httpx.request(
|
|
44
62
|
url=endpoint_info_data["url"],
|
|
45
63
|
verify=False,
|
|
64
|
+
timeout=None,
|
|
46
65
|
**request_params
|
|
47
66
|
)
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
_check_response_error(resp, function_type, function_id, data)
|
|
69
|
+
return resp
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def _async_direct_execute(function_type, function_id, data) -> httpx.Response:
|
|
73
|
+
api_key, api_url = get_api_key_and_url()
|
|
74
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
75
|
+
url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
|
|
76
|
+
|
|
77
|
+
endpoint_info = await http_client.async_post(url, json=data, headers=headers)
|
|
78
|
+
_check_endpoint_error(endpoint_info, function_type, function_id, data)
|
|
79
|
+
|
|
80
|
+
endpoint_info_data = endpoint_info.json()
|
|
81
|
+
request_params = _build_direct_execute_params(endpoint_info_data)
|
|
82
|
+
|
|
83
|
+
has_mtls, cert_path, key_path, ca_path = get_mtls_config()
|
|
84
|
+
|
|
85
|
+
# One-off async client for custom TLS settings on external URLs.
|
|
86
|
+
if has_mtls:
|
|
87
|
+
async with httpx.AsyncClient(
|
|
88
|
+
cert=(cert_path, key_path), verify=ca_path, timeout=None
|
|
89
|
+
) as client:
|
|
90
|
+
resp = await client.request(
|
|
91
|
+
url=endpoint_info_data["url"], **request_params
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
async with httpx.AsyncClient(verify=False, timeout=None) as client:
|
|
95
|
+
resp = await client.request(
|
|
96
|
+
url=endpoint_info_data["url"], **request_params
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
_check_response_error(resp, function_type, function_id, data)
|
|
56
100
|
return resp
|
|
57
101
|
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
|
|
103
|
+
def direct_execute(function_type, function_id, data) -> httpx.Response:
|
|
104
|
+
""" execute a specific function id/type (sync)
|
|
60
105
|
"""
|
|
106
|
+
return _sync_direct_execute(function_type, function_id, data)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async def direct_execute_async(function_type, function_id, data) -> httpx.Response:
|
|
110
|
+
""" execute a specific function id/type (async)
|
|
111
|
+
"""
|
|
112
|
+
return await _async_direct_execute(function_type, function_id, data)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _sync_execute(function_type, function_id, data) -> httpx.Response:
|
|
61
116
|
api_key, api_url = get_api_key_and_url()
|
|
62
117
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
118
|
+
url = f"{api_url}/functions/{function_type}/{function_id}/execute"
|
|
63
119
|
|
|
120
|
+
resp = http_client.post(url, json=data, headers=headers)
|
|
121
|
+
_check_response_error(resp, function_type, function_id, data)
|
|
122
|
+
return resp
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def _async_execute(function_type, function_id, data) -> httpx.Response:
|
|
126
|
+
api_key, api_url = get_api_key_and_url()
|
|
127
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
64
128
|
url = f"{api_url}/functions/{function_type}/{function_id}/execute"
|
|
65
|
-
|
|
66
|
-
# Make the request
|
|
67
|
-
resp = requests.post(
|
|
68
|
-
url,
|
|
69
|
-
json=data,
|
|
70
|
-
headers=headers,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
if (resp.status_code < 200 or resp.status_code >= 300) and os.getenv("LOGS_ENABLED"):
|
|
74
|
-
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
75
|
-
if function_type == 'api' and os.getenv("LOGS_ENABLED"):
|
|
76
|
-
logger.error(f"Error executing api function with id: {function_id}. Status code: {resp.status_code}. Request data: {data}, Response: {error_content}")
|
|
77
|
-
elif function_type != 'api':
|
|
78
|
-
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
79
129
|
|
|
130
|
+
resp = await http_client.async_post(url, json=data, headers=headers)
|
|
131
|
+
_check_response_error(resp, function_type, function_id, data)
|
|
80
132
|
return resp
|
|
81
133
|
|
|
82
134
|
|
|
83
|
-
def
|
|
135
|
+
def execute(function_type, function_id, data) -> httpx.Response:
|
|
136
|
+
""" execute a specific function id/type (sync)
|
|
137
|
+
"""
|
|
138
|
+
return _sync_execute(function_type, function_id, data)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
async def execute_async(function_type, function_id, data) -> httpx.Response:
|
|
142
|
+
""" execute a specific function id/type (async)
|
|
143
|
+
"""
|
|
144
|
+
return await _async_execute(function_type, function_id, data)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _sync_execute_post(path, data):
|
|
148
|
+
api_key, api_url = get_api_key_and_url()
|
|
149
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
150
|
+
return http_client.post(api_url + path, json=data, headers=headers)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
async def _async_execute_post(path, data):
|
|
84
154
|
api_key, api_url = get_api_key_and_url()
|
|
85
155
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
86
|
-
|
|
156
|
+
return await http_client.async_post(api_url + path, json=data, headers=headers)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def execute_post(path, data):
|
|
160
|
+
return _sync_execute_post(path, data)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
async def execute_post_async(path, data):
|
|
164
|
+
return await _async_execute_post(path, data)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _sync_variable_get(variable_id: str) -> httpx.Response:
|
|
168
|
+
api_key, base_url = get_api_key_and_url()
|
|
169
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
170
|
+
url = f"{base_url}/variables/{variable_id}/value"
|
|
171
|
+
resp = http_client.get(url, headers=headers)
|
|
172
|
+
if resp.status_code != 200 and resp.status_code != 201:
|
|
173
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
174
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
87
175
|
return resp
|
|
88
176
|
|
|
89
177
|
|
|
90
|
-
def
|
|
178
|
+
async def _async_variable_get(variable_id: str) -> httpx.Response:
|
|
91
179
|
api_key, base_url = get_api_key_and_url()
|
|
92
180
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
93
181
|
url = f"{base_url}/variables/{variable_id}/value"
|
|
94
|
-
resp =
|
|
182
|
+
resp = await http_client.async_get(url, headers=headers)
|
|
95
183
|
if resp.status_code != 200 and resp.status_code != 201:
|
|
96
184
|
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
97
185
|
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
98
186
|
return resp
|
|
99
187
|
|
|
100
188
|
|
|
101
|
-
def
|
|
189
|
+
def variable_get(variable_id: str) -> httpx.Response:
|
|
190
|
+
return _sync_variable_get(variable_id)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
async def variable_get_async(variable_id: str) -> httpx.Response:
|
|
194
|
+
return await _async_variable_get(variable_id)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _sync_variable_update(variable_id: str, value) -> httpx.Response:
|
|
102
198
|
api_key, base_url = get_api_key_and_url()
|
|
103
199
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
104
200
|
url = f"{base_url}/variables/{variable_id}"
|
|
105
|
-
resp =
|
|
201
|
+
resp = http_client.patch(url, data={"value": value}, headers=headers)
|
|
106
202
|
if resp.status_code != 200 and resp.status_code != 201:
|
|
107
203
|
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
108
204
|
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
109
|
-
return resp
|
|
205
|
+
return resp
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
async def _async_variable_update(variable_id: str, value) -> httpx.Response:
|
|
209
|
+
api_key, base_url = get_api_key_and_url()
|
|
210
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
211
|
+
url = f"{base_url}/variables/{variable_id}"
|
|
212
|
+
resp = await http_client.async_patch(url, data={"value": value}, headers=headers)
|
|
213
|
+
if resp.status_code != 200 and resp.status_code != 201:
|
|
214
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
215
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
216
|
+
return resp
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def variable_update(variable_id: str, value) -> httpx.Response:
|
|
220
|
+
return _sync_variable_update(variable_id, value)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
async def variable_update_async(variable_id: str, value) -> httpx.Response:
|
|
224
|
+
return await _async_variable_update(variable_id, value)
|
polyapi/function_cli.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from typing import Any, List, Optional
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
from polyapi import http_client
|
|
5
4
|
from polyapi.config import get_api_key_and_url
|
|
6
5
|
from polyapi.utils import get_auth_headers, print_green, print_red, print_yellow
|
|
7
6
|
from polyapi.parser import parse_function_code, get_jsonschema_type
|
|
@@ -87,7 +86,7 @@ def function_add_or_update(
|
|
|
87
86
|
sys.exit(1)
|
|
88
87
|
|
|
89
88
|
headers = get_auth_headers(api_key)
|
|
90
|
-
resp =
|
|
89
|
+
resp = http_client.post(url, headers=headers, json=data)
|
|
91
90
|
if resp.status_code in [200, 201]:
|
|
92
91
|
print_green("DEPLOYED")
|
|
93
92
|
function_id = resp.json()["id"]
|
|
@@ -126,5 +125,5 @@ def spec_delete(function_type: str, function_id: str):
|
|
|
126
125
|
print(f"Unknown function type: {function_type}")
|
|
127
126
|
sys.exit(1)
|
|
128
127
|
headers = get_auth_headers(api_key)
|
|
129
|
-
resp =
|
|
128
|
+
resp = http_client.delete(url, headers=headers)
|
|
130
129
|
return resp
|
polyapi/generate.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import requests
|
|
3
2
|
import os
|
|
4
3
|
import uuid
|
|
5
4
|
import shutil
|
|
@@ -20,6 +19,7 @@ from .server import render_server_function
|
|
|
20
19
|
from .utils import add_import_to_init, get_auth_headers, init_the_init, print_green, to_func_namespace
|
|
21
20
|
from .variables import generate_variables
|
|
22
21
|
from .poly_tables import generate_tables
|
|
22
|
+
from . import http_client
|
|
23
23
|
from .config import get_api_key_and_url, get_direct_execute_config, get_cached_generate_args
|
|
24
24
|
|
|
25
25
|
SUPPORTED_FUNCTION_TYPES = {
|
|
@@ -62,7 +62,7 @@ def get_specs(contexts: Optional[List[str]] = None, names: Optional[List[str]] =
|
|
|
62
62
|
if get_direct_execute_config():
|
|
63
63
|
params["apiFunctionDirectExecute"] = "true"
|
|
64
64
|
|
|
65
|
-
resp =
|
|
65
|
+
resp = http_client.get(url, headers=headers, params=params)
|
|
66
66
|
if resp.status_code == 200:
|
|
67
67
|
return resp.json()
|
|
68
68
|
else:
|