polyapi-python 0.2.3.dev4__tar.gz → 0.2.3.dev6__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.
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/PKG-INFO +1 -1
- polyapi-python-0.2.3.dev6/polyapi/client.py +25 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/function_cli.py +30 -14
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/generate.py +49 -69
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/typedefs.py +4 -2
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/PKG-INFO +1 -1
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/SOURCES.txt +1 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/pyproject.toml +1 -1
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/LICENSE +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/README.md +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/__init__.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/__main__.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/api.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/auth.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/cli.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/config.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/constants.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/error_handler.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/exceptions.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/execute.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/py.typed +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/schema.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/server.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/utils.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/variables.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi/webhook.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/dependency_links.txt +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/requires.txt +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/top_level.txt +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/setup.cfg +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_api.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_auth.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_function_cli.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_server.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_utils.py +0 -0
- {polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/tests/test_variables.py +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Tuple
|
|
2
|
+
|
|
3
|
+
from polyapi.typedefs import PropertySpecification
|
|
4
|
+
from polyapi.utils import camelCase, add_type_import_path, parse_arguments, get_type_and_def
|
|
5
|
+
|
|
6
|
+
DEFS_TEMPLATE = """
|
|
7
|
+
from typing import List, Dict, Any, TypedDict
|
|
8
|
+
{args_def}
|
|
9
|
+
{return_type_def}
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def render_client_function(
|
|
14
|
+
function_name: str,
|
|
15
|
+
code: str,
|
|
16
|
+
arguments: List[PropertySpecification],
|
|
17
|
+
return_type: Dict[str, Any],
|
|
18
|
+
) -> Tuple[str, str]:
|
|
19
|
+
args, args_def = parse_arguments(function_name, arguments)
|
|
20
|
+
return_type_name, return_type_def = get_type_and_def(return_type) # type: ignore
|
|
21
|
+
func_type_defs = DEFS_TEMPLATE.format(
|
|
22
|
+
args_def=args_def,
|
|
23
|
+
return_type_def=return_type_def,
|
|
24
|
+
)
|
|
25
|
+
return code, func_type_defs
|
|
@@ -3,7 +3,7 @@ import argparse
|
|
|
3
3
|
import json
|
|
4
4
|
import types
|
|
5
5
|
import sys
|
|
6
|
-
from typing import Dict, List, Tuple
|
|
6
|
+
from typing import Dict, List, Mapping, Optional, Tuple
|
|
7
7
|
from typing_extensions import _TypedDictMeta # type: ignore
|
|
8
8
|
import requests
|
|
9
9
|
from stdlib_list import stdlib_list
|
|
@@ -18,7 +18,7 @@ import importlib
|
|
|
18
18
|
|
|
19
19
|
# these libraries are already installed in the base docker image
|
|
20
20
|
# and shouldnt be included in additional requirements
|
|
21
|
-
BASE_REQUIREMENTS = {"polyapi", "requests", "typing_extensions", "jsonschema-gentypes", "pydantic"}
|
|
21
|
+
BASE_REQUIREMENTS = {"polyapi", "requests", "typing_extensions", "jsonschema-gentypes", "pydantic", "cloudevents"}
|
|
22
22
|
all_stdlib_symbols = stdlib_list('.'.join([str(v) for v in sys.version_info[0:2]]))
|
|
23
23
|
BASE_REQUIREMENTS.update(all_stdlib_symbols) # dont need to pip install stuff in the python standard library
|
|
24
24
|
|
|
@@ -104,6 +104,19 @@ def _get_type(expr: ast.expr | None, schemas: List[Dict]) -> Tuple[str, Dict | N
|
|
|
104
104
|
return json_type, _get_type_schema(json_type, python_type, schemas)
|
|
105
105
|
|
|
106
106
|
|
|
107
|
+
def _get_req_name_if_not_in_base(n: Optional[str], pip_name_lookup: Mapping[str, List[str]]) -> Optional[str]:
|
|
108
|
+
if not n:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
if "." in n:
|
|
112
|
+
n = n.split(".")[0]
|
|
113
|
+
|
|
114
|
+
if n in BASE_REQUIREMENTS:
|
|
115
|
+
return None
|
|
116
|
+
else:
|
|
117
|
+
return pip_name_lookup[n][0]
|
|
118
|
+
|
|
119
|
+
|
|
107
120
|
def _parse_code(code: str, function_name: str):
|
|
108
121
|
parsed_args = []
|
|
109
122
|
return_type = None
|
|
@@ -121,13 +134,16 @@ def _parse_code(code: str, function_name: str):
|
|
|
121
134
|
|
|
122
135
|
for node in ast.iter_child_nodes(parsed_code):
|
|
123
136
|
if isinstance(node, ast.Import):
|
|
137
|
+
# TODO maybe handle `import foo.bar` case?
|
|
124
138
|
for name in node.names:
|
|
125
|
-
|
|
126
|
-
|
|
139
|
+
req = _get_req_name_if_not_in_base(name.name, pip_name_lookup)
|
|
140
|
+
if req:
|
|
141
|
+
requirements.append(req)
|
|
127
142
|
elif isinstance(node, ast.ImportFrom):
|
|
128
|
-
if node.module
|
|
129
|
-
req =
|
|
130
|
-
|
|
143
|
+
if node.module:
|
|
144
|
+
req = _get_req_name_if_not_in_base(node.module, pip_name_lookup)
|
|
145
|
+
if req:
|
|
146
|
+
requirements.append(req)
|
|
131
147
|
|
|
132
148
|
elif isinstance(node, ast.FunctionDef) and node.name == function_name:
|
|
133
149
|
function_args = [arg for arg in node.args.args]
|
|
@@ -168,7 +184,8 @@ def function_add_or_update(
|
|
|
168
184
|
args = parser.parse_args(subcommands)
|
|
169
185
|
|
|
170
186
|
verb = "Updating" if _func_already_exists(context, args.function_name) else "Adding"
|
|
171
|
-
|
|
187
|
+
ftype = "server" if server else "client"
|
|
188
|
+
print(f"{verb} custom {ftype} function...", end="")
|
|
172
189
|
|
|
173
190
|
with open(args.filename, "r") as f:
|
|
174
191
|
code = f.read()
|
|
@@ -186,9 +203,6 @@ def function_add_or_update(
|
|
|
186
203
|
print(f"Function {args.function_name} not found as top-level function in {args.filename}")
|
|
187
204
|
sys.exit(1)
|
|
188
205
|
|
|
189
|
-
if requirements:
|
|
190
|
-
print_yellow('\nPlease note that deploying your functions will take a few minutes because it makes use of libraries other than polyapi.')
|
|
191
|
-
|
|
192
206
|
data = {
|
|
193
207
|
"context": context,
|
|
194
208
|
"name": args.function_name,
|
|
@@ -197,18 +211,20 @@ def function_add_or_update(
|
|
|
197
211
|
"language": "python",
|
|
198
212
|
"returnType": return_type,
|
|
199
213
|
"returnTypeSchema": return_type_schema,
|
|
200
|
-
"requirements": requirements,
|
|
201
214
|
"arguments": arguments,
|
|
202
215
|
"logsEnabled": logs_enabled,
|
|
203
216
|
}
|
|
204
217
|
|
|
218
|
+
if server and requirements:
|
|
219
|
+
print_yellow('\nPlease note that deploying your functions will take a few minutes because it makes use of libraries other than polyapi.')
|
|
220
|
+
data["requirements"] = requirements
|
|
221
|
+
|
|
205
222
|
api_key, api_url = get_api_key_and_url()
|
|
206
223
|
assert api_key
|
|
207
224
|
if server:
|
|
208
225
|
url = f"{api_url}/functions/server"
|
|
209
226
|
else:
|
|
210
|
-
|
|
211
|
-
# url = f"{base_url}/functions/client"
|
|
227
|
+
url = f"{api_url}/functions/client"
|
|
212
228
|
|
|
213
229
|
headers = get_auth_headers(api_key)
|
|
214
230
|
resp = requests.post(url, headers=headers, json=data)
|
|
@@ -2,9 +2,10 @@ import json
|
|
|
2
2
|
import requests
|
|
3
3
|
import os
|
|
4
4
|
import shutil
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import List
|
|
6
6
|
|
|
7
7
|
from polyapi.auth import render_auth_function
|
|
8
|
+
from polyapi.client import render_client_function
|
|
8
9
|
from polyapi.execute import execute_post
|
|
9
10
|
from polyapi.webhook import render_webhook_handle
|
|
10
11
|
|
|
@@ -18,6 +19,7 @@ from .config import get_api_key_and_url, initialize_config
|
|
|
18
19
|
SUPPORTED_FUNCTION_TYPES = {
|
|
19
20
|
"apiFunction",
|
|
20
21
|
"authFunction",
|
|
22
|
+
"customFunction",
|
|
21
23
|
"serverFunction",
|
|
22
24
|
"webhookHandle",
|
|
23
25
|
}
|
|
@@ -38,32 +40,29 @@ def get_specs() -> List:
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
def parse_function_specs(
|
|
41
|
-
specs: List
|
|
42
|
-
|
|
43
|
+
specs: List[SpecificationDto],
|
|
44
|
+
limit_ids: List[str] | None, # optional list of ids to limit to
|
|
45
|
+
) -> List[SpecificationDto]:
|
|
43
46
|
functions = []
|
|
44
47
|
for spec in specs:
|
|
48
|
+
if not spec or "function" not in spec:
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
if not spec["function"]:
|
|
52
|
+
continue
|
|
53
|
+
|
|
45
54
|
if limit_ids and spec["id"] not in limit_ids:
|
|
46
55
|
continue
|
|
47
56
|
|
|
48
57
|
if spec["type"] not in SUPPORTED_FUNCTION_TYPES:
|
|
49
58
|
continue
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
functions.append(
|
|
58
|
-
(
|
|
59
|
-
function_type,
|
|
60
|
-
function_name,
|
|
61
|
-
function_id,
|
|
62
|
-
spec["description"],
|
|
63
|
-
arguments,
|
|
64
|
-
spec["function"]["returnType"],
|
|
65
|
-
)
|
|
66
|
-
)
|
|
60
|
+
if spec["type"] == "customFunction" and spec["language"] != "python":
|
|
61
|
+
# poly libraries only support client functions of same language
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
functions.append(spec)
|
|
65
|
+
|
|
67
66
|
return functions
|
|
68
67
|
|
|
69
68
|
|
|
@@ -90,11 +89,10 @@ def read_cached_specs() -> List[SpecificationDto]:
|
|
|
90
89
|
return json.loads(f.read())
|
|
91
90
|
|
|
92
91
|
|
|
93
|
-
def get_functions_and_parse(limit_ids: List[str] | None = None):
|
|
92
|
+
def get_functions_and_parse(limit_ids: List[str] | None = None) -> List[SpecificationDto]:
|
|
94
93
|
specs = get_specs()
|
|
95
94
|
cache_specs(specs)
|
|
96
|
-
|
|
97
|
-
return functions
|
|
95
|
+
return parse_function_specs(specs, limit_ids=limit_ids)
|
|
98
96
|
|
|
99
97
|
|
|
100
98
|
def get_variables() -> List[VariableSpecDto]:
|
|
@@ -162,14 +160,7 @@ def save_rendered_specs() -> None:
|
|
|
162
160
|
api_specs = [spec for spec in specs if spec["type"] == "apiFunction"]
|
|
163
161
|
for spec in api_specs:
|
|
164
162
|
assert spec["function"]
|
|
165
|
-
func_str, type_defs = render_spec(
|
|
166
|
-
spec["type"],
|
|
167
|
-
spec["name"],
|
|
168
|
-
spec["id"],
|
|
169
|
-
spec["description"],
|
|
170
|
-
spec["function"]["arguments"],
|
|
171
|
-
spec["function"]["returnType"],
|
|
172
|
-
)
|
|
163
|
+
func_str, type_defs = render_spec(spec)
|
|
173
164
|
data = {
|
|
174
165
|
"language": "python",
|
|
175
166
|
"apiFunctionId": spec["id"],
|
|
@@ -181,14 +172,20 @@ def save_rendered_specs() -> None:
|
|
|
181
172
|
assert resp.status_code == 201, (resp.text, resp.status_code)
|
|
182
173
|
|
|
183
174
|
|
|
184
|
-
def render_spec(
|
|
185
|
-
function_type
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
175
|
+
def render_spec(spec: SpecificationDto):
|
|
176
|
+
function_type = spec["type"]
|
|
177
|
+
function_description = spec["description"]
|
|
178
|
+
function_name = spec["name"]
|
|
179
|
+
function_id = spec["id"]
|
|
180
|
+
|
|
181
|
+
arguments: List[PropertySpecification] = []
|
|
182
|
+
return_type = {}
|
|
183
|
+
if spec["function"]:
|
|
184
|
+
arguments = [
|
|
185
|
+
arg for arg in spec["function"]["arguments"]
|
|
186
|
+
]
|
|
187
|
+
return_type = spec["function"]["returnType"]
|
|
188
|
+
|
|
192
189
|
if function_type == "apiFunction":
|
|
193
190
|
func_str, func_type_defs = render_api_function(
|
|
194
191
|
function_type,
|
|
@@ -198,6 +195,13 @@ def render_spec(
|
|
|
198
195
|
arguments,
|
|
199
196
|
return_type,
|
|
200
197
|
)
|
|
198
|
+
elif function_type == "customFunction":
|
|
199
|
+
func_str, func_type_defs = render_client_function(
|
|
200
|
+
function_name,
|
|
201
|
+
spec["code"],
|
|
202
|
+
arguments,
|
|
203
|
+
return_type,
|
|
204
|
+
)
|
|
201
205
|
elif function_type == "serverFunction":
|
|
202
206
|
func_str, func_type_defs = render_server_function(
|
|
203
207
|
function_type,
|
|
@@ -229,25 +233,14 @@ def render_spec(
|
|
|
229
233
|
|
|
230
234
|
|
|
231
235
|
def add_function_file(
|
|
232
|
-
function_type: str,
|
|
233
236
|
full_path: str,
|
|
234
237
|
function_name: str,
|
|
235
|
-
|
|
236
|
-
function_description: str,
|
|
237
|
-
arguments: List[PropertySpecification],
|
|
238
|
-
return_type: Dict[str, Any],
|
|
238
|
+
spec: SpecificationDto,
|
|
239
239
|
):
|
|
240
240
|
# first lets add the import to the __init__
|
|
241
241
|
init_the_init(full_path)
|
|
242
242
|
|
|
243
|
-
func_str, func_type_defs = render_spec(
|
|
244
|
-
function_type,
|
|
245
|
-
function_name,
|
|
246
|
-
function_id,
|
|
247
|
-
function_description,
|
|
248
|
-
arguments,
|
|
249
|
-
return_type,
|
|
250
|
-
)
|
|
243
|
+
func_str, func_type_defs = render_spec(spec)
|
|
251
244
|
|
|
252
245
|
if func_str:
|
|
253
246
|
# add function to init
|
|
@@ -262,27 +255,17 @@ def add_function_file(
|
|
|
262
255
|
|
|
263
256
|
|
|
264
257
|
def create_function(
|
|
265
|
-
|
|
266
|
-
path: str,
|
|
267
|
-
function_id: str,
|
|
268
|
-
function_description: str,
|
|
269
|
-
arguments: List[PropertySpecification],
|
|
270
|
-
return_type: Dict[str, Any],
|
|
258
|
+
spec: SpecificationDto
|
|
271
259
|
) -> None:
|
|
272
260
|
full_path = os.path.dirname(os.path.abspath(__file__))
|
|
273
|
-
|
|
274
|
-
folders = path.split(".")
|
|
261
|
+
folders = f"poly.{spec['context']}.{spec['name']}".split(".")
|
|
275
262
|
for idx, folder in enumerate(folders):
|
|
276
263
|
if idx + 1 == len(folders):
|
|
277
264
|
# special handling for final level
|
|
278
265
|
add_function_file(
|
|
279
|
-
function_type,
|
|
280
266
|
full_path,
|
|
281
267
|
folder,
|
|
282
|
-
|
|
283
|
-
function_description,
|
|
284
|
-
arguments,
|
|
285
|
-
return_type,
|
|
268
|
+
spec,
|
|
286
269
|
)
|
|
287
270
|
else:
|
|
288
271
|
full_path = os.path.join(full_path, folder)
|
|
@@ -296,9 +279,6 @@ def create_function(
|
|
|
296
279
|
add_import_to_init(full_path, next)
|
|
297
280
|
|
|
298
281
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
def generate_functions(functions: List) -> None:
|
|
282
|
+
def generate_functions(functions: List[SpecificationDto]) -> None:
|
|
303
283
|
for func in functions:
|
|
304
|
-
create_function(
|
|
284
|
+
create_function(func)
|
|
@@ -32,9 +32,11 @@ class SpecificationDto(TypedDict):
|
|
|
32
32
|
context: str
|
|
33
33
|
name: str
|
|
34
34
|
description: str
|
|
35
|
-
# function is none if this is actually VariableSpecDto
|
|
36
|
-
function: FunctionSpecification | None
|
|
35
|
+
# function is none (or function key not present) if this is actually VariableSpecDto
|
|
36
|
+
function: NotRequired[FunctionSpecification | None]
|
|
37
37
|
type: Literal['apiFunction', 'customFunction', 'serverFunction', 'authFunction', 'webhookHandle', 'serverVariable']
|
|
38
|
+
code: NotRequired[str]
|
|
39
|
+
language: str
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
class VariableSpecification(TypedDict):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{polyapi-python-0.2.3.dev4 → polyapi-python-0.2.3.dev6}/polyapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|