polyapi-python 0.3.7.dev0__py3-none-any.whl → 0.3.7.dev2__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 +76 -7
- polyapi/api.py +10 -2
- polyapi/config.py +30 -1
- polyapi/execute.py +51 -5
- polyapi/generate.py +5 -1
- polyapi/utils.py +1 -1
- {polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/METADATA +1 -1
- {polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/RECORD +11 -11
- {polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/WHEEL +1 -1
- {polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/licenses/LICENSE +0 -0
- {polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/top_level.txt +0 -0
polyapi/__init__.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
import truststore
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Optional, overload, Literal
|
|
5
|
+
from typing_extensions import TypedDict
|
|
5
6
|
truststore.inject_into_ssl()
|
|
6
7
|
from .cli import CLI_COMMANDS
|
|
7
8
|
|
|
@@ -15,9 +16,77 @@ if len(sys.argv) > 1 and sys.argv[1] not in CLI_COMMANDS:
|
|
|
15
16
|
sys.exit(1)
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
class PolyCustomDict(TypedDict, total=False):
|
|
20
|
+
"""Type definition for polyCustom dictionary."""
|
|
21
|
+
executionId: Optional[str] # Read-only
|
|
22
|
+
executionApiKey: Optional[str]
|
|
23
|
+
responseStatusCode: int
|
|
24
|
+
responseContentType: Optional[str]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _PolyCustom:
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self._internal_store = {
|
|
30
|
+
"executionId": None,
|
|
31
|
+
"executionApiKey": None,
|
|
32
|
+
"responseStatusCode": 200,
|
|
33
|
+
"responseContentType": None,
|
|
34
|
+
}
|
|
35
|
+
self._execution_id_locked = False
|
|
36
|
+
|
|
37
|
+
def set_once(self, key: str, value: Any) -> None:
|
|
38
|
+
if key == "executionId" and self._execution_id_locked:
|
|
39
|
+
# Silently ignore attempts to overwrite locked executionId
|
|
40
|
+
return
|
|
41
|
+
self._internal_store[key] = value
|
|
42
|
+
if key == "executionId":
|
|
43
|
+
# Lock executionId after setting it
|
|
44
|
+
self.lock_execution_id()
|
|
45
|
+
|
|
46
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
47
|
+
return self._internal_store.get(key, default)
|
|
48
|
+
|
|
49
|
+
def lock_execution_id(self) -> None:
|
|
50
|
+
self._execution_id_locked = True
|
|
51
|
+
|
|
52
|
+
def unlock_execution_id(self) -> None:
|
|
53
|
+
self._execution_id_locked = False
|
|
54
|
+
|
|
55
|
+
@overload
|
|
56
|
+
def __getitem__(self, key: Literal["executionId"]) -> Optional[str]: ...
|
|
57
|
+
|
|
58
|
+
@overload
|
|
59
|
+
def __getitem__(self, key: Literal["executionApiKey"]) -> Optional[str]: ...
|
|
60
|
+
|
|
61
|
+
@overload
|
|
62
|
+
def __getitem__(self, key: Literal["responseStatusCode"]) -> int: ...
|
|
63
|
+
|
|
64
|
+
@overload
|
|
65
|
+
def __getitem__(self, key: Literal["responseContentType"]) -> Optional[str]: ...
|
|
66
|
+
|
|
67
|
+
def __getitem__(self, key: str) -> Any:
|
|
68
|
+
return self.get(key)
|
|
69
|
+
|
|
70
|
+
@overload
|
|
71
|
+
def __setitem__(self, key: Literal["executionApiKey"], value: Optional[str]) -> None: ...
|
|
72
|
+
|
|
73
|
+
@overload
|
|
74
|
+
def __setitem__(self, key: Literal["responseStatusCode"], value: int) -> None: ...
|
|
75
|
+
|
|
76
|
+
@overload
|
|
77
|
+
def __setitem__(self, key: Literal["responseContentType"], value: Optional[str]) -> None: ...
|
|
78
|
+
|
|
79
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
80
|
+
self.set_once(key, value)
|
|
81
|
+
|
|
82
|
+
def __repr__(self) -> str:
|
|
83
|
+
return f"PolyCustom({self._internal_store})"
|
|
84
|
+
|
|
85
|
+
def copy(self) -> '_PolyCustom':
|
|
86
|
+
new = _PolyCustom()
|
|
87
|
+
new._internal_store = self._internal_store.copy()
|
|
88
|
+
new._execution_id_locked = self._execution_id_locked
|
|
89
|
+
return new
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
polyCustom: PolyCustomDict = _PolyCustom()
|
polyapi/api.py
CHANGED
|
@@ -23,8 +23,16 @@ def {function_name}(
|
|
|
23
23
|
|
|
24
24
|
Function ID: {function_id}
|
|
25
25
|
\"""
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if get_direct_execute_config():
|
|
27
|
+
resp = direct_execute("{function_type}", "{function_id}", {data})
|
|
28
|
+
return {api_response_type}({{
|
|
29
|
+
"status": resp.status_code,
|
|
30
|
+
"headers": dict(resp.headers),
|
|
31
|
+
"data": resp.json()
|
|
32
|
+
}}) # type: ignore
|
|
33
|
+
else:
|
|
34
|
+
resp = execute("{function_type}", "{function_id}", {data})
|
|
35
|
+
return {api_response_type}(resp.json()) # type: ignore
|
|
28
36
|
|
|
29
37
|
|
|
30
38
|
"""
|
polyapi/config.py
CHANGED
|
@@ -8,6 +8,10 @@ from polyapi.utils import is_valid_polyapi_url, print_green, print_yellow
|
|
|
8
8
|
# cached values
|
|
9
9
|
API_KEY = None
|
|
10
10
|
API_URL = None
|
|
11
|
+
API_FUNCTION_DIRECT_EXECUTE = None
|
|
12
|
+
MTLS_CERT_PATH = None
|
|
13
|
+
MTLS_KEY_PATH = None
|
|
14
|
+
MTLS_CA_PATH = None
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
def get_config_file_path() -> str:
|
|
@@ -45,6 +49,13 @@ def get_api_key_and_url() -> Tuple[str | None, str | None]:
|
|
|
45
49
|
API_KEY = key
|
|
46
50
|
API_URL = url
|
|
47
51
|
|
|
52
|
+
# Read and cache MTLS and direct execute settings
|
|
53
|
+
global API_FUNCTION_DIRECT_EXECUTE, MTLS_CERT_PATH, MTLS_KEY_PATH, MTLS_CA_PATH
|
|
54
|
+
API_FUNCTION_DIRECT_EXECUTE = config.get("polyapi", "api_function_direct_execute", fallback="false").lower() == "true"
|
|
55
|
+
MTLS_CERT_PATH = config.get("polyapi", "mtls_cert_path", fallback=None)
|
|
56
|
+
MTLS_KEY_PATH = config.get("polyapi", "mtls_key_path", fallback=None)
|
|
57
|
+
MTLS_CA_PATH = config.get("polyapi", "mtls_ca_path", fallback=None)
|
|
58
|
+
|
|
48
59
|
return key, url
|
|
49
60
|
|
|
50
61
|
|
|
@@ -104,4 +115,22 @@ def clear_config():
|
|
|
104
115
|
|
|
105
116
|
path = get_config_file_path()
|
|
106
117
|
if os.path.exists(path):
|
|
107
|
-
os.remove(path)
|
|
118
|
+
os.remove(path)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_mtls_config() -> Tuple[bool, str | None, str | None, str | None]:
|
|
122
|
+
"""Return MTLS configuration settings"""
|
|
123
|
+
global MTLS_CERT_PATH, MTLS_KEY_PATH, MTLS_CA_PATH
|
|
124
|
+
if MTLS_CERT_PATH is None or MTLS_KEY_PATH is None or MTLS_CA_PATH is None:
|
|
125
|
+
# Force a config read if values aren't cached
|
|
126
|
+
get_api_key_and_url()
|
|
127
|
+
return bool(MTLS_CERT_PATH and MTLS_KEY_PATH and MTLS_CA_PATH), MTLS_CERT_PATH, MTLS_KEY_PATH, MTLS_CA_PATH
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_direct_execute_config() -> bool:
|
|
131
|
+
"""Return whether direct execute is enabled"""
|
|
132
|
+
global API_FUNCTION_DIRECT_EXECUTE
|
|
133
|
+
if API_FUNCTION_DIRECT_EXECUTE is None:
|
|
134
|
+
# Force a config read if value isn't cached
|
|
135
|
+
get_api_key_and_url()
|
|
136
|
+
return bool(API_FUNCTION_DIRECT_EXECUTE)
|
polyapi/execute.py
CHANGED
|
@@ -1,22 +1,68 @@
|
|
|
1
|
-
from typing import Dict
|
|
1
|
+
from typing import Dict, Optional
|
|
2
2
|
import requests
|
|
3
3
|
from requests import Response
|
|
4
|
-
from polyapi.config import get_api_key_and_url
|
|
4
|
+
from polyapi.config import get_api_key_and_url, get_mtls_config
|
|
5
5
|
from polyapi.exceptions import PolyApiException
|
|
6
6
|
|
|
7
|
+
def direct_execute(function_type, function_id, data) -> Response:
|
|
8
|
+
""" execute a specific function id/type
|
|
9
|
+
"""
|
|
10
|
+
api_key, api_url = get_api_key_and_url()
|
|
11
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
12
|
+
url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
|
|
13
|
+
|
|
14
|
+
endpoint_info = requests.post(url, json=data, headers=headers)
|
|
15
|
+
if endpoint_info.status_code < 200 or endpoint_info.status_code >= 300:
|
|
16
|
+
raise PolyApiException(f"{endpoint_info.status_code}: {endpoint_info.content.decode('utf-8', errors='ignore')}")
|
|
17
|
+
|
|
18
|
+
endpoint_info_data = endpoint_info.json()
|
|
19
|
+
request_params = endpoint_info_data.copy()
|
|
20
|
+
request_params.pop("url", None)
|
|
21
|
+
|
|
22
|
+
if "maxRedirects" in request_params:
|
|
23
|
+
request_params["allow_redirects"] = request_params.pop("maxRedirects") > 0
|
|
24
|
+
|
|
25
|
+
has_mtls, cert_path, key_path, ca_path = get_mtls_config()
|
|
26
|
+
|
|
27
|
+
if has_mtls:
|
|
28
|
+
resp = requests.request(
|
|
29
|
+
url=endpoint_info_data["url"],
|
|
30
|
+
cert=(cert_path, key_path),
|
|
31
|
+
verify=ca_path,
|
|
32
|
+
**request_params
|
|
33
|
+
)
|
|
34
|
+
else:
|
|
35
|
+
resp = requests.request(
|
|
36
|
+
url=endpoint_info_data["url"],
|
|
37
|
+
verify=False,
|
|
38
|
+
**request_params
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if resp.status_code < 200 or resp.status_code >= 300:
|
|
42
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
43
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
44
|
+
|
|
45
|
+
return resp
|
|
7
46
|
|
|
8
47
|
def execute(function_type, function_id, data) -> Response:
|
|
9
48
|
""" execute a specific function id/type
|
|
10
49
|
"""
|
|
11
50
|
api_key, api_url = get_api_key_and_url()
|
|
12
51
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
52
|
+
|
|
13
53
|
url = f"{api_url}/functions/{function_type}/{function_id}/execute"
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
|
|
54
|
+
|
|
55
|
+
# Make the request
|
|
56
|
+
resp = requests.post(
|
|
57
|
+
url,
|
|
58
|
+
json=data,
|
|
59
|
+
headers=headers,
|
|
60
|
+
)
|
|
61
|
+
|
|
17
62
|
if resp.status_code < 200 or resp.status_code >= 300:
|
|
18
63
|
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
19
64
|
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
65
|
+
|
|
20
66
|
return resp
|
|
21
67
|
|
|
22
68
|
|
polyapi/generate.py
CHANGED
|
@@ -14,7 +14,7 @@ from .api import render_api_function
|
|
|
14
14
|
from .server import render_server_function
|
|
15
15
|
from .utils import add_import_to_init, get_auth_headers, init_the_init, print_green, to_func_namespace
|
|
16
16
|
from .variables import generate_variables
|
|
17
|
-
from .config import get_api_key_and_url
|
|
17
|
+
from .config import get_api_key_and_url, get_direct_execute_config
|
|
18
18
|
|
|
19
19
|
SUPPORTED_FUNCTION_TYPES = {
|
|
20
20
|
"apiFunction",
|
|
@@ -46,6 +46,10 @@ def get_specs(contexts=Optional[List[str]], no_types: bool = False) -> List:
|
|
|
46
46
|
if contexts:
|
|
47
47
|
params["contexts"] = contexts
|
|
48
48
|
|
|
49
|
+
# Add apiFunctionDirectExecute parameter if direct execute is enabled
|
|
50
|
+
if get_direct_execute_config():
|
|
51
|
+
params["apiFunctionDirectExecute"] = "true"
|
|
52
|
+
|
|
49
53
|
resp = requests.get(url, headers=headers, params=params)
|
|
50
54
|
if resp.status_code == 200:
|
|
51
55
|
return resp.json()
|
polyapi/utils.py
CHANGED
|
@@ -16,7 +16,7 @@ from polyapi.schema import (
|
|
|
16
16
|
|
|
17
17
|
# this string should be in every __init__ file.
|
|
18
18
|
# it contains all the imports needed for the function or variable code to run
|
|
19
|
-
CODE_IMPORTS = "from typing import List, Dict, Any, Optional, Callable\nfrom typing_extensions import TypedDict, NotRequired\nimport logging\nimport requests\nimport socketio # type: ignore\nfrom polyapi.config import get_api_key_and_url\nfrom polyapi.execute import execute, execute_post, variable_get, variable_update\n\n"
|
|
19
|
+
CODE_IMPORTS = "from typing import List, Dict, Any, Optional, Callable\nfrom typing_extensions import TypedDict, NotRequired\nimport logging\nimport requests\nimport socketio # type: ignore\nfrom polyapi.config import get_api_key_and_url, get_direct_execute_config\nfrom polyapi.execute import execute, execute_post, variable_get, variable_update, direct_execute\n\n"
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def init_the_init(full_path: str, code_imports="") -> None:
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
polyapi/__init__.py,sha256=
|
|
1
|
+
polyapi/__init__.py,sha256=Au5snCFb05a87mDMK2Cwoft7nntR35iw4lL0Ztgivoo,2931
|
|
2
2
|
polyapi/__main__.py,sha256=V4zhAh_YGxno5f_KSrlkELxcuDh9bR3WSd0n-2r-qQQ,93
|
|
3
|
-
polyapi/api.py,sha256=
|
|
3
|
+
polyapi/api.py,sha256=2nds6ZdNe9OHvCba4IjOPga0CAYIsib2SbhEyDDCmd8,2188
|
|
4
4
|
polyapi/auth.py,sha256=zrIGatjba5GwUTNjKj1GHQWTEDP9B-HrSzCKbLFoqvc,5336
|
|
5
5
|
polyapi/cli.py,sha256=jtKXARbT9AOgYTR6nf3OiwiPvsyUlLVbyynEA84PDzw,8924
|
|
6
6
|
polyapi/client.py,sha256=CoFDYvyKsqL4wPQbUDIr0Qb8Q5eD92xN4OEEcJEVuGQ,1296
|
|
7
|
-
polyapi/config.py,sha256=
|
|
7
|
+
polyapi/config.py,sha256=QQxRZ9nMUykItUMAdw97dad0DPEV1luRwkeqOyrEKf8,4316
|
|
8
8
|
polyapi/constants.py,sha256=sc-FnS0SngBLvSu1ZWMs0UCf9EYD1u1Yhfr-sZXGLns,607
|
|
9
9
|
polyapi/deployables.py,sha256=WVcNNB6W5ZW_-ukf_kK3moRcnwIkC-O4te6vLepjcco,11936
|
|
10
10
|
polyapi/error_handler.py,sha256=I_e0iz6VM23FLVQWJljxs2NGcl_OODbi43OcbnqBlp8,2398
|
|
11
11
|
polyapi/exceptions.py,sha256=Zh7i7eCUhDuXEdUYjatkLFTeZkrx1BJ1P5ePgbJ9eIY,89
|
|
12
|
-
polyapi/execute.py,sha256=
|
|
12
|
+
polyapi/execute.py,sha256=sjI6BMBYPSCD6UngV9DzpJIRSU6p02aShNaTXhDExtY,3457
|
|
13
13
|
polyapi/function_cli.py,sha256=wDbgWGSQjMpzmZoPAcU57ZwD8EUTKE8sF9dgZLUInMk,4118
|
|
14
|
-
polyapi/generate.py,sha256=
|
|
14
|
+
polyapi/generate.py,sha256=ZTLtiMPYUcRygJ-s--2IzLY2FQ1W7idLJnbwh2UngKU,12089
|
|
15
15
|
polyapi/parser.py,sha256=mdoh4pNq8pyiHE0-i6Coqj8frEXfBLRk6itpAXMrrgI,20373
|
|
16
16
|
polyapi/poly_schemas.py,sha256=T4kfZyfgVLiqLD28GmYNiHnrNx77J_HO4uzk8LUAhlo,3137
|
|
17
17
|
polyapi/prepare.py,sha256=Q8CWV4kmZ2dbXYVsud34AgJkj5ymcQ_IcYhLuikc9yk,6659
|
|
@@ -21,11 +21,11 @@ polyapi/schema.py,sha256=ZSzeUjpqigLvE4tFKB7y4AaZG-W5N5Z9wMH-F-vjMBU,4616
|
|
|
21
21
|
polyapi/server.py,sha256=YXWxhYBx-hluwDQ8Jvfpy2s8ogz0GsNTMcZVNcP5ca8,2147
|
|
22
22
|
polyapi/sync.py,sha256=PGdC0feBBjEVrF3d9EluW_OAxbWuzSrfh84czma8kWg,6476
|
|
23
23
|
polyapi/typedefs.py,sha256=MGDwWaijLNqokXF9UCHGAP-yKixOzztrH4Lsj800AJs,2328
|
|
24
|
-
polyapi/utils.py,sha256=
|
|
24
|
+
polyapi/utils.py,sha256=hW_H207-aHB22UFFYtUjxZvW13TUXTR786-3LaL4OLc,10351
|
|
25
25
|
polyapi/variables.py,sha256=j7WWrGLr2O5SkWGxnsusnnfl25kVL3b6SQYcVGEoC8c,4277
|
|
26
26
|
polyapi/webhook.py,sha256=LWv28c2MLz_OKBI_Nn7WR4C-gs1SWgbdXsoxIIf-9UI,4886
|
|
27
|
-
polyapi_python-0.3.7.
|
|
28
|
-
polyapi_python-0.3.7.
|
|
29
|
-
polyapi_python-0.3.7.
|
|
30
|
-
polyapi_python-0.3.7.
|
|
31
|
-
polyapi_python-0.3.7.
|
|
27
|
+
polyapi_python-0.3.7.dev2.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
|
|
28
|
+
polyapi_python-0.3.7.dev2.dist-info/METADATA,sha256=rx9IKDlG3qPk8IGDAn3m7Z2BCL5gS43uTtQEYnUHPm8,5782
|
|
29
|
+
polyapi_python-0.3.7.dev2.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
30
|
+
polyapi_python-0.3.7.dev2.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
|
|
31
|
+
polyapi_python-0.3.7.dev2.dist-info/RECORD,,
|
{polyapi_python-0.3.7.dev0.dist-info → polyapi_python-0.3.7.dev2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|