polyapi-python 0.1.0.dev2__tar.gz → 0.1.0.dev4__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.dev2 → polyapi-python-0.1.0.dev4}/PKG-INFO +10 -1
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/README.md +10 -1
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/api.py +13 -23
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/config.py +5 -0
- polyapi-python-0.1.0.dev4/polyapi/execute.py +37 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/generate.py +7 -19
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/schema.py +8 -1
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/typedefs.py +18 -2
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/utils.py +15 -1
- polyapi-python-0.1.0.dev4/polyapi/variables.py +103 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/PKG-INFO +10 -1
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/SOURCES.txt +3 -2
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/pyproject.toml +2 -2
- polyapi-python-0.1.0.dev2/tests/test_generate.py → polyapi-python-0.1.0.dev4/tests/test_api.py +15 -11
- polyapi-python-0.1.0.dev4/tests/test_variables.py +28 -0
- polyapi-python-0.1.0.dev2/polyapi/execute.py +0 -15
- polyapi-python-0.1.0.dev2/polyapi/variables.py +0 -86
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/LICENSE +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/__init__.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/__main__.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/cli.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/constants.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/exceptions.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/function_cli.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi/py.typed +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/dependency_links.txt +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/requires.txt +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/top_level.txt +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/setup.cfg +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/tests/test_function_cli.py +0 -0
- {polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: polyapi-python
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev4
|
|
4
4
|
Summary: The PolyAPI Python Client
|
|
5
5
|
Author-email: Dan Fellin <dan@polyapi.io>
|
|
6
6
|
License: MIT License
|
|
@@ -124,6 +124,11 @@ def bar(n: int) -> Foobar:
|
|
|
124
124
|
return Foobar(count=n)
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
## Pypi
|
|
128
|
+
|
|
129
|
+
This library is hosted on Pypi. You can find the latest version on the [pypi polyapi-python](https://pypi.org/project/polyapi-python/) project.
|
|
130
|
+
|
|
131
|
+
|
|
127
132
|
## Upgrade
|
|
128
133
|
|
|
129
134
|
To upgrade your library to the latest version, pass the upgrade flag.
|
|
@@ -147,3 +152,7 @@ To run this library's unit tests, please clone the repo then run:
|
|
|
147
152
|
```bash
|
|
148
153
|
python -m unittest discover
|
|
149
154
|
```
|
|
155
|
+
|
|
156
|
+
## Support
|
|
157
|
+
|
|
158
|
+
If you run into any issues or want help getting started with this project, please contact support@polyapi.io
|
|
@@ -88,6 +88,11 @@ def bar(n: int) -> Foobar:
|
|
|
88
88
|
return Foobar(count=n)
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
## Pypi
|
|
92
|
+
|
|
93
|
+
This library is hosted on Pypi. You can find the latest version on the [pypi polyapi-python](https://pypi.org/project/polyapi-python/) project.
|
|
94
|
+
|
|
95
|
+
|
|
91
96
|
## Upgrade
|
|
92
97
|
|
|
93
98
|
To upgrade your library to the latest version, pass the upgrade flag.
|
|
@@ -110,4 +115,8 @@ To run this library's unit tests, please clone the repo then run:
|
|
|
110
115
|
|
|
111
116
|
```bash
|
|
112
117
|
python -m unittest discover
|
|
113
|
-
```
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Support
|
|
121
|
+
|
|
122
|
+
If you run into any issues or want help getting started with this project, please contact support@polyapi.io
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Dict, List, Tuple
|
|
3
3
|
|
|
4
|
-
from polyapi.constants import BASIC_PYTHON_TYPES
|
|
4
|
+
from polyapi.constants import BASIC_PYTHON_TYPES
|
|
5
5
|
from polyapi.typedefs import PropertySpecification, PropertyType
|
|
6
|
-
from polyapi.utils import
|
|
7
|
-
from polyapi.schema import generate_schema_types, clean_title
|
|
6
|
+
from polyapi.utils import add_import_to_init, camelCase, init_the_init
|
|
7
|
+
from polyapi.schema import generate_schema_types, clean_title, map_primitive_types
|
|
8
8
|
|
|
9
9
|
# map the function type from the spec type to the function execute type
|
|
10
10
|
TEMPLATE_FUNCTION_TYPE_MAP = {
|
|
@@ -47,21 +47,16 @@ def {function_name}(
|
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def _map_primitive_types(type_: str) -> str:
|
|
51
|
-
# Define your mapping logic here
|
|
52
|
-
return JSONSCHEMA_TO_PYTHON_TYPE_MAP.get(type_, "Any")
|
|
53
|
-
|
|
54
|
-
|
|
55
50
|
def _get_type(type_spec: PropertyType) -> Tuple[str, str]:
|
|
56
51
|
if type_spec["kind"] == "plain":
|
|
57
52
|
value = type_spec["value"]
|
|
58
53
|
if value.endswith("[]"):
|
|
59
|
-
primitive =
|
|
54
|
+
primitive = map_primitive_types(value[:-2])
|
|
60
55
|
return f"List[{primitive}]", ""
|
|
61
56
|
else:
|
|
62
|
-
return
|
|
57
|
+
return map_primitive_types(value), ""
|
|
63
58
|
elif type_spec["kind"] == "primitive":
|
|
64
|
-
return
|
|
59
|
+
return map_primitive_types(type_spec["type"]), ""
|
|
65
60
|
elif type_spec["kind"] == "array":
|
|
66
61
|
if type_spec.get("items"):
|
|
67
62
|
items = type_spec["items"]
|
|
@@ -141,9 +136,10 @@ def _add_type_import_path(function_name: str, arg: str) -> str:
|
|
|
141
136
|
return arg
|
|
142
137
|
else:
|
|
143
138
|
if '"' in sub:
|
|
144
|
-
|
|
145
|
-
else:
|
|
139
|
+
sub = sub.replace('"', "")
|
|
146
140
|
return f'List["_{function_name}.{camelCase(sub)}"]'
|
|
141
|
+
else:
|
|
142
|
+
return f'List[_{function_name}.{camelCase(sub)}]'
|
|
147
143
|
|
|
148
144
|
return f'_{function_name}.{camelCase(arg)}'
|
|
149
145
|
|
|
@@ -221,8 +217,7 @@ def add_function_file(
|
|
|
221
217
|
return_type: Dict[str, Any],
|
|
222
218
|
):
|
|
223
219
|
# first lets add the import to the __init__
|
|
224
|
-
|
|
225
|
-
_init_the_init(init_path)
|
|
220
|
+
init_the_init(full_path)
|
|
226
221
|
|
|
227
222
|
func_str, func_type_defs = render_function(
|
|
228
223
|
function_type,
|
|
@@ -233,6 +228,7 @@ def add_function_file(
|
|
|
233
228
|
return_type,
|
|
234
229
|
)
|
|
235
230
|
|
|
231
|
+
init_path = os.path.join(full_path, "__init__.py")
|
|
236
232
|
with open(init_path, "a") as f:
|
|
237
233
|
f.write(f"\n\nfrom . import _{function_name}\n\n{func_str}")
|
|
238
234
|
|
|
@@ -242,12 +238,6 @@ def add_function_file(
|
|
|
242
238
|
f.write(func_type_defs)
|
|
243
239
|
|
|
244
240
|
|
|
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")
|
|
249
|
-
|
|
250
|
-
|
|
251
241
|
def create_function(
|
|
252
242
|
function_type: str,
|
|
253
243
|
path: str,
|
|
@@ -279,8 +269,8 @@ def create_function(
|
|
|
279
269
|
# append to __init__.py file if nested folders
|
|
280
270
|
next = folders[idx + 1] if idx + 2 < len(folders) else ""
|
|
281
271
|
if next:
|
|
282
|
-
|
|
283
|
-
|
|
272
|
+
init_the_init(full_path)
|
|
273
|
+
add_import_to_init(full_path, next)
|
|
284
274
|
|
|
285
275
|
|
|
286
276
|
def generate_api(api_functions: List) -> None:
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from requests import Response
|
|
3
|
+
from polyapi.config import get_api_key_and_url
|
|
4
|
+
from polyapi.exceptions import PolyApiException
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def execute(function_type, function_id, data) -> Response:
|
|
8
|
+
api_key, api_url = get_api_key_and_url()
|
|
9
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
10
|
+
url = f"{api_url}/functions/{function_type}/{function_id}/execute"
|
|
11
|
+
resp = requests.post(url, json=data, headers=headers)
|
|
12
|
+
if resp.status_code != 200 and resp.status_code != 201:
|
|
13
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
14
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
15
|
+
return resp
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def variable_get(variable_id: str) -> Response:
|
|
19
|
+
api_key, base_url = get_api_key_and_url()
|
|
20
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
21
|
+
url = f"{base_url}/variables/{variable_id}/value"
|
|
22
|
+
resp = requests.get(url, headers=headers)
|
|
23
|
+
if resp.status_code != 200 and resp.status_code != 201:
|
|
24
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
25
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
26
|
+
return resp
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def variable_update(variable_id: str, value) -> Response:
|
|
30
|
+
api_key, base_url = get_api_key_and_url()
|
|
31
|
+
headers = {"Authorization": f"Bearer {api_key}"}
|
|
32
|
+
url = f"{base_url}/variables/{variable_id}/value"
|
|
33
|
+
resp = requests.patch(url, data={"value": value}, headers=headers)
|
|
34
|
+
if resp.status_code != 200 and resp.status_code != 201:
|
|
35
|
+
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
36
|
+
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
37
|
+
return resp
|
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import shutil
|
|
5
5
|
from typing import Any, Dict, List, Tuple
|
|
6
6
|
|
|
7
|
-
from .typedefs import PropertySpecification
|
|
7
|
+
from .typedefs import PropertySpecification, VariableSpecDto
|
|
8
8
|
from .utils import get_auth_headers
|
|
9
9
|
from .api import generate_api
|
|
10
10
|
from .variables import generate_variables
|
|
@@ -81,31 +81,19 @@ def get_functions_and_parse():
|
|
|
81
81
|
return functions
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def
|
|
85
|
-
raw = get_variables()
|
|
86
|
-
variables = parse_variables(raw)
|
|
87
|
-
return variables
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def get_variables():
|
|
84
|
+
def get_variables() -> List[VariableSpecDto]:
|
|
91
85
|
api_key, api_url = get_api_key_and_url()
|
|
92
86
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
93
|
-
|
|
87
|
+
# TODO do some caching so this and get_functions just do 1 function call
|
|
88
|
+
url = f"{api_url}/specs"
|
|
94
89
|
resp = requests.get(url, headers=headers)
|
|
95
90
|
if resp.status_code == 200:
|
|
96
|
-
|
|
91
|
+
specs = resp.json()
|
|
92
|
+
return [spec for spec in specs if spec['type'] == "serverVariable"]
|
|
97
93
|
else:
|
|
98
94
|
raise NotImplementedError(resp.content)
|
|
99
95
|
|
|
100
96
|
|
|
101
|
-
def parse_variables(variables: List) -> List[Tuple[str, str, bool]]:
|
|
102
|
-
rv = []
|
|
103
|
-
for v in variables:
|
|
104
|
-
path = f"vari.{v['context']}.{v['name']}"
|
|
105
|
-
rv.append((path, v["id"], v["secret"]))
|
|
106
|
-
return rv
|
|
107
|
-
|
|
108
|
-
|
|
109
97
|
def remove_old_library():
|
|
110
98
|
currdir = os.path.dirname(os.path.abspath(__file__))
|
|
111
99
|
path = os.path.join(currdir, "poly")
|
|
@@ -131,7 +119,7 @@ def generate() -> None:
|
|
|
131
119
|
)
|
|
132
120
|
exit()
|
|
133
121
|
|
|
134
|
-
variables =
|
|
122
|
+
variables = get_variables()
|
|
135
123
|
if variables:
|
|
136
124
|
generate_variables(variables)
|
|
137
125
|
|
|
@@ -5,6 +5,8 @@ from jsonschema_gentypes import configuration
|
|
|
5
5
|
import tempfile
|
|
6
6
|
import json
|
|
7
7
|
|
|
8
|
+
from polyapi.constants import JSONSCHEMA_TO_PYTHON_TYPE_MAP
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
def _cleanup_input_for_gentypes(input_data: Dict):
|
|
10
12
|
""" cleanup input_data in place to make it more suitable for jsonschema_gentypes
|
|
@@ -83,4 +85,9 @@ def clean_title(title: str) -> str:
|
|
|
83
85
|
# certain reserved words cant be titles, let's replace them
|
|
84
86
|
if title == "List":
|
|
85
87
|
title = "List_"
|
|
86
|
-
return title
|
|
88
|
+
return title
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def map_primitive_types(type_: str) -> str:
|
|
92
|
+
# Define your mapping logic here
|
|
93
|
+
return JSONSCHEMA_TO_PYTHON_TYPE_MAP.get(type_, "Any")
|
|
@@ -32,6 +32,22 @@ class SpecificationDto(TypedDict):
|
|
|
32
32
|
context: str
|
|
33
33
|
name: str
|
|
34
34
|
description: str
|
|
35
|
+
# function is none if this is actually VariableSpecDto
|
|
35
36
|
function: FunctionSpecification | None
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
type: Literal['apiFunction', 'customFunction', 'serverFunction', 'authFunction', 'webhookHandle', 'serverVariable']
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class VariableSpecification(TypedDict):
|
|
41
|
+
environmentId: str
|
|
42
|
+
value: Any
|
|
43
|
+
valueType: PropertyType
|
|
44
|
+
secret: bool
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class VariableSpecDto(TypedDict):
|
|
48
|
+
id: str
|
|
49
|
+
context: str
|
|
50
|
+
name: str
|
|
51
|
+
description: str
|
|
52
|
+
variable: VariableSpecification
|
|
53
|
+
type: Literal['serverVariable']
|
|
@@ -2,7 +2,21 @@ import re
|
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# this string should be in every __init__ file.
|
|
6
|
+
# it contains all the imports needed for the function or variable code to run
|
|
7
|
+
CODE_IMPORTS = "from typing import List, Dict, Any, TypedDict\nfrom polyapi.execute import execute, variable_get, variable_update\n\n"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def init_the_init(full_path: str) -> None:
|
|
11
|
+
init_path = os.path.join(full_path, "__init__.py")
|
|
12
|
+
if not os.path.exists(init_path):
|
|
13
|
+
with open(init_path, "w") as f:
|
|
14
|
+
f.write(CODE_IMPORTS)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def add_import_to_init(full_path: str, next: str) -> None:
|
|
18
|
+
init_the_init(full_path)
|
|
19
|
+
|
|
6
20
|
init_path = os.path.join(full_path, "__init__.py")
|
|
7
21
|
with open(init_path, "a+") as f:
|
|
8
22
|
import_stmt = "from . import {}\n".format(next)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from polyapi.schema import map_primitive_types
|
|
5
|
+
from polyapi.typedefs import PropertyType, VariableSpecDto
|
|
6
|
+
from polyapi.utils import add_import_to_init, init_the_init
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# GET is only included if the variable is not a secret
|
|
10
|
+
GET_TEMPLATE = """
|
|
11
|
+
@staticmethod
|
|
12
|
+
def get() -> {variable_type}:
|
|
13
|
+
resp = variable_get("{variable_id}")
|
|
14
|
+
return resp.text
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
TEMPLATE = """
|
|
19
|
+
class {variable_name}:{get_method}
|
|
20
|
+
@staticmethod
|
|
21
|
+
def update(value: {variable_type}):
|
|
22
|
+
resp = variable_update("{variable_id}", value)
|
|
23
|
+
return resp.json()
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def inject(path=None) -> {variable_type}:
|
|
27
|
+
return {{
|
|
28
|
+
"type": "PolyVariable",
|
|
29
|
+
"id": "{variable_id}",
|
|
30
|
+
"path": path,
|
|
31
|
+
}} # type: ignore"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def generate_variables(variables: List[VariableSpecDto]):
|
|
35
|
+
for variable in variables:
|
|
36
|
+
create_variable(variable)
|
|
37
|
+
print("Variables generated!")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def render_variable(variable: VariableSpecDto):
|
|
41
|
+
variable_type = _get_variable_type(variable["variable"]["valueType"])
|
|
42
|
+
get_method = (
|
|
43
|
+
""
|
|
44
|
+
if variable["variable"]["secret"]
|
|
45
|
+
else GET_TEMPLATE.format(
|
|
46
|
+
variable_id=variable["id"], variable_type=variable_type
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
return TEMPLATE.format(
|
|
50
|
+
variable_name=variable["name"],
|
|
51
|
+
variable_id=variable["id"],
|
|
52
|
+
variable_type=variable_type,
|
|
53
|
+
get_method=get_method,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _get_variable_type(type_spec: PropertyType) -> str:
|
|
58
|
+
# simplified version of _get_type from api.py
|
|
59
|
+
if type_spec["kind"] == "plain":
|
|
60
|
+
value = type_spec["value"]
|
|
61
|
+
if value.endswith("[]"):
|
|
62
|
+
primitive = map_primitive_types(value[:-2])
|
|
63
|
+
return f"List[{primitive}]"
|
|
64
|
+
else:
|
|
65
|
+
return map_primitive_types(value)
|
|
66
|
+
elif type_spec["kind"] == "primitive":
|
|
67
|
+
return map_primitive_types(type_spec["type"])
|
|
68
|
+
elif type_spec["kind"] == "array":
|
|
69
|
+
return "List"
|
|
70
|
+
elif type_spec["kind"] == "void":
|
|
71
|
+
return "None"
|
|
72
|
+
elif type_spec["kind"] == "object":
|
|
73
|
+
return "Dict"
|
|
74
|
+
elif type_spec["kind"] == "any":
|
|
75
|
+
return "Any"
|
|
76
|
+
else:
|
|
77
|
+
return "Any"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def create_variable(variable: VariableSpecDto) -> None:
|
|
81
|
+
folders = ["vari"]
|
|
82
|
+
if variable["context"]:
|
|
83
|
+
folders += variable["context"].split(".")
|
|
84
|
+
|
|
85
|
+
# build up the full_path by adding all the folders
|
|
86
|
+
full_path = os.path.join(os.path.dirname(os.path.abspath(__file__)))
|
|
87
|
+
|
|
88
|
+
for idx, folder in enumerate(folders):
|
|
89
|
+
full_path = os.path.join(full_path, folder)
|
|
90
|
+
if not os.path.exists(full_path):
|
|
91
|
+
os.makedirs(full_path)
|
|
92
|
+
next = folders[idx + 1] if idx + 1 < len(folders) else None
|
|
93
|
+
if next:
|
|
94
|
+
add_import_to_init(full_path, next)
|
|
95
|
+
|
|
96
|
+
add_variable_to_init(full_path, variable)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def add_variable_to_init(full_path: str, variable: VariableSpecDto):
|
|
100
|
+
init_the_init(full_path)
|
|
101
|
+
init_path = os.path.join(full_path, "__init__.py")
|
|
102
|
+
with open(init_path, "a") as f:
|
|
103
|
+
f.write(render_variable(variable) + "\n\n")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: polyapi-python
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev4
|
|
4
4
|
Summary: The PolyAPI Python Client
|
|
5
5
|
Author-email: Dan Fellin <dan@polyapi.io>
|
|
6
6
|
License: MIT License
|
|
@@ -124,6 +124,11 @@ def bar(n: int) -> Foobar:
|
|
|
124
124
|
return Foobar(count=n)
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
## Pypi
|
|
128
|
+
|
|
129
|
+
This library is hosted on Pypi. You can find the latest version on the [pypi polyapi-python](https://pypi.org/project/polyapi-python/) project.
|
|
130
|
+
|
|
131
|
+
|
|
127
132
|
## Upgrade
|
|
128
133
|
|
|
129
134
|
To upgrade your library to the latest version, pass the upgrade flag.
|
|
@@ -147,3 +152,7 @@ To run this library's unit tests, please clone the repo then run:
|
|
|
147
152
|
```bash
|
|
148
153
|
python -m unittest discover
|
|
149
154
|
```
|
|
155
|
+
|
|
156
|
+
## Support
|
|
157
|
+
|
|
158
|
+
If you run into any issues or want help getting started with this project, please contact support@polyapi.io
|
|
@@ -21,6 +21,7 @@ polyapi_python.egg-info/SOURCES.txt
|
|
|
21
21
|
polyapi_python.egg-info/dependency_links.txt
|
|
22
22
|
polyapi_python.egg-info/requires.txt
|
|
23
23
|
polyapi_python.egg-info/top_level.txt
|
|
24
|
+
tests/test_api.py
|
|
24
25
|
tests/test_function_cli.py
|
|
25
|
-
tests/
|
|
26
|
-
tests/
|
|
26
|
+
tests/test_utils.py
|
|
27
|
+
tests/test_variables.py
|
|
@@ -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.dev4"
|
|
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"]
|
|
@@ -19,4 +19,4 @@ packages = ["polyapi"]
|
|
|
19
19
|
|
|
20
20
|
[tools.setuptools.packages.find]
|
|
21
21
|
include = ["polyapi"]
|
|
22
|
-
exclude = ["polyapi/poly*", "polyapi/vari*", "polyapi/.config.env"] # exclude the generated libraries from builds
|
|
22
|
+
exclude = ["polyapi/poly*", "polyapi/vari*", "polyapi/.config.env"] # exclude the generated libraries from builds
|
polyapi-python-0.1.0.dev2/tests/test_generate.py → polyapi-python-0.1.0.dev4/tests/test_api.py
RENAMED
|
@@ -155,9 +155,10 @@ GET_PRODUCTS_COUNT = {
|
|
|
155
155
|
|
|
156
156
|
class T(unittest.TestCase):
|
|
157
157
|
def test_render_function_accuweather(self):
|
|
158
|
-
|
|
158
|
+
name = ACCUWEATHER["name"]
|
|
159
|
+
func_str, _ = render_function(
|
|
159
160
|
ACCUWEATHER["type"],
|
|
160
|
-
|
|
161
|
+
name,
|
|
161
162
|
ACCUWEATHER["id"],
|
|
162
163
|
ACCUWEATHER["description"],
|
|
163
164
|
ACCUWEATHER["function"]["arguments"],
|
|
@@ -165,12 +166,13 @@ class T(unittest.TestCase):
|
|
|
165
166
|
)
|
|
166
167
|
self.assertIn(ACCUWEATHER["id"], func_str)
|
|
167
168
|
self.assertIn("locationId: int,", func_str)
|
|
168
|
-
self.assertIn("->
|
|
169
|
+
self.assertIn(f"-> _{name}.{name}Response", func_str)
|
|
169
170
|
|
|
170
171
|
def test_render_function_zillow(self):
|
|
171
|
-
|
|
172
|
+
name = ZILLOW['name']
|
|
173
|
+
func_str, _ = render_function(
|
|
172
174
|
ZILLOW["type"],
|
|
173
|
-
|
|
175
|
+
name,
|
|
174
176
|
ZILLOW["id"],
|
|
175
177
|
ZILLOW["description"],
|
|
176
178
|
ZILLOW["function"]["arguments"],
|
|
@@ -178,10 +180,11 @@ class T(unittest.TestCase):
|
|
|
178
180
|
)
|
|
179
181
|
self.assertIn(ZILLOW["id"], func_str)
|
|
180
182
|
self.assertIn("locationId: int,", func_str)
|
|
181
|
-
self.assertIn("->
|
|
183
|
+
self.assertIn(f"-> _{name}.{name}Response", func_str)
|
|
182
184
|
|
|
183
185
|
def test_render_function_twilio_api(self):
|
|
184
|
-
|
|
186
|
+
name = TWILIO['name']
|
|
187
|
+
func_str, _ = render_function(
|
|
185
188
|
TWILIO["type"],
|
|
186
189
|
TWILIO["name"],
|
|
187
190
|
TWILIO["id"],
|
|
@@ -192,11 +195,12 @@ class T(unittest.TestCase):
|
|
|
192
195
|
self.assertIn(TWILIO["id"], func_str)
|
|
193
196
|
self.assertIn("conversationSID: str", func_str)
|
|
194
197
|
self.assertIn("authToken: str", func_str)
|
|
195
|
-
self.assertIn("->
|
|
198
|
+
self.assertIn(f"-> _{name}.{name}Response", func_str)
|
|
196
199
|
|
|
197
200
|
def test_render_function_twilio_server(self):
|
|
198
201
|
# same test but try it as a serverFunction rather than an apiFunction
|
|
199
|
-
|
|
202
|
+
name = TWILIO['name']
|
|
203
|
+
func_str, _ = render_function(
|
|
200
204
|
"serverFunction",
|
|
201
205
|
TWILIO["name"],
|
|
202
206
|
TWILIO["id"],
|
|
@@ -207,11 +211,11 @@ class T(unittest.TestCase):
|
|
|
207
211
|
self.assertIn(TWILIO["id"], func_str)
|
|
208
212
|
self.assertIn("conversationSID: str", func_str)
|
|
209
213
|
self.assertIn("authToken: str", func_str)
|
|
210
|
-
self.assertIn("-> ResponseType", func_str)
|
|
214
|
+
self.assertIn(f"-> _{name}.ResponseType", func_str)
|
|
211
215
|
|
|
212
216
|
def test_render_function_get_products_count(self):
|
|
213
217
|
return_type = GET_PRODUCTS_COUNT["function"]["returnType"]
|
|
214
|
-
func_str = render_function(
|
|
218
|
+
func_str, _ = render_function(
|
|
215
219
|
GET_PRODUCTS_COUNT["type"],
|
|
216
220
|
GET_PRODUCTS_COUNT["name"],
|
|
217
221
|
GET_PRODUCTS_COUNT["id"],
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from polyapi.variables import render_variable
|
|
3
|
+
|
|
4
|
+
EXAMPLE = {
|
|
5
|
+
"type": "serverVariable",
|
|
6
|
+
"id": "181238j18231j",
|
|
7
|
+
"name": "test",
|
|
8
|
+
"context": "my3",
|
|
9
|
+
"description": "a test variable",
|
|
10
|
+
"visibilityMetadata": {
|
|
11
|
+
"visibility": "ENVIRONMENT"
|
|
12
|
+
},
|
|
13
|
+
"variable": {
|
|
14
|
+
"environmentId": "123818231",
|
|
15
|
+
"secret": False,
|
|
16
|
+
"valueType": {
|
|
17
|
+
"kind": "primitive",
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"value": "some mock value"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class T(unittest.TestCase):
|
|
26
|
+
def test_render_variable(self):
|
|
27
|
+
variable_str = render_variable(EXAMPLE)
|
|
28
|
+
self.assertIn("class test", variable_str)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
from requests import Response
|
|
3
|
-
from polyapi.config import get_api_key_and_url
|
|
4
|
-
from polyapi.exceptions import PolyApiException
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def execute(function_type, function_id, data) -> Response:
|
|
8
|
-
api_key, api_url = get_api_key_and_url()
|
|
9
|
-
headers = {"Authorization": f"Bearer {api_key}"}
|
|
10
|
-
url = f"{api_url}/functions/{function_type}/{function_id}/execute"
|
|
11
|
-
resp = requests.post(url, json=data, headers=headers)
|
|
12
|
-
if resp.status_code != 200 and resp.status_code != 201:
|
|
13
|
-
error_content = resp.content.decode("utf-8", errors="ignore")
|
|
14
|
-
raise PolyApiException(f"{resp.status_code}: {error_content}")
|
|
15
|
-
return resp
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from polyapi.utils import append_init
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
TEMPLATE = """
|
|
7
|
-
import requests
|
|
8
|
-
from polyapi.config import get_api_key_and_url
|
|
9
|
-
from polyapi.exceptions import PolyApiException
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class {variable_name}:
|
|
13
|
-
@staticmethod
|
|
14
|
-
def get():
|
|
15
|
-
secret = {secret}
|
|
16
|
-
if secret:
|
|
17
|
-
raise ValueError('Cannot access secret variable from client. Use .inject() instead within Poly function.')
|
|
18
|
-
else:
|
|
19
|
-
api_key, base_url = get_api_key_and_url()
|
|
20
|
-
headers = {{"Authorization": f"Bearer {{api_key}}"}}
|
|
21
|
-
url = f"{{base_url}}/variables/{variable_id}/value"
|
|
22
|
-
resp = requests.get(url, headers=headers)
|
|
23
|
-
if resp.status_code != 200 and resp.status_code != 201:
|
|
24
|
-
raise PolyApiException(f"{{resp.status_code}}: {{resp.content}}")
|
|
25
|
-
return resp.text
|
|
26
|
-
|
|
27
|
-
@staticmethod
|
|
28
|
-
def update(value):
|
|
29
|
-
api_key, base_url = get_api_key_and_url()
|
|
30
|
-
headers = {{"Authorization": f"Bearer {{api_key}}"}}
|
|
31
|
-
url = f"{{base_url}}/variables/{variable_id}"
|
|
32
|
-
resp = requests.patch(url, data={{"value": value}}, headers=headers)
|
|
33
|
-
if resp.status_code != 200 and resp.status_code != 201:
|
|
34
|
-
raise PolyApiException(f"{{resp.status_code}}: {{resp.content}}")
|
|
35
|
-
return resp.json()
|
|
36
|
-
|
|
37
|
-
def inject(path=None):
|
|
38
|
-
return {{
|
|
39
|
-
"type": "PolyVariable",
|
|
40
|
-
"id": "{variable_id}",
|
|
41
|
-
"path": path,
|
|
42
|
-
}}
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def generate_variables(variables):
|
|
47
|
-
for variable in variables:
|
|
48
|
-
create_variable(*variable)
|
|
49
|
-
print("Variables generated!")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def add_variable_file(full_path: str, variable_name: str, variable_id: str, secret: str):
|
|
53
|
-
# first lets add the import to the __init__
|
|
54
|
-
init_path = os.path.join(full_path, "__init__.py")
|
|
55
|
-
with open(init_path, "a") as f:
|
|
56
|
-
f.write(f"from ._{variable_name} import {variable_name}\n")
|
|
57
|
-
|
|
58
|
-
# now lets add the code!
|
|
59
|
-
file_path = os.path.join(full_path, f"_{variable_name}.py")
|
|
60
|
-
with open(file_path, "w") as f:
|
|
61
|
-
f.write(
|
|
62
|
-
TEMPLATE.format(
|
|
63
|
-
variable_name=variable_name,
|
|
64
|
-
variable_id=variable_id,
|
|
65
|
-
secret=secret,
|
|
66
|
-
)
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def create_variable(path: str, variable_id: str, secret: str) -> None:
|
|
71
|
-
full_path = os.path.dirname(os.path.abspath(__file__))
|
|
72
|
-
|
|
73
|
-
folders = path.split(".")
|
|
74
|
-
for idx, folder in enumerate(folders):
|
|
75
|
-
if idx + 1 == len(folders):
|
|
76
|
-
variable_name = folder
|
|
77
|
-
add_variable_file(full_path, variable_name, variable_id, secret)
|
|
78
|
-
else:
|
|
79
|
-
full_path = os.path.join(full_path, folder)
|
|
80
|
-
if not os.path.exists(full_path):
|
|
81
|
-
os.makedirs(full_path)
|
|
82
|
-
|
|
83
|
-
# append to __init__.py file if nested folders
|
|
84
|
-
next = folders[idx + 1] if idx + 2 < len(folders) else ""
|
|
85
|
-
if next:
|
|
86
|
-
append_init(full_path, next)
|
|
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.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{polyapi-python-0.1.0.dev2 → polyapi-python-0.1.0.dev4}/polyapi_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|