polyapi-python 0.0.30__tar.gz → 0.1.0.dev0__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.
Files changed (28) hide show
  1. {polyapi-python-0.0.30/polyapi_python.egg-info → polyapi-python-0.1.0.dev0}/PKG-INFO +10 -2
  2. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/README.md +9 -1
  3. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/api.py +61 -34
  4. polyapi-python-0.1.0.dev0/polyapi/execute.py +16 -0
  5. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/generate.py +31 -10
  6. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0/polyapi_python.egg-info}/PKG-INFO +10 -2
  7. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi_python.egg-info/SOURCES.txt +1 -0
  8. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/pyproject.toml +2 -2
  9. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/tests/test_generate.py +5 -0
  10. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/LICENSE +0 -0
  11. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/__init__.py +0 -0
  12. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/__main__.py +0 -0
  13. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/cli.py +0 -0
  14. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/config.py +0 -0
  15. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/constants.py +0 -0
  16. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/exceptions.py +0 -0
  17. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/function_cli.py +0 -0
  18. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/py.typed +0 -0
  19. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/schema.py +0 -0
  20. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/typedefs.py +0 -0
  21. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/utils.py +0 -0
  22. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi/variables.py +0 -0
  23. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi_python.egg-info/dependency_links.txt +0 -0
  24. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi_python.egg-info/requires.txt +0 -0
  25. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/polyapi_python.egg-info/top_level.txt +0 -0
  26. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/setup.cfg +0 -0
  27. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/tests/test_function_cli.py +0 -0
  28. {polyapi-python-0.0.30 → polyapi-python-0.1.0.dev0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polyapi-python
3
- Version: 0.0.30
3
+ Version: 0.1.0.dev0
4
4
  Summary: The PolyAPI Python Client
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -126,12 +126,20 @@ def bar(n: int) -> Foobar:
126
126
 
127
127
  ## Upgrade
128
128
 
129
- To upgrade your library to the latest version, pass the upgrade flag.:
129
+ To upgrade your library to the latest version, pass the upgrade flag.
130
130
 
131
131
  ```bash
132
132
  pip install polyapi-python --upgrade
133
133
  ```
134
134
 
135
+ ## Pre-Release
136
+
137
+ To upgrade your library to the latest dev version, pass the `--pre` flag.
138
+
139
+ ```bash
140
+ pip install polyapi-python --pre --upgrade
141
+ ```
142
+
135
143
  ## Unit Tests
136
144
 
137
145
  To run this library's unit tests, please clone the repo then run:
@@ -90,12 +90,20 @@ def bar(n: int) -> Foobar:
90
90
 
91
91
  ## Upgrade
92
92
 
93
- To upgrade your library to the latest version, pass the upgrade flag.:
93
+ To upgrade your library to the latest version, pass the upgrade flag.
94
94
 
95
95
  ```bash
96
96
  pip install polyapi-python --upgrade
97
97
  ```
98
98
 
99
+ ## Pre-Release
100
+
101
+ To upgrade your library to the latest dev version, pass the `--pre` flag.
102
+
103
+ ```bash
104
+ pip install polyapi-python --pre --upgrade
105
+ ```
106
+
99
107
  ## Unit Tests
100
108
 
101
109
  To run this library's unit tests, please clone the repo then run:
@@ -15,16 +15,15 @@ TEMPLATE_FUNCTION_TYPE_MAP = {
15
15
  SERVER_TEMPLATE = """
16
16
  import requests
17
17
  from typing import List, Dict, Any
18
- from polyapi.config import get_api_key_and_url
18
+ from polyapi.execute import execute
19
19
  from polyapi.exceptions import PolyApiException
20
20
  {args_def}
21
21
  {return_type_def}
22
- def {function_name}({args}) -> {return_type_name}:
23
- api_key, api_url = get_api_key_and_url()
24
- headers = {{"Authorization": f"Bearer {{api_key}}"}}
25
- url = f"{{api_url}}/functions/{function_type}/{function_id}/execute"
26
- data = {data}
27
- resp = requests.post(url, json=data, headers=headers)
22
+ def {function_name}(
23
+ {args}
24
+ ) -> {return_type_name}:
25
+ "{function_description}"
26
+ resp = execute("{function_type}", "{function_id}", {data})
28
27
  if resp.status_code != 200 and resp.status_code != 201:
29
28
  error_content = resp.content.decode("utf-8", errors="ignore")
30
29
  raise PolyApiException(f"{{resp.status_code}}: {{error_content}}")
@@ -35,7 +34,7 @@ def {function_name}({args}) -> {return_type_name}:
35
34
  API_TEMPLATE = """
36
35
  import requests
37
36
  from typing import List, Dict, Any, TypedDict
38
- from polyapi.config import get_api_key_and_url
37
+ from polyapi.execute import execute
39
38
  from polyapi.exceptions import PolyApiException
40
39
  {args_def}
41
40
  {return_type_def}
@@ -45,12 +44,11 @@ class ApiFunctionResponse(TypedDict):
45
44
  data: {return_type_name}
46
45
 
47
46
 
48
- def {function_name}({args}) -> ApiFunctionResponse:
49
- api_key, api_url = get_api_key_and_url()
50
- headers = {{"Authorization": f"Bearer {{api_key}}"}}
51
- url = f"{{api_url}}/functions/{function_type}/{function_id}/execute"
52
- data = {data}
53
- resp = requests.post(url, json=data, headers=headers)
47
+ def {function_name}(
48
+ {args}
49
+ ) -> ApiFunctionResponse:
50
+ "{function_description}"
51
+ resp = execute("{function_type}", "{function_id}", {data})
54
52
  if resp.status_code != 200 and resp.status_code != 201:
55
53
  error_content = resp.content.decode("utf-8", errors="ignore")
56
54
  raise PolyApiException(f"{{resp.status_code}}: {{error_content}}")
@@ -108,7 +106,7 @@ def _get_type(type_spec: PropertyType) -> Tuple[str, str]:
108
106
  if not title:
109
107
  return "List", ""
110
108
 
111
- title = f'List[{title}]'
109
+ title = f"List[{title}]"
112
110
  return title, generate_schema_types(schema, root=title)
113
111
  else:
114
112
  return "Any", ""
@@ -122,20 +120,29 @@ def _get_type(type_spec: PropertyType) -> Tuple[str, str]:
122
120
 
123
121
  def _parse_arguments(arguments: List[PropertySpecification]) -> Tuple[str, str]:
124
122
  args_def = []
125
- arg_strings = []
126
- for a in arguments:
123
+ arg_string = ""
124
+ for idx, a in enumerate(arguments):
127
125
  arg_type, arg_def = _get_type(a["type"])
128
126
  if arg_def:
129
127
  args_def.append(arg_def)
130
- a['name'] = camelCase(a["name"])
131
- arg_strings.append(f"{a['name']}: {arg_type}")
132
- return ", ".join(arg_strings), "\n\n".join(args_def)
128
+ a["name"] = camelCase(a["name"])
129
+ arg_string += f" {a['name']}: {arg_type}"
130
+ description = a.get("description", "")
131
+ if description:
132
+ if idx == len(arguments) - 1:
133
+ arg_string += f" # {description}\n"
134
+ else:
135
+ arg_string += f", # {description}\n"
136
+ else:
137
+ arg_string += ",\n"
138
+ return arg_string.rstrip("\n"), "\n\n".join(args_def)
133
139
 
134
140
 
135
141
  def render_function(
136
142
  function_type: str,
137
143
  function_name: str,
138
144
  function_id: str,
145
+ function_description: str,
139
146
  arguments: List[PropertySpecification],
140
147
  return_type: Dict[str, Any],
141
148
  ) -> str:
@@ -148,6 +155,7 @@ def render_function(
148
155
  function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
149
156
  function_name=function_name,
150
157
  function_id=function_id,
158
+ function_description=function_description.replace('"', "'"),
151
159
  args=args,
152
160
  args_def=args_def,
153
161
  return_type_name=return_type_name,
@@ -155,22 +163,12 @@ def render_function(
155
163
  data=data,
156
164
  )
157
165
  else:
158
- if return_type_name == "str":
159
- return_action = "resp.text"
160
- elif return_type_name == "Any":
161
- return_action = "resp.text"
162
- elif return_type_name == "int":
163
- return_action = "int(resp.text.replace('(int) ', ''))"
164
- elif return_type_name == "float":
165
- return_action = "float(resp.text.replace('(float) ', ''))"
166
- elif return_type_name == "bool":
167
- return_action = "False if resp.text == 'False' else True"
168
- else:
169
- return_action = "resp.json()"
166
+ return_action = _get_server_return_action(return_type_name)
170
167
  rendered = SERVER_TEMPLATE.format(
171
168
  function_type=TEMPLATE_FUNCTION_TYPE_MAP[function_type],
172
169
  function_name=function_name,
173
170
  function_id=function_id,
171
+ function_description=function_description.replace('"', "'"),
174
172
  args=args,
175
173
  args_def=args_def,
176
174
  return_type_name=return_type_name,
@@ -181,11 +179,28 @@ def render_function(
181
179
  return rendered
182
180
 
183
181
 
182
+ def _get_server_return_action(return_type_name: str) -> str:
183
+ if return_type_name == "str":
184
+ return_action = "resp.text"
185
+ elif return_type_name == "Any":
186
+ return_action = "resp.text"
187
+ elif return_type_name == "int":
188
+ return_action = "int(resp.text.replace('(int) ', ''))"
189
+ elif return_type_name == "float":
190
+ return_action = "float(resp.text.replace('(float) ', ''))"
191
+ elif return_type_name == "bool":
192
+ return_action = "False if resp.text == 'False' else True"
193
+ else:
194
+ return_action = "resp.json()"
195
+ return return_action
196
+
197
+
184
198
  def add_function_file(
185
199
  function_type: str,
186
200
  full_path: str,
187
201
  function_name: str,
188
202
  function_id: str,
203
+ function_description: str,
189
204
  arguments: List[PropertySpecification],
190
205
  return_type: Dict[str, Any],
191
206
  ):
@@ -199,7 +214,12 @@ def add_function_file(
199
214
  with open(file_path, "w") as f:
200
215
  f.write(
201
216
  render_function(
202
- function_type, function_name, function_id, arguments, return_type
217
+ function_type,
218
+ function_name,
219
+ function_id,
220
+ function_description,
221
+ arguments,
222
+ return_type,
203
223
  )
204
224
  )
205
225
 
@@ -208,6 +228,7 @@ def create_function(
208
228
  function_type: str,
209
229
  path: str,
210
230
  function_id: str,
231
+ function_description: str,
211
232
  arguments: List[PropertySpecification],
212
233
  return_type: Dict[str, Any],
213
234
  ) -> None:
@@ -218,7 +239,13 @@ def create_function(
218
239
  if idx + 1 == len(folders):
219
240
  # special handling for final level
220
241
  add_function_file(
221
- function_type, full_path, folder, function_id, arguments, return_type
242
+ function_type,
243
+ full_path,
244
+ folder,
245
+ function_id,
246
+ function_description,
247
+ arguments,
248
+ return_type,
222
249
  )
223
250
  else:
224
251
  full_path = os.path.join(full_path, folder)
@@ -0,0 +1,16 @@
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
+ # TODO use this to cleanup generated code
8
+ def execute(function_type, function_id, data) -> Response:
9
+ api_key, api_url = get_api_key_and_url()
10
+ headers = {"Authorization": f"Bearer {api_key}"}
11
+ url = f"{api_url}/functions/{function_type}/{function_id}/execute"
12
+ resp = requests.post(url, json=data, headers=headers)
13
+ if resp.status_code != 200 and resp.status_code != 201:
14
+ error_content = resp.content.decode("utf-8", errors="ignore")
15
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
16
+ return resp
@@ -1,4 +1,4 @@
1
- import sys
1
+ import json
2
2
  import requests
3
3
  import os
4
4
  import shutil
@@ -25,9 +25,16 @@ def get_specs() -> List:
25
25
 
26
26
  def parse_specs(
27
27
  specs: List,
28
- ) -> List[Tuple[str, str, str, List[PropertySpecification], Dict[str, Any]]]:
28
+ ) -> List[Tuple[str, str, str, str, List[PropertySpecification], Dict[str, Any]]]:
29
+ # optional array of ids to include in the generated library
30
+ # currently just used for testing/development purposes
31
+ allowed_ids: List[str] = []
32
+
29
33
  api_functions = []
30
34
  for spec in specs:
35
+ if allowed_ids and spec["id"] not in allowed_ids:
36
+ continue
37
+
31
38
  if spec["type"] != "apiFunction" and spec["type"] != "serverFunction":
32
39
  # for now we only support api and server functions
33
40
  continue
@@ -43,6 +50,7 @@ def parse_specs(
43
50
  function_type,
44
51
  function_name,
45
52
  function_id,
53
+ spec["description"],
46
54
  arguments,
47
55
  spec["function"]["returnType"],
48
56
  )
@@ -50,10 +58,27 @@ def parse_specs(
50
58
  return api_functions
51
59
 
52
60
 
53
- def get_specs_and_parse():
61
+ def cache_specs(specs):
62
+ supported = []
63
+ for spec in specs:
64
+ # this needs to stay in sync with logic in parse_specs
65
+ if spec["type"] == "apiFunction" or spec["type"] == "serverFunction":
66
+ supported.append(spec)
67
+
68
+ full_path = os.path.dirname(os.path.abspath(__file__))
69
+ full_path = os.path.join(full_path, "poly")
70
+ if not os.path.exists(full_path):
71
+ os.makedirs(full_path)
72
+
73
+ with open(os.path.join(full_path, "specs.json"), "w") as f:
74
+ f.write(json.dumps(supported))
75
+
76
+
77
+ def get_functions_and_parse():
54
78
  specs = get_specs()
55
- api_functions = parse_specs(specs)
56
- return api_functions
79
+ cache_specs(specs)
80
+ functions = parse_specs(specs)
81
+ return functions
57
82
 
58
83
 
59
84
  def get_variables_and_parse() -> List[Tuple[str, str, bool]]:
@@ -97,14 +122,10 @@ def generate() -> None:
97
122
 
98
123
  remove_old_library()
99
124
 
100
- functions = get_specs_and_parse()
125
+ functions = get_functions_and_parse()
101
126
  if functions:
102
127
  generate_api(functions)
103
128
  else:
104
- full_path = os.path.dirname(os.path.abspath(__file__))
105
- full_path = os.path.join(full_path, "poly")
106
- if not os.path.exists(full_path):
107
- os.makedirs(full_path)
108
129
  print(
109
130
  "No functions exist yet in this tenant! Empty library initialized. Let's add some functions!"
110
131
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polyapi-python
3
- Version: 0.0.30
3
+ Version: 0.1.0.dev0
4
4
  Summary: The PolyAPI Python Client
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -126,12 +126,20 @@ def bar(n: int) -> Foobar:
126
126
 
127
127
  ## Upgrade
128
128
 
129
- To upgrade your library to the latest version, pass the upgrade flag.:
129
+ To upgrade your library to the latest version, pass the upgrade flag.
130
130
 
131
131
  ```bash
132
132
  pip install polyapi-python --upgrade
133
133
  ```
134
134
 
135
+ ## Pre-Release
136
+
137
+ To upgrade your library to the latest dev version, pass the `--pre` flag.
138
+
139
+ ```bash
140
+ pip install polyapi-python --pre --upgrade
141
+ ```
142
+
135
143
  ## Unit Tests
136
144
 
137
145
  To run this library's unit tests, please clone the repo then run:
@@ -8,6 +8,7 @@ polyapi/cli.py
8
8
  polyapi/config.py
9
9
  polyapi/constants.py
10
10
  polyapi/exceptions.py
11
+ polyapi/execute.py
11
12
  polyapi/function_cli.py
12
13
  polyapi/generate.py
13
14
  polyapi/py.typed
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.2", "wheel"]
3
3
 
4
4
  [project]
5
5
  name = "polyapi-python"
6
- version = "0.0.30"
6
+ version = "0.1.0.dev0"
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*"] # exclude the generated libraries from builds
22
+ exclude = ["polyapi/poly*", "polyapi/vari*", "polyapi/.config.env"] # exclude the generated libraries from builds
@@ -159,6 +159,7 @@ class T(unittest.TestCase):
159
159
  ACCUWEATHER["type"],
160
160
  ACCUWEATHER["name"],
161
161
  ACCUWEATHER["id"],
162
+ ACCUWEATHER["description"],
162
163
  ACCUWEATHER["function"]["arguments"],
163
164
  ACCUWEATHER["function"]["returnType"],
164
165
  )
@@ -171,6 +172,7 @@ class T(unittest.TestCase):
171
172
  ZILLOW["type"],
172
173
  ZILLOW["name"],
173
174
  ZILLOW["id"],
175
+ ZILLOW["description"],
174
176
  ZILLOW["function"]["arguments"],
175
177
  ZILLOW["function"]["returnType"],
176
178
  )
@@ -183,6 +185,7 @@ class T(unittest.TestCase):
183
185
  TWILIO["type"],
184
186
  TWILIO["name"],
185
187
  TWILIO["id"],
188
+ TWILIO["description"],
186
189
  TWILIO["function"]["arguments"],
187
190
  TWILIO["function"]["returnType"],
188
191
  )
@@ -197,6 +200,7 @@ class T(unittest.TestCase):
197
200
  "serverFunction",
198
201
  TWILIO["name"],
199
202
  TWILIO["id"],
203
+ TWILIO["description"],
200
204
  TWILIO["function"]["arguments"],
201
205
  TWILIO["function"]["returnType"],
202
206
  )
@@ -211,6 +215,7 @@ class T(unittest.TestCase):
211
215
  GET_PRODUCTS_COUNT["type"],
212
216
  GET_PRODUCTS_COUNT["name"],
213
217
  GET_PRODUCTS_COUNT["id"],
218
+ GET_PRODUCTS_COUNT["description"],
214
219
  GET_PRODUCTS_COUNT["function"]["arguments"],
215
220
  return_type,
216
221
  )