polyapi-python 0.1.0.dev0__tar.gz → 0.1.0.dev2__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.1.0.dev0 → polyapi-python-0.1.0.dev2}/PKG-INFO +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/api.py +72 -47
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/constants.py +6 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/execute.py +0 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/schema.py +5 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/PKG-INFO +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/pyproject.toml +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/LICENSE +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/README.md +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/__init__.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/__main__.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/config.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/exceptions.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/function_cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/generate.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/py.typed +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/typedefs.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/utils.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi/variables.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/SOURCES.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/dependency_links.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/requires.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/top_level.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/setup.cfg +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/tests/test_function_cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/tests/test_generate.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/tests/test_utils.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, List, Tuple
|
|
3
3
|
|
|
4
|
-
from polyapi.constants import JSONSCHEMA_TO_PYTHON_TYPE_MAP
|
|
4
|
+
from polyapi.constants import BASIC_PYTHON_TYPES, JSONSCHEMA_TO_PYTHON_TYPE_MAP
|
|
5
5
|
from polyapi.typedefs import PropertySpecification, PropertyType
|
|
6
6
|
from polyapi.utils import append_init, camelCase
|
|
7
7
|
from polyapi.schema import generate_schema_types, clean_title
|
|
@@ -12,47 +12,38 @@ TEMPLATE_FUNCTION_TYPE_MAP = {
|
|
|
12
12
|
"serverFunction": "server",
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
from typing import List, Dict, Any
|
|
18
|
-
from polyapi.execute import execute
|
|
19
|
-
from polyapi.exceptions import PolyApiException
|
|
15
|
+
SERVER_DEFS_TEMPLATE = """
|
|
16
|
+
from typing import List, Dict, Any, TypedDict
|
|
20
17
|
{args_def}
|
|
21
18
|
{return_type_def}
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
SERVER_FUNCTION_TEMPLATE = """
|
|
22
22
|
def {function_name}(
|
|
23
23
|
{args}
|
|
24
24
|
) -> {return_type_name}:
|
|
25
25
|
"{function_description}"
|
|
26
26
|
resp = execute("{function_type}", "{function_id}", {data})
|
|
27
|
-
if resp.status_code != 200 and resp.status_code != 201:
|
|
28
|
-
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
29
|
-
raise PolyApiException(f"{{resp.status_code}}: {{error_content}}")
|
|
30
|
-
|
|
31
27
|
return {return_action}
|
|
32
28
|
"""
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
import requests
|
|
30
|
+
API_DEFS_TEMPLATE = """
|
|
36
31
|
from typing import List, Dict, Any, TypedDict
|
|
37
|
-
from polyapi.execute import execute
|
|
38
|
-
from polyapi.exceptions import PolyApiException
|
|
39
32
|
{args_def}
|
|
40
33
|
{return_type_def}
|
|
41
|
-
class
|
|
34
|
+
class {api_response_type}(TypedDict):
|
|
42
35
|
status: int
|
|
43
36
|
headers: Dict
|
|
44
37
|
data: {return_type_name}
|
|
38
|
+
"""
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
API_FUNCTION_TEMPLATE = """
|
|
47
41
|
def {function_name}(
|
|
48
42
|
{args}
|
|
49
|
-
) ->
|
|
43
|
+
) -> {api_response_type}:
|
|
50
44
|
"{function_description}"
|
|
51
45
|
resp = execute("{function_type}", "{function_id}", {data})
|
|
52
|
-
|
|
53
|
-
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
54
|
-
raise PolyApiException(f"{{resp.status_code}}: {{error_content}}")
|
|
55
|
-
return ApiFunctionResponse(resp.json())
|
|
46
|
+
return {api_response_type}(resp.json()) # type: ignore
|
|
56
47
|
"""
|
|
57
48
|
|
|
58
49
|
|
|
@@ -118,7 +109,7 @@ def _get_type(type_spec: PropertyType) -> Tuple[str, str]:
|
|
|
118
109
|
return "Any", ""
|
|
119
110
|
|
|
120
111
|
|
|
121
|
-
def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
112
|
+
def _parse_arguments(function_name: str, arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
122
113
|
args_def = []
|
|
123
114
|
arg_string = ""
|
|
124
115
|
for idx, a in enumerate(arguments):
|
|
@@ -126,7 +117,7 @@ def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
|
126
117
|
if arg_def:
|
|
127
118
|
args_def.append(arg_def)
|
|
128
119
|
a["name"] = camelCase(a["name"])
|
|
129
|
-
arg_string += f" {a['name']}: {arg_type}"
|
|
120
|
+
arg_string += f" {a['name']}: {_add_type_import_path(function_name, arg_type)}"
|
|
130
121
|
description = a.get("description", "")
|
|
131
122
|
if description:
|
|
132
123
|
if idx == len(arguments) - 1:
|
|
@@ -138,6 +129,25 @@ def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
|
138
129
|
return arg_string.rstrip("\n"), "\n\n".join(args_def)
|
|
139
130
|
|
|
140
131
|
|
|
132
|
+
def _add_type_import_path(function_name: str, arg: str) -> str:
|
|
133
|
+
""" if not basic type, coerce to camelCase and add the import path
|
|
134
|
+
"""
|
|
135
|
+
if arg in BASIC_PYTHON_TYPES:
|
|
136
|
+
return arg
|
|
137
|
+
|
|
138
|
+
if arg.startswith("List["):
|
|
139
|
+
sub = arg[5:-1]
|
|
140
|
+
if sub in BASIC_PYTHON_TYPES:
|
|
141
|
+
return arg
|
|
142
|
+
else:
|
|
143
|
+
if '"' in sub:
|
|
144
|
+
return f'List[_{function_name}.{camelCase(sub)}]'
|
|
145
|
+
else:
|
|
146
|
+
return f'List["_{function_name}.{camelCase(sub)}"]'
|
|
147
|
+
|
|
148
|
+
return f'_{function_name}.{camelCase(arg)}'
|
|
149
|
+
|
|
150
|
+
|
|
141
151
|
def render_function(
|
|
142
152
|
function_type: str,
|
|
143
153
|
function_name: str,
|
|
@@ -145,38 +155,44 @@ def render_function(
|
|
|
145
155
|
function_description: str,
|
|
146
156
|
arguments: List[PropertySpecification],
|
|
147
157
|
return_type: Dict[str, Any],
|
|
148
|
-
) -> str:
|
|
158
|
+
) -> Tuple[str, str]:
|
|
149
159
|
arg_names = [a["name"] for a in arguments]
|
|
150
|
-
args, args_def = _parse_arguments(arguments)
|
|
160
|
+
args, args_def = _parse_arguments(function_name, arguments)
|
|
151
161
|
return_type_name, return_type_def = _get_type(return_type) # type: ignore
|
|
152
162
|
data = "{" + ", ".join([f"'{arg}': {camelCase(arg)}" for arg in arg_names]) + "}"
|
|
153
163
|
if function_type == "apiFunction":
|
|
154
|
-
|
|
164
|
+
api_response_type = f"{function_name}Response"
|
|
165
|
+
func_type_defs = API_DEFS_TEMPLATE.format(
|
|
166
|
+
args_def=args_def,
|
|
167
|
+
api_response_type=api_response_type,
|
|
168
|
+
return_type_name=return_type_name,
|
|
169
|
+
return_type_def=return_type_def,
|
|
170
|
+
)
|
|
171
|
+
func_str = API_FUNCTION_TEMPLATE.format(
|
|
155
172
|
function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
|
|
156
173
|
function_name=function_name,
|
|
157
174
|
function_id=function_id,
|
|
158
175
|
function_description=function_description.replace('"', "'"),
|
|
159
176
|
args=args,
|
|
160
|
-
args_def=args_def,
|
|
161
|
-
return_type_name=return_type_name,
|
|
162
|
-
return_type_def=return_type_def,
|
|
163
177
|
data=data,
|
|
178
|
+
api_response_type=_add_type_import_path(function_name, api_response_type),
|
|
164
179
|
)
|
|
165
180
|
else:
|
|
166
|
-
|
|
167
|
-
|
|
181
|
+
func_type_defs = SERVER_DEFS_TEMPLATE.format(
|
|
182
|
+
args_def=args_def,
|
|
183
|
+
return_type_def=return_type_def,
|
|
184
|
+
)
|
|
185
|
+
func_str = SERVER_FUNCTION_TEMPLATE.format(
|
|
186
|
+
return_type_name=_add_type_import_path(function_name, return_type_name),
|
|
168
187
|
function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
|
|
169
188
|
function_name=function_name,
|
|
170
189
|
function_id=function_id,
|
|
171
190
|
function_description=function_description.replace('"', "'"),
|
|
172
191
|
args=args,
|
|
173
|
-
|
|
174
|
-
return_type_name=return_type_name,
|
|
175
|
-
return_type_def=return_type_def,
|
|
176
|
-
return_action=return_action,
|
|
192
|
+
return_action=_get_server_return_action(return_type_name),
|
|
177
193
|
data=data,
|
|
178
194
|
)
|
|
179
|
-
return
|
|
195
|
+
return func_str, func_type_defs
|
|
180
196
|
|
|
181
197
|
|
|
182
198
|
def _get_server_return_action(return_type_name: str) -> str:
|
|
@@ -206,22 +222,30 @@ def add_function_file(
|
|
|
206
222
|
):
|
|
207
223
|
# first lets add the import to the __init__
|
|
208
224
|
init_path = os.path.join(full_path, "__init__.py")
|
|
225
|
+
_init_the_init(init_path)
|
|
226
|
+
|
|
227
|
+
func_str, func_type_defs = render_function(
|
|
228
|
+
function_type,
|
|
229
|
+
function_name,
|
|
230
|
+
function_id,
|
|
231
|
+
function_description,
|
|
232
|
+
arguments,
|
|
233
|
+
return_type,
|
|
234
|
+
)
|
|
235
|
+
|
|
209
236
|
with open(init_path, "a") as f:
|
|
210
|
-
f.write(f"
|
|
237
|
+
f.write(f"\n\nfrom . import _{function_name}\n\n{func_str}")
|
|
211
238
|
|
|
212
239
|
# now lets add the code!
|
|
213
240
|
file_path = os.path.join(full_path, f"_{function_name}.py")
|
|
214
241
|
with open(file_path, "w") as f:
|
|
215
|
-
f.write(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return_type,
|
|
223
|
-
)
|
|
224
|
-
)
|
|
242
|
+
f.write(func_type_defs)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _init_the_init(init_path: str) -> None:
|
|
246
|
+
if not os.path.exists(init_path):
|
|
247
|
+
with open(init_path, "w") as f:
|
|
248
|
+
f.write("from typing import List, Dict, Any, TypedDict\nfrom polyapi.execute import execute\nfrom polyapi.exceptions import PolyApiException\n")
|
|
225
249
|
|
|
226
250
|
|
|
227
251
|
def create_function(
|
|
@@ -255,6 +279,7 @@ def create_function(
|
|
|
255
279
|
# append to __init__.py file if nested folders
|
|
256
280
|
next = folders[idx + 1] if idx + 2 < len(folders) else ""
|
|
257
281
|
if next:
|
|
282
|
+
_init_the_init(os.path.join(full_path, "__init__.py"))
|
|
258
283
|
append_init(full_path, next)
|
|
259
284
|
|
|
260
285
|
|
|
@@ -15,4 +15,9 @@ PYTHON_TO_JSONSCHEMA_TYPE_MAP = {
|
|
|
15
15
|
"bool": "boolean",
|
|
16
16
|
"List": "array",
|
|
17
17
|
"Dict": "object",
|
|
18
|
-
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
BASIC_PYTHON_TYPES = set(PYTHON_TO_JSONSCHEMA_TYPE_MAP.keys())
|
|
21
|
+
|
|
22
|
+
# TODO wire this up to config-variables in future so clients can modify
|
|
23
|
+
SUPPORT_EMAIL = 'support@polyapi.io'
|
|
@@ -4,7 +4,6 @@ from polyapi.config import get_api_key_and_url
|
|
|
4
4
|
from polyapi.exceptions import PolyApiException
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
# TODO use this to cleanup generated code
|
|
8
7
|
def execute(function_type, function_id, data) -> Response:
|
|
9
8
|
api_key, api_url = get_api_key_and_url()
|
|
10
9
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
@@ -79,4 +79,8 @@ def clean_title(title: str) -> str:
|
|
|
79
79
|
""" used by library generation, sometimes functions can be added with spaces in the title
|
|
80
80
|
or other nonsense. fix them!
|
|
81
81
|
"""
|
|
82
|
-
|
|
82
|
+
title = title.replace(" ", "")
|
|
83
|
+
# certain reserved words cant be titles, let's replace them
|
|
84
|
+
if title == "List":
|
|
85
|
+
title = "List_"
|
|
86
|
+
return title
|
|
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.2", "wheel"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "polyapi-python"
|
|
6
|
-
version = "0.1.0.
|
|
6
|
+
version = "0.1.0.dev2"
|
|
7
7
|
description = "The PolyAPI Python Client"
|
|
8
8
|
authors = [{ name = "Dan Fellin", email = "dan@polyapi.io" }]
|
|
9
9
|
dependencies = ["requests", "typing_extensions", "jsonschema-gentypes", "pydantic>=2.5.3", "stdlib_list"]
|
|
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.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev2}/polyapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|