polyapi-python 0.3.7.dev2__py3-none-any.whl → 0.3.7.dev3__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/function_cli.py +1 -1
- polyapi/generate.py +105 -28
- polyapi/utils.py +50 -12
- {polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/METADATA +1 -1
- {polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/RECORD +8 -8
- {polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/WHEEL +1 -1
- {polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/licenses/LICENSE +0 -0
- {polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/top_level.txt +0 -0
polyapi/function_cli.py
CHANGED
|
@@ -86,7 +86,7 @@ def function_add_or_update(
|
|
|
86
86
|
|
|
87
87
|
headers = get_auth_headers(api_key)
|
|
88
88
|
resp = requests.post(url, headers=headers, json=data)
|
|
89
|
-
if resp.status_code
|
|
89
|
+
if resp.status_code in [200, 201]:
|
|
90
90
|
print_green("DEPLOYED")
|
|
91
91
|
function_id = resp.json()["id"]
|
|
92
92
|
print(f"Function ID: {function_id}")
|
polyapi/generate.py
CHANGED
|
@@ -129,24 +129,26 @@ def parse_function_specs(
|
|
|
129
129
|
) -> List[SpecificationDto]:
|
|
130
130
|
functions = []
|
|
131
131
|
for spec in specs:
|
|
132
|
-
if not spec
|
|
133
|
-
continue
|
|
134
|
-
|
|
135
|
-
if not spec["function"]:
|
|
136
|
-
continue
|
|
137
|
-
|
|
138
|
-
if limit_ids and spec["id"] not in limit_ids:
|
|
132
|
+
if not spec:
|
|
139
133
|
continue
|
|
140
134
|
|
|
135
|
+
# For no_types mode, we might not have function data, but we still want to include the spec
|
|
136
|
+
# if it's a supported function type
|
|
141
137
|
if spec["type"] not in SUPPORTED_FUNCTION_TYPES:
|
|
142
138
|
continue
|
|
143
139
|
|
|
144
|
-
if
|
|
145
|
-
|
|
140
|
+
# Skip if we have a limit and this spec is not in it
|
|
141
|
+
if limit_ids and spec.get("id") not in limit_ids:
|
|
146
142
|
continue
|
|
147
143
|
|
|
144
|
+
# For customFunction, check language if we have function data
|
|
145
|
+
if spec["type"] == "customFunction":
|
|
146
|
+
if spec.get("language") and spec["language"] != "python":
|
|
147
|
+
# poly libraries only support client functions of same language
|
|
148
|
+
continue
|
|
149
|
+
|
|
148
150
|
# Functions with serverSideAsync True will always return a Dict with execution ID
|
|
149
|
-
if spec.get('serverSideAsync'):
|
|
151
|
+
if spec.get('serverSideAsync') and spec.get("function"):
|
|
150
152
|
spec['function']['returnType'] = {'kind': 'plain', 'value': 'object'}
|
|
151
153
|
|
|
152
154
|
functions.append(spec)
|
|
@@ -205,6 +207,63 @@ def remove_old_library():
|
|
|
205
207
|
shutil.rmtree(path)
|
|
206
208
|
|
|
207
209
|
|
|
210
|
+
def create_empty_schemas_module():
|
|
211
|
+
"""Create an empty schemas module for no-types mode so user code can still import from polyapi.schemas"""
|
|
212
|
+
currdir = os.path.dirname(os.path.abspath(__file__))
|
|
213
|
+
schemas_path = os.path.join(currdir, "schemas")
|
|
214
|
+
|
|
215
|
+
# Create the schemas directory
|
|
216
|
+
if not os.path.exists(schemas_path):
|
|
217
|
+
os.makedirs(schemas_path)
|
|
218
|
+
|
|
219
|
+
# Create an __init__.py file with dynamic schema resolution
|
|
220
|
+
init_path = os.path.join(schemas_path, "__init__.py")
|
|
221
|
+
with open(init_path, "w") as f:
|
|
222
|
+
f.write('''"""Empty schemas module for no-types mode"""
|
|
223
|
+
from typing import Any, Dict
|
|
224
|
+
|
|
225
|
+
class _GenericSchema(Dict[str, Any]):
|
|
226
|
+
"""Generic schema type that acts like a Dict for no-types mode"""
|
|
227
|
+
def __init__(self, *args, **kwargs):
|
|
228
|
+
super().__init__(*args, **kwargs)
|
|
229
|
+
|
|
230
|
+
class _SchemaModule:
|
|
231
|
+
"""Dynamic module that returns itself for attribute access, allowing infinite nesting"""
|
|
232
|
+
|
|
233
|
+
def __getattr__(self, name: str):
|
|
234
|
+
# For callable access (like schemas.Response()), return the generic schema class
|
|
235
|
+
# For further attribute access (like schemas.random.random2), return self to allow nesting
|
|
236
|
+
return _NestedSchemaAccess()
|
|
237
|
+
|
|
238
|
+
def __call__(self, *args, **kwargs):
|
|
239
|
+
# If someone tries to call the module itself, return a generic schema
|
|
240
|
+
return _GenericSchema(*args, **kwargs)
|
|
241
|
+
|
|
242
|
+
def __dir__(self):
|
|
243
|
+
# Return common schema names for introspection
|
|
244
|
+
return ['Response', 'Request', 'Error', 'Data', 'Result']
|
|
245
|
+
|
|
246
|
+
class _NestedSchemaAccess:
|
|
247
|
+
"""Handles nested attribute access and final callable resolution"""
|
|
248
|
+
|
|
249
|
+
def __getattr__(self, name: str):
|
|
250
|
+
# Continue allowing nested access
|
|
251
|
+
return _NestedSchemaAccess()
|
|
252
|
+
|
|
253
|
+
def __call__(self, *args, **kwargs):
|
|
254
|
+
# When finally called, return a generic schema instance
|
|
255
|
+
return _GenericSchema(*args, **kwargs)
|
|
256
|
+
|
|
257
|
+
def __class_getitem__(cls, item):
|
|
258
|
+
# Support type annotations like schemas.Response[str]
|
|
259
|
+
return _GenericSchema
|
|
260
|
+
|
|
261
|
+
# Replace this module with our dynamic module
|
|
262
|
+
import sys
|
|
263
|
+
sys.modules[__name__] = _SchemaModule()
|
|
264
|
+
''')
|
|
265
|
+
|
|
266
|
+
|
|
208
267
|
def generate(contexts: Optional[List[str]] = None, no_types: bool = False) -> None:
|
|
209
268
|
generate_msg = f"Generating Poly Python SDK for contexts ${contexts}..." if contexts else "Generating Poly Python SDK..."
|
|
210
269
|
print(generate_msg, end="", flush=True)
|
|
@@ -216,14 +275,23 @@ def generate(contexts: Optional[List[str]] = None, no_types: bool = False) -> No
|
|
|
216
275
|
limit_ids: List[str] = [] # useful for narrowing down generation to a single function to debug
|
|
217
276
|
functions = parse_function_specs(specs, limit_ids=limit_ids)
|
|
218
277
|
|
|
219
|
-
schemas
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
278
|
+
# Only process schemas if no_types is False
|
|
279
|
+
if not no_types:
|
|
280
|
+
schemas = get_schemas()
|
|
281
|
+
schema_index = build_schema_index(schemas)
|
|
282
|
+
if schemas:
|
|
283
|
+
schema_limit_ids: List[str] = [] # useful for narrowing down generation to a single function to debug
|
|
284
|
+
schemas = replace_poly_refs_in_schemas(schemas, schema_index)
|
|
285
|
+
generate_schemas(schemas, limit_ids=schema_limit_ids)
|
|
286
|
+
|
|
287
|
+
functions = replace_poly_refs_in_functions(functions, schema_index)
|
|
288
|
+
else:
|
|
289
|
+
# When no_types is True, we still need to process functions but without schema resolution
|
|
290
|
+
# Use an empty schema index to avoid poly-ref resolution
|
|
291
|
+
schema_index = {}
|
|
292
|
+
|
|
293
|
+
# Create an empty schemas module so user code can still import from polyapi.schemas
|
|
294
|
+
create_empty_schemas_module()
|
|
227
295
|
|
|
228
296
|
if functions:
|
|
229
297
|
generate_functions(functions)
|
|
@@ -233,10 +301,11 @@ def generate(contexts: Optional[List[str]] = None, no_types: bool = False) -> No
|
|
|
233
301
|
)
|
|
234
302
|
exit()
|
|
235
303
|
|
|
236
|
-
variables
|
|
237
|
-
if
|
|
238
|
-
|
|
239
|
-
|
|
304
|
+
# Only process variables if no_types is False
|
|
305
|
+
if not no_types:
|
|
306
|
+
variables = get_variables()
|
|
307
|
+
if variables:
|
|
308
|
+
generate_variables(variables)
|
|
240
309
|
|
|
241
310
|
# indicator to vscode extension that this is a polyapi-python project
|
|
242
311
|
file_path = os.path.join(os.getcwd(), ".polyapi-python")
|
|
@@ -266,11 +335,19 @@ def render_spec(spec: SpecificationDto) -> Tuple[str, str]:
|
|
|
266
335
|
|
|
267
336
|
arguments: List[PropertySpecification] = []
|
|
268
337
|
return_type = {}
|
|
269
|
-
if spec
|
|
270
|
-
arguments
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
338
|
+
if spec.get("function"):
|
|
339
|
+
# Handle cases where arguments might be missing or None
|
|
340
|
+
if spec["function"].get("arguments"):
|
|
341
|
+
arguments = [
|
|
342
|
+
arg for arg in spec["function"]["arguments"]
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
# Handle cases where returnType might be missing or None
|
|
346
|
+
if spec["function"].get("returnType"):
|
|
347
|
+
return_type = spec["function"]["returnType"]
|
|
348
|
+
else:
|
|
349
|
+
# Provide a fallback return type when missing
|
|
350
|
+
return_type = {"kind": "any"}
|
|
274
351
|
|
|
275
352
|
if function_type == "apiFunction":
|
|
276
353
|
func_str, func_type_defs = render_api_function(
|
|
@@ -284,7 +361,7 @@ def render_spec(spec: SpecificationDto) -> Tuple[str, str]:
|
|
|
284
361
|
elif function_type == "customFunction":
|
|
285
362
|
func_str, func_type_defs = render_client_function(
|
|
286
363
|
function_name,
|
|
287
|
-
spec
|
|
364
|
+
spec.get("code", ""),
|
|
288
365
|
arguments,
|
|
289
366
|
return_type,
|
|
290
367
|
)
|
polyapi/utils.py
CHANGED
|
@@ -97,20 +97,32 @@ def get_type_and_def(
|
|
|
97
97
|
) -> Tuple[str, str]:
|
|
98
98
|
""" returns type and type definition for a given PropertyType
|
|
99
99
|
"""
|
|
100
|
+
# Handle cases where type_spec might be None or empty
|
|
101
|
+
if not type_spec:
|
|
102
|
+
return "Any", ""
|
|
103
|
+
|
|
104
|
+
# Handle cases where kind might be missing
|
|
105
|
+
if "kind" not in type_spec:
|
|
106
|
+
return "Any", ""
|
|
107
|
+
|
|
100
108
|
if type_spec["kind"] == "plain":
|
|
101
|
-
value = type_spec
|
|
109
|
+
value = type_spec.get("value", "")
|
|
102
110
|
if value.endswith("[]"):
|
|
103
111
|
primitive = map_primitive_types(value[:-2])
|
|
104
112
|
return f"List[{primitive}]", ""
|
|
105
113
|
else:
|
|
106
114
|
return map_primitive_types(value), ""
|
|
107
115
|
elif type_spec["kind"] == "primitive":
|
|
108
|
-
return map_primitive_types(type_spec
|
|
116
|
+
return map_primitive_types(type_spec.get("type", "any")), ""
|
|
109
117
|
elif type_spec["kind"] == "array":
|
|
110
118
|
if type_spec.get("items"):
|
|
111
119
|
items = type_spec["items"]
|
|
112
120
|
if items.get("$ref"):
|
|
113
|
-
|
|
121
|
+
# For no-types mode, avoid complex schema generation
|
|
122
|
+
try:
|
|
123
|
+
return wrapped_generate_schema_types(type_spec, "ResponseType", "Dict") # type: ignore
|
|
124
|
+
except:
|
|
125
|
+
return "List[Dict]", ""
|
|
114
126
|
else:
|
|
115
127
|
item_type, _ = get_type_and_def(items)
|
|
116
128
|
title = f"List[{item_type}]"
|
|
@@ -130,13 +142,20 @@ def get_type_and_def(
|
|
|
130
142
|
return "List", ""
|
|
131
143
|
elif title:
|
|
132
144
|
assert isinstance(title, str)
|
|
133
|
-
|
|
145
|
+
# For no-types mode, avoid complex schema generation
|
|
146
|
+
try:
|
|
147
|
+
return wrapped_generate_schema_types(schema, title, "Dict") # type: ignore
|
|
148
|
+
except:
|
|
149
|
+
return "Dict", ""
|
|
134
150
|
elif schema.get("allOf") and len(schema["allOf"]):
|
|
135
151
|
# we are in a case of a single allOf, lets strip off the allOf and move on!
|
|
136
152
|
# our library doesn't handle allOf well yet
|
|
137
153
|
allOf = schema["allOf"][0]
|
|
138
154
|
title = allOf.get("title", allOf.get("name", title_fallback))
|
|
139
|
-
|
|
155
|
+
try:
|
|
156
|
+
return wrapped_generate_schema_types(allOf, title, "Dict")
|
|
157
|
+
except:
|
|
158
|
+
return "Dict", ""
|
|
140
159
|
elif schema.get("items"):
|
|
141
160
|
# fallback to schema $ref name if no explicit title
|
|
142
161
|
items = schema.get("items") # type: ignore
|
|
@@ -150,9 +169,15 @@ def get_type_and_def(
|
|
|
150
169
|
return "List", ""
|
|
151
170
|
|
|
152
171
|
title = f"List[{title}]"
|
|
153
|
-
|
|
172
|
+
try:
|
|
173
|
+
return wrapped_generate_schema_types(schema, title, "List")
|
|
174
|
+
except:
|
|
175
|
+
return "List[Dict]", ""
|
|
176
|
+
elif schema.get("properties"):
|
|
177
|
+
result = wrapped_generate_schema_types(schema, "ResponseType", "Dict") # type: ignore
|
|
178
|
+
return result
|
|
154
179
|
else:
|
|
155
|
-
return "
|
|
180
|
+
return "Dict", ""
|
|
156
181
|
else:
|
|
157
182
|
return "Dict", ""
|
|
158
183
|
elif type_spec["kind"] == "function":
|
|
@@ -187,9 +212,13 @@ def get_type_and_def(
|
|
|
187
212
|
|
|
188
213
|
|
|
189
214
|
def _maybe_add_fallback_schema_name(a: PropertySpecification):
|
|
190
|
-
|
|
215
|
+
# Handle cases where type might be missing
|
|
216
|
+
if not a.get("type"):
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
if a["type"].get("kind") == "object" and a["type"].get("schema"):
|
|
191
220
|
schema = a["type"].get("schema", {})
|
|
192
|
-
if not schema.get("title") and not schema.get("name") and a
|
|
221
|
+
if not schema.get("title") and not schema.get("name") and a.get("name"):
|
|
193
222
|
schema["title"] = a["name"].title()
|
|
194
223
|
|
|
195
224
|
|
|
@@ -200,14 +229,23 @@ def parse_arguments(
|
|
|
200
229
|
arg_string = ""
|
|
201
230
|
for idx, a in enumerate(arguments):
|
|
202
231
|
_maybe_add_fallback_schema_name(a)
|
|
203
|
-
|
|
232
|
+
|
|
233
|
+
# Handle cases where type might be missing
|
|
234
|
+
arg_type_spec = a.get("type", {"kind": "any"})
|
|
235
|
+
arg_type, arg_def = get_type_and_def(arg_type_spec)
|
|
204
236
|
if arg_def:
|
|
205
237
|
args_def.append(arg_def)
|
|
206
|
-
|
|
238
|
+
|
|
239
|
+
# Handle cases where name might be missing
|
|
240
|
+
arg_name = a.get("name", f"arg{idx}")
|
|
241
|
+
a["name"] = rewrite_arg_name(arg_name)
|
|
242
|
+
|
|
207
243
|
arg_string += (
|
|
208
244
|
f" {a['name']}: {add_type_import_path(function_name, arg_type)}"
|
|
209
245
|
)
|
|
210
|
-
|
|
246
|
+
|
|
247
|
+
# Handle cases where required might be missing
|
|
248
|
+
if not a.get("required", True):
|
|
211
249
|
arg_string += " = None"
|
|
212
250
|
|
|
213
251
|
description = a.get("description", "")
|
|
@@ -10,8 +10,8 @@ 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
12
|
polyapi/execute.py,sha256=sjI6BMBYPSCD6UngV9DzpJIRSU6p02aShNaTXhDExtY,3457
|
|
13
|
-
polyapi/function_cli.py,sha256=
|
|
14
|
-
polyapi/generate.py,sha256=
|
|
13
|
+
polyapi/function_cli.py,sha256=hv5K5niegqitT6VwbS7M5ec3nEMyqwVtE6tcpwHoxIk,4125
|
|
14
|
+
polyapi/generate.py,sha256=1ZwcUEfhYLc64Wh5aYhvU6P594HOL2LYycPKkH39frc,15394
|
|
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=ehRD5o0fGJPtXEEeX8rXPmbzPzVLfLimHC2lzBkNUGs,11672
|
|
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.dev3.dist-info/licenses/LICENSE,sha256=6b_I7aPVp8JXhqQwdw7_B84Ca0S4JGjHj0sr_1VOdB4,1068
|
|
28
|
+
polyapi_python-0.3.7.dev3.dist-info/METADATA,sha256=qoFbCNu-kAltunwz4xR5hYvBAm9ErCMaLPHKvg5TjUQ,5782
|
|
29
|
+
polyapi_python-0.3.7.dev3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
polyapi_python-0.3.7.dev3.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
|
|
31
|
+
polyapi_python-0.3.7.dev3.dist-info/RECORD,,
|
{polyapi_python-0.3.7.dev2.dist-info → polyapi_python-0.3.7.dev3.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|