polyapi-python 0.1.0.dev0__tar.gz → 0.1.0.dev1__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.dev1}/PKG-INFO +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/api.py +74 -47
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/constants.py +6 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/execute.py +0 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/schema.py +5 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/PKG-INFO +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/pyproject.toml +1 -1
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/LICENSE +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/README.md +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/__init__.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/__main__.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/config.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/exceptions.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/function_cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/generate.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/py.typed +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/typedefs.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/utils.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi/variables.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/SOURCES.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/dependency_links.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/requires.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/top_level.txt +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/setup.cfg +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/tests/test_function_cli.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/tests/test_generate.py +0 -0
- {polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/tests/test_utils.py +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, List, Tuple
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from regex import W
|
|
5
|
+
|
|
6
|
+
from polyapi.constants import BASIC_PYTHON_TYPES, JSONSCHEMA_TO_PYTHON_TYPE_MAP
|
|
5
7
|
from polyapi.typedefs import PropertySpecification, PropertyType
|
|
6
8
|
from polyapi.utils import append_init, camelCase
|
|
7
9
|
from polyapi.schema import generate_schema_types, clean_title
|
|
@@ -12,47 +14,38 @@ TEMPLATE_FUNCTION_TYPE_MAP = {
|
|
|
12
14
|
"serverFunction": "server",
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
from typing import List, Dict, Any
|
|
18
|
-
from polyapi.execute import execute
|
|
19
|
-
from polyapi.exceptions import PolyApiException
|
|
17
|
+
SERVER_DEFS_TEMPLATE = """
|
|
18
|
+
from typing import List, Dict, Any, TypedDict
|
|
20
19
|
{args_def}
|
|
21
20
|
{return_type_def}
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
SERVER_FUNCTION_TEMPLATE = """
|
|
22
24
|
def {function_name}(
|
|
23
25
|
{args}
|
|
24
26
|
) -> {return_type_name}:
|
|
25
27
|
"{function_description}"
|
|
26
28
|
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
29
|
return {return_action}
|
|
32
30
|
"""
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
import requests
|
|
32
|
+
API_DEFS_TEMPLATE = """
|
|
36
33
|
from typing import List, Dict, Any, TypedDict
|
|
37
|
-
from polyapi.execute import execute
|
|
38
|
-
from polyapi.exceptions import PolyApiException
|
|
39
34
|
{args_def}
|
|
40
35
|
{return_type_def}
|
|
41
|
-
class
|
|
36
|
+
class {api_response_type}(TypedDict):
|
|
42
37
|
status: int
|
|
43
38
|
headers: Dict
|
|
44
39
|
data: {return_type_name}
|
|
40
|
+
"""
|
|
45
41
|
|
|
46
|
-
|
|
42
|
+
API_FUNCTION_TEMPLATE = """
|
|
47
43
|
def {function_name}(
|
|
48
44
|
{args}
|
|
49
|
-
) ->
|
|
45
|
+
) -> {api_response_type}:
|
|
50
46
|
"{function_description}"
|
|
51
47
|
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())
|
|
48
|
+
return {api_response_type}(resp.json()) # type: ignore
|
|
56
49
|
"""
|
|
57
50
|
|
|
58
51
|
|
|
@@ -118,7 +111,7 @@ def _get_type(type_spec: PropertyType) -> Tuple[str, str]:
|
|
|
118
111
|
return "Any", ""
|
|
119
112
|
|
|
120
113
|
|
|
121
|
-
def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
114
|
+
def _parse_arguments(function_name: str, arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
122
115
|
args_def = []
|
|
123
116
|
arg_string = ""
|
|
124
117
|
for idx, a in enumerate(arguments):
|
|
@@ -126,7 +119,7 @@ def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
|
126
119
|
if arg_def:
|
|
127
120
|
args_def.append(arg_def)
|
|
128
121
|
a["name"] = camelCase(a["name"])
|
|
129
|
-
arg_string += f" {a['name']}: {arg_type}"
|
|
122
|
+
arg_string += f" {a['name']}: {_add_type_import_path(function_name, arg_type)}"
|
|
130
123
|
description = a.get("description", "")
|
|
131
124
|
if description:
|
|
132
125
|
if idx == len(arguments) - 1:
|
|
@@ -138,6 +131,25 @@ def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
|
|
|
138
131
|
return arg_string.rstrip("\n"), "\n\n".join(args_def)
|
|
139
132
|
|
|
140
133
|
|
|
134
|
+
def _add_type_import_path(function_name: str, arg: str) -> str:
|
|
135
|
+
""" if not basic type, coerce to camelCase and add the import path
|
|
136
|
+
"""
|
|
137
|
+
if arg in BASIC_PYTHON_TYPES:
|
|
138
|
+
return arg
|
|
139
|
+
|
|
140
|
+
if arg.startswith("List["):
|
|
141
|
+
sub = arg[5:-1]
|
|
142
|
+
if sub in BASIC_PYTHON_TYPES:
|
|
143
|
+
return arg
|
|
144
|
+
else:
|
|
145
|
+
if '"' in sub:
|
|
146
|
+
return f'List[_{function_name}.{camelCase(sub)}]'
|
|
147
|
+
else:
|
|
148
|
+
return f'List["_{function_name}.{camelCase(sub)}"]'
|
|
149
|
+
|
|
150
|
+
return f'_{function_name}.{camelCase(arg)}'
|
|
151
|
+
|
|
152
|
+
|
|
141
153
|
def render_function(
|
|
142
154
|
function_type: str,
|
|
143
155
|
function_name: str,
|
|
@@ -145,38 +157,44 @@ def render_function(
|
|
|
145
157
|
function_description: str,
|
|
146
158
|
arguments: List[PropertySpecification],
|
|
147
159
|
return_type: Dict[str, Any],
|
|
148
|
-
) -> str:
|
|
160
|
+
) -> Tuple[str, str]:
|
|
149
161
|
arg_names = [a["name"] for a in arguments]
|
|
150
|
-
args, args_def = _parse_arguments(arguments)
|
|
162
|
+
args, args_def = _parse_arguments(function_name, arguments)
|
|
151
163
|
return_type_name, return_type_def = _get_type(return_type) # type: ignore
|
|
152
164
|
data = "{" + ", ".join([f"'{arg}': {camelCase(arg)}" for arg in arg_names]) + "}"
|
|
153
165
|
if function_type == "apiFunction":
|
|
154
|
-
|
|
166
|
+
api_response_type = f"{function_name}Response"
|
|
167
|
+
func_type_defs = API_DEFS_TEMPLATE.format(
|
|
168
|
+
args_def=args_def,
|
|
169
|
+
api_response_type=api_response_type,
|
|
170
|
+
return_type_name=return_type_name,
|
|
171
|
+
return_type_def=return_type_def,
|
|
172
|
+
)
|
|
173
|
+
func_str = API_FUNCTION_TEMPLATE.format(
|
|
155
174
|
function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
|
|
156
175
|
function_name=function_name,
|
|
157
176
|
function_id=function_id,
|
|
158
177
|
function_description=function_description.replace('"', "'"),
|
|
159
178
|
args=args,
|
|
160
|
-
args_def=args_def,
|
|
161
|
-
return_type_name=return_type_name,
|
|
162
|
-
return_type_def=return_type_def,
|
|
163
179
|
data=data,
|
|
180
|
+
api_response_type=_add_type_import_path(function_name, api_response_type),
|
|
164
181
|
)
|
|
165
182
|
else:
|
|
166
|
-
|
|
167
|
-
|
|
183
|
+
func_type_defs = SERVER_DEFS_TEMPLATE.format(
|
|
184
|
+
args_def=args_def,
|
|
185
|
+
return_type_def=return_type_def,
|
|
186
|
+
)
|
|
187
|
+
func_str = SERVER_FUNCTION_TEMPLATE.format(
|
|
188
|
+
return_type_name=_add_type_import_path(function_name, return_type_name),
|
|
168
189
|
function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
|
|
169
190
|
function_name=function_name,
|
|
170
191
|
function_id=function_id,
|
|
171
192
|
function_description=function_description.replace('"', "'"),
|
|
172
193
|
args=args,
|
|
173
|
-
|
|
174
|
-
return_type_name=return_type_name,
|
|
175
|
-
return_type_def=return_type_def,
|
|
176
|
-
return_action=return_action,
|
|
194
|
+
return_action=_get_server_return_action(return_type_name),
|
|
177
195
|
data=data,
|
|
178
196
|
)
|
|
179
|
-
return
|
|
197
|
+
return func_str, func_type_defs
|
|
180
198
|
|
|
181
199
|
|
|
182
200
|
def _get_server_return_action(return_type_name: str) -> str:
|
|
@@ -206,22 +224,30 @@ def add_function_file(
|
|
|
206
224
|
):
|
|
207
225
|
# first lets add the import to the __init__
|
|
208
226
|
init_path = os.path.join(full_path, "__init__.py")
|
|
227
|
+
_init_the_init(init_path)
|
|
228
|
+
|
|
229
|
+
func_str, func_type_defs = render_function(
|
|
230
|
+
function_type,
|
|
231
|
+
function_name,
|
|
232
|
+
function_id,
|
|
233
|
+
function_description,
|
|
234
|
+
arguments,
|
|
235
|
+
return_type,
|
|
236
|
+
)
|
|
237
|
+
|
|
209
238
|
with open(init_path, "a") as f:
|
|
210
|
-
f.write(f"
|
|
239
|
+
f.write(f"\n\nfrom . import _{function_name}\n\n{func_str}")
|
|
211
240
|
|
|
212
241
|
# now lets add the code!
|
|
213
242
|
file_path = os.path.join(full_path, f"_{function_name}.py")
|
|
214
243
|
with open(file_path, "w") as f:
|
|
215
|
-
f.write(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return_type,
|
|
223
|
-
)
|
|
224
|
-
)
|
|
244
|
+
f.write(func_type_defs)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _init_the_init(init_path: str) -> None:
|
|
248
|
+
if not os.path.exists(init_path):
|
|
249
|
+
with open(init_path, "w") as f:
|
|
250
|
+
f.write("from typing import List, Dict, Any, TypedDict\nfrom polyapi.execute import execute\nfrom polyapi.exceptions import PolyApiException\n")
|
|
225
251
|
|
|
226
252
|
|
|
227
253
|
def create_function(
|
|
@@ -255,6 +281,7 @@ def create_function(
|
|
|
255
281
|
# append to __init__.py file if nested folders
|
|
256
282
|
next = folders[idx + 1] if idx + 2 < len(folders) else ""
|
|
257
283
|
if next:
|
|
284
|
+
_init_the_init(os.path.join(full_path, "__init__.py"))
|
|
258
285
|
append_init(full_path, next)
|
|
259
286
|
|
|
260
287
|
|
|
@@ -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.dev1"
|
|
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.dev1}/polyapi_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev0 → polyapi-python-0.1.0.dev1}/polyapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|