polyapi-python 0.3.13.dev3__tar.gz → 0.3.14__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 (54) hide show
  1. {polyapi_python-0.3.13.dev3/polyapi_python.egg-info → polyapi_python-0.3.14}/PKG-INFO +13 -4
  2. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/README.md +8 -0
  3. polyapi_python-0.3.14/polyapi/__init__.py +163 -0
  4. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/api.py +19 -0
  5. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/auth.py +33 -0
  6. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/cli.py +1 -3
  7. polyapi_python-0.3.14/polyapi/cli_constants.py +10 -0
  8. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/constants.py +7 -4
  9. polyapi_python-0.3.14/polyapi/execute.py +224 -0
  10. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/function_cli.py +3 -4
  11. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/generate.py +2 -2
  12. polyapi_python-0.3.14/polyapi/http_client.py +73 -0
  13. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/poly_tables.py +2 -2
  14. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/prepare.py +3 -4
  15. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/rendered_spec.py +3 -3
  16. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/server.py +14 -0
  17. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/sync.py +4 -5
  18. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/utils.py +1 -2
  19. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/variables.py +10 -0
  20. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14/polyapi_python.egg-info}/PKG-INFO +13 -4
  21. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi_python.egg-info/SOURCES.txt +4 -0
  22. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi_python.egg-info/requires.txt +4 -3
  23. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/pyproject.toml +5 -4
  24. polyapi_python-0.3.14/tests/test_async_proof.py +412 -0
  25. polyapi_python-0.3.14/tests/test_poly_custom.py +130 -0
  26. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_rendered_spec.py +1 -1
  27. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_tabi.py +18 -4
  28. polyapi_python-0.3.13.dev3/polyapi/__init__.py +0 -101
  29. polyapi_python-0.3.13.dev3/polyapi/execute.py +0 -109
  30. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/LICENSE +0 -0
  31. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/__main__.py +0 -0
  32. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/client.py +0 -0
  33. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/config.py +0 -0
  34. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/deployables.py +0 -0
  35. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/error_handler.py +0 -0
  36. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/exceptions.py +0 -0
  37. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/parser.py +0 -0
  38. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/poly_schemas.py +0 -0
  39. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/py.typed +0 -0
  40. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/schema.py +0 -0
  41. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/typedefs.py +0 -0
  42. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi/webhook.py +0 -0
  43. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi_python.egg-info/dependency_links.txt +0 -0
  44. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/polyapi_python.egg-info/top_level.txt +0 -0
  45. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/setup.cfg +0 -0
  46. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_api.py +0 -0
  47. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_auth.py +0 -0
  48. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_deployables.py +0 -0
  49. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_generate.py +0 -0
  50. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_parser.py +0 -0
  51. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_schema.py +0 -0
  52. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_server.py +0 -0
  53. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_utils.py +0 -0
  54. {polyapi_python-0.3.13.dev3 → polyapi_python-0.3.14}/tests/test_variables.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyapi-python
3
- Version: 0.3.13.dev3
3
+ Version: 0.3.14
4
4
  Summary: The Python Client for PolyAPI, the IPaaS by Developers for Developers
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -30,12 +30,13 @@ Description-Content-Type: text/markdown
30
30
  License-File: LICENSE
31
31
  Requires-Dist: requests>=2.32.3
32
32
  Requires-Dist: typing_extensions>=4.12.2
33
- Requires-Dist: jsonschema-gentypes==2.6.0
34
- Requires-Dist: pydantic>=2.8.0
35
- Requires-Dist: stdlib_list>=0.10.0
33
+ Requires-Dist: jsonschema-gentypes==2.10.0
34
+ Requires-Dist: pydantic<3.0.0,>=2.8.0
35
+ Requires-Dist: stdlib_list<1.0.0,>=0.10.0
36
36
  Requires-Dist: colorama==0.4.4
37
37
  Requires-Dist: python-socketio[asyncio_client]==5.11.1
38
38
  Requires-Dist: truststore>=0.8.0
39
+ Requires-Dist: httpx>=0.28.1
39
40
  Dynamic: license-file
40
41
 
41
42
  # PolyAPI Python Library
@@ -185,6 +186,14 @@ This script is handy for checking for any mypy types:
185
186
 
186
187
  Please ignore \[name-defined\] errors for now. This is a known bug we are working to fix!
187
188
 
189
+ ## Strategies for QA'ing Changes To Generate Or Other Core Functionality
190
+
191
+ Our https://na1.polyapi.io has a large OOB catalog (as does eu1/na2). We also have several big internal PolyAPI projects with Python (message @eupharis if you need a pointer to which ones).
192
+
193
+ Running `python -m polyapi generate` in all these projects and then checking the flake8 and check_mypy steps above is a great way to build confidence that the `generate` changes has no gotchas.
194
+
195
+ Of course all this is in addition to the changes passing through normal unittests and integration tests!
196
+
188
197
  ## Support
189
198
 
190
199
  If you run into any issues or want help getting started with this project, please contact support@polyapi.io
@@ -145,6 +145,14 @@ This script is handy for checking for any mypy types:
145
145
 
146
146
  Please ignore \[name-defined\] errors for now. This is a known bug we are working to fix!
147
147
 
148
+ ## Strategies for QA'ing Changes To Generate Or Other Core Functionality
149
+
150
+ Our https://na1.polyapi.io has a large OOB catalog (as does eu1/na2). We also have several big internal PolyAPI projects with Python (message @eupharis if you need a pointer to which ones).
151
+
152
+ Running `python -m polyapi generate` in all these projects and then checking the flake8 and check_mypy steps above is a great way to build confidence that the `generate` changes has no gotchas.
153
+
154
+ Of course all this is in addition to the changes passing through normal unittests and integration tests!
155
+
148
156
  ## Support
149
157
 
150
158
  If you run into any issues or want help getting started with this project, please contact support@polyapi.io
@@ -0,0 +1,163 @@
1
+ import copy
2
+ import os
3
+ import sys
4
+ from contextvars import ContextVar, Token
5
+ from dataclasses import dataclass
6
+ from typing import Any, Dict, Literal, Optional, overload
7
+
8
+ import truststore
9
+ from typing_extensions import TypedDict
10
+
11
+ from .cli_constants import CLI_COMMANDS
12
+
13
+ truststore.inject_into_ssl()
14
+
15
+ __all__ = ["poly"]
16
+
17
+
18
+ if len(sys.argv) > 1 and sys.argv[1] not in CLI_COMMANDS:
19
+ currdir = os.path.dirname(os.path.abspath(__file__))
20
+ if not os.path.isdir(os.path.join(currdir, "poly")):
21
+ print("No 'poly' found. Please run 'python3 -m polyapi generate' to generate the 'poly' library for your tenant.")
22
+ sys.exit(1)
23
+
24
+
25
+ class PolyCustomDict(TypedDict, total=False):
26
+ """Type definition for polyCustom dictionary."""
27
+
28
+ executionId: Optional[str] # Read-only unless explicitly unlocked
29
+ executionApiKey: Optional[str]
30
+ userSessionId: Optional[str]
31
+ responseStatusCode: Optional[int]
32
+ responseContentType: Optional[str]
33
+ responseHeaders: Dict[str, Any]
34
+
35
+
36
+ @dataclass
37
+ class _PolyCustomState:
38
+ internal_store: Dict[str, Any]
39
+ execution_id_locked: bool = False
40
+
41
+
42
+ class PolyCustom:
43
+ def __init__(self) -> None:
44
+ object.__setattr__(
45
+ self,
46
+ "_default_store",
47
+ {
48
+ "executionId": None,
49
+ "executionApiKey": None,
50
+ "userSessionId": None,
51
+ "responseStatusCode": 200,
52
+ "responseContentType": None,
53
+ "responseHeaders": {},
54
+ },
55
+ )
56
+ object.__setattr__(self, "_state_var", ContextVar("_poly_custom_state", default=None))
57
+
58
+ def _make_state(self) -> _PolyCustomState:
59
+ return _PolyCustomState(internal_store=copy.deepcopy(self._default_store))
60
+
61
+ def _get_state(self) -> _PolyCustomState:
62
+ state = self._state_var.get()
63
+ if state is None:
64
+ state = self._make_state()
65
+ self._state_var.set(state)
66
+ return state
67
+
68
+ def push_scope(self, initial_values: Optional[Dict[str, Any]] = None) -> Token:
69
+ state = self._make_state()
70
+ if initial_values:
71
+ state.internal_store.update(copy.deepcopy(initial_values))
72
+ if state.internal_store.get("executionId") is not None:
73
+ state.execution_id_locked = True
74
+ return self._state_var.set(state)
75
+
76
+ def pop_scope(self, token: Token) -> None:
77
+ self._state_var.reset(token)
78
+
79
+ def set_once(self, key: str, value: Any) -> None:
80
+ state = self._get_state()
81
+ if key == "executionId" and state.execution_id_locked:
82
+ return
83
+ state.internal_store[key] = value
84
+ if key == "executionId":
85
+ state.execution_id_locked = True
86
+
87
+ def get(self, key: str, default: Any = None) -> Any:
88
+ return self._get_state().internal_store.get(key, default)
89
+
90
+ def lock_execution_id(self) -> None:
91
+ self._get_state().execution_id_locked = True
92
+
93
+ def unlock_execution_id(self) -> None:
94
+ self._get_state().execution_id_locked = False
95
+
96
+ @overload
97
+ def __getitem__(self, key: Literal["executionId"]) -> Optional[str]: ...
98
+
99
+ @overload
100
+ def __getitem__(self, key: Literal["executionApiKey"]) -> Optional[str]: ...
101
+
102
+ @overload
103
+ def __getitem__(self, key: Literal["userSessionId"]) -> Optional[str]: ...
104
+
105
+ @overload
106
+ def __getitem__(self, key: Literal["responseStatusCode"]) -> Optional[int]: ...
107
+
108
+ @overload
109
+ def __getitem__(self, key: Literal["responseContentType"]) -> Optional[str]: ...
110
+
111
+ @overload
112
+ def __getitem__(self, key: Literal["responseHeaders"]) -> Dict[str, Any]: ...
113
+
114
+ def __getitem__(self, key: str) -> Any:
115
+ return self.get(key)
116
+
117
+ @overload
118
+ def __setitem__(self, key: Literal["executionApiKey"], value: Optional[str]) -> None: ...
119
+
120
+ @overload
121
+ def __setitem__(self, key: Literal["userSessionId"], value: Optional[str]) -> None: ...
122
+
123
+ @overload
124
+ def __setitem__(self, key: Literal["responseStatusCode"], value: Optional[int]) -> None: ...
125
+
126
+ @overload
127
+ def __setitem__(self, key: Literal["responseContentType"], value: Optional[str]) -> None: ...
128
+
129
+ @overload
130
+ def __setitem__(self, key: Literal["responseHeaders"], value: Dict[str, Any]) -> None: ...
131
+
132
+ def __setitem__(self, key: str, value: Any) -> None:
133
+ self.set_once(key, value)
134
+
135
+ def __getattr__(self, key: str) -> Any:
136
+ if key in self._default_store:
137
+ return self.get(key)
138
+ raise AttributeError(f"{type(self).__name__!r} object has no attribute {key!r}")
139
+
140
+ def __setattr__(self, key: str, value: Any) -> None:
141
+ if key.startswith("_"):
142
+ object.__setattr__(self, key, value)
143
+ return
144
+ self.set_once(key, value)
145
+
146
+ def __repr__(self) -> str:
147
+ return f"PolyCustom({self._get_state().internal_store})"
148
+
149
+ def copy(self) -> "PolyCustom":
150
+ new = PolyCustom()
151
+ state = self._get_state()
152
+ new._state_var.set(
153
+ _PolyCustomState(
154
+ internal_store=copy.deepcopy(state.internal_store),
155
+ execution_id_locked=state.execution_id_locked,
156
+ )
157
+ )
158
+ return new
159
+
160
+
161
+ _PolyCustom = PolyCustom
162
+
163
+ polyCustom: PolyCustom = PolyCustom()
@@ -35,6 +35,25 @@ def {function_name}(
35
35
  return {api_response_type}(resp.json()) # type: ignore
36
36
 
37
37
 
38
+ async def {function_name}_async(
39
+ {args}
40
+ ) -> {api_response_type}:
41
+ \"""{function_description}
42
+
43
+ Function ID: {function_id}
44
+ \"""
45
+ if get_direct_execute_config():
46
+ resp = await direct_execute_async("{function_type}", "{function_id}", {data})
47
+ return {api_response_type}({{
48
+ "status": resp.status_code,
49
+ "headers": dict(resp.headers),
50
+ "data": resp.json()
51
+ }}) # type: ignore
52
+ else:
53
+ resp = await execute_async("{function_type}", "{function_id}", {data})
54
+ return {api_response_type}(resp.json()) # type: ignore
55
+
56
+
38
57
  """
39
58
 
40
59
 
@@ -117,6 +117,16 @@ def introspectToken(token: str) -> AuthFunctionResponse:
117
117
  url = "/auth-providers/{function_id}/introspect"
118
118
  resp = execute_post(url, {{"token": token}})
119
119
  return resp.json()
120
+
121
+
122
+ async def introspectToken_async(token: str) -> AuthFunctionResponse:
123
+ \"""{description}
124
+
125
+ Function ID: {function_id}
126
+ \"""
127
+ url = "/auth-providers/{function_id}/introspect"
128
+ resp = await execute_post_async(url, {{"token": token}})
129
+ return resp.json()
120
130
  """
121
131
 
122
132
  REFRESH_TOKEN_TEMPLATE = """
@@ -128,6 +138,16 @@ def refreshToken(token: str) -> AuthFunctionResponse:
128
138
  url = "/auth-providers/{function_id}/refresh"
129
139
  resp = execute_post(url, {{"token": token}})
130
140
  return resp.json()
141
+
142
+
143
+ async def refreshToken_async(token: str) -> AuthFunctionResponse:
144
+ \"""{description}
145
+
146
+ Function ID: {function_id}
147
+ \"""
148
+ url = "/auth-providers/{function_id}/refresh"
149
+ resp = await execute_post_async(url, {{"token": token}})
150
+ return resp.json()
131
151
  """
132
152
 
133
153
  REVOKE_TOKEN_TEMPLATE = """
@@ -142,6 +162,19 @@ def revokeToken(token: str) -> Optional[AuthFunctionResponse]:
142
162
  return resp.json()
143
163
  except:
144
164
  return None
165
+
166
+
167
+ async def revokeToken_async(token: str) -> Optional[AuthFunctionResponse]:
168
+ \"""{description}
169
+
170
+ Function ID: {function_id}
171
+ \"""
172
+ url = "/auth-providers/{function_id}/revoke"
173
+ resp = await execute_post_async(url, {{"token": token}})
174
+ try:
175
+ return resp.json()
176
+ except:
177
+ return None
145
178
  """
146
179
 
147
180
 
@@ -3,6 +3,7 @@ import argparse
3
3
 
4
4
  from polyapi.utils import print_green, print_red
5
5
 
6
+ from .cli_constants import CLI_COMMANDS
6
7
  from .config import initialize_config, set_api_key_and_url
7
8
  from .generate import generate, clear
8
9
  from .function_cli import function_add_or_update, function_execute
@@ -11,9 +12,6 @@ from .prepare import prepare_deployables
11
12
  from .sync import sync_deployables
12
13
 
13
14
 
14
- CLI_COMMANDS = ["setup", "generate", "function", "clear", "help", "update_rendered_spec"]
15
-
16
-
17
15
  def _get_version_string():
18
16
  """Get the version string for the package."""
19
17
  try:
@@ -0,0 +1,10 @@
1
+ CLI_COMMANDS = (
2
+ "setup",
3
+ "generate",
4
+ "function",
5
+ "clear",
6
+ "help",
7
+ "update_rendered_spec",
8
+ "prepare",
9
+ "sync",
10
+ )
@@ -3,8 +3,8 @@ JSONSCHEMA_TO_PYTHON_TYPE_MAP = {
3
3
  "number": "float",
4
4
  "string": "str",
5
5
  "boolean": "bool",
6
- "array": "List",
7
- "object": "Dict",
6
+ "array": "list",
7
+ "object": "dict",
8
8
  "function": "Callable",
9
9
  "void": "None",
10
10
  }
@@ -15,10 +15,13 @@ PYTHON_TO_JSONSCHEMA_TYPE_MAP = {
15
15
  "float": "number",
16
16
  "str": "string",
17
17
  "bool": "boolean",
18
- "List": "array",
19
- "Dict": "object",
18
+ "list": "array",
19
+ "dict": "object",
20
20
  "Callable": "function",
21
21
  "None": "void",
22
+ # Keep uppercase aliases for backwards compatibility
23
+ "List": "array",
24
+ "Dict": "object",
22
25
  }
23
26
 
24
27
  BASIC_PYTHON_TYPES = set(PYTHON_TO_JSONSCHEMA_TYPE_MAP.keys())
@@ -0,0 +1,224 @@
1
+ import httpx
2
+ import os
3
+ import logging
4
+ from polyapi.config import get_api_key_and_url, get_mtls_config
5
+ from polyapi.exceptions import PolyApiException
6
+ from polyapi import http_client
7
+
8
+ logger = logging.getLogger("poly")
9
+
10
+ def _check_response_error(resp, function_type, function_id, data):
11
+ if resp.status_code < 200 or resp.status_code >= 300:
12
+ error_content = resp.content.decode("utf-8", errors="ignore")
13
+ if function_type == 'api' and os.getenv("LOGS_ENABLED"):
14
+ logger.error(f"Error executing api function with id: {function_id}. Status code: {resp.status_code}. Request data: {data}, Response: {error_content}")
15
+ elif function_type != 'api':
16
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
17
+
18
+
19
+ def _check_endpoint_error(resp, function_type, function_id, data):
20
+ if resp.status_code < 200 or resp.status_code >= 300:
21
+ error_content = resp.content.decode("utf-8", errors="ignore")
22
+ if function_type == 'api' and os.getenv("LOGS_ENABLED"):
23
+ raise PolyApiException(f"Error executing api function with id: {function_id}. Status code: {resp.status_code}. Request data: {data}, Response: {error_content}")
24
+ elif function_type != 'api':
25
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
26
+
27
+
28
+ def _build_direct_execute_params(endpoint_info_data):
29
+ request_params = endpoint_info_data.copy()
30
+ request_params.pop("url", None)
31
+ if "maxRedirects" in request_params:
32
+ request_params["follow_redirects"] = request_params.pop("maxRedirects") > 0
33
+ return request_params
34
+
35
+
36
+ def _sync_direct_execute(function_type, function_id, data) -> httpx.Response:
37
+ api_key, api_url = get_api_key_and_url()
38
+ headers = {"Authorization": f"Bearer {api_key}"}
39
+ url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
40
+
41
+ endpoint_info = http_client.post(url, json=data, headers=headers)
42
+ _check_endpoint_error(endpoint_info, function_type, function_id, data)
43
+
44
+ endpoint_info_data = endpoint_info.json()
45
+ request_params = _build_direct_execute_params(endpoint_info_data)
46
+
47
+ has_mtls, cert_path, key_path, ca_path = get_mtls_config()
48
+
49
+ # Direct-execute hits URL that may need custom TLS
50
+ # settings (mTLS certs or disabled verification). httpx Client.request()
51
+ # doesn't accept per-request transport kwargs, so use one-off calls.
52
+ if has_mtls:
53
+ resp = httpx.request(
54
+ url=endpoint_info_data["url"],
55
+ cert=(cert_path, key_path),
56
+ verify=ca_path,
57
+ timeout=None,
58
+ **request_params
59
+ )
60
+ else:
61
+ resp = httpx.request(
62
+ url=endpoint_info_data["url"],
63
+ verify=False,
64
+ timeout=None,
65
+ **request_params
66
+ )
67
+
68
+ _check_response_error(resp, function_type, function_id, data)
69
+ return resp
70
+
71
+
72
+ async def _async_direct_execute(function_type, function_id, data) -> httpx.Response:
73
+ api_key, api_url = get_api_key_and_url()
74
+ headers = {"Authorization": f"Bearer {api_key}"}
75
+ url = f"{api_url}/functions/{function_type}/{function_id}/direct-execute"
76
+
77
+ endpoint_info = await http_client.async_post(url, json=data, headers=headers)
78
+ _check_endpoint_error(endpoint_info, function_type, function_id, data)
79
+
80
+ endpoint_info_data = endpoint_info.json()
81
+ request_params = _build_direct_execute_params(endpoint_info_data)
82
+
83
+ has_mtls, cert_path, key_path, ca_path = get_mtls_config()
84
+
85
+ # One-off async client for custom TLS settings on external URLs.
86
+ if has_mtls:
87
+ async with httpx.AsyncClient(
88
+ cert=(cert_path, key_path), verify=ca_path, timeout=None
89
+ ) as client:
90
+ resp = await client.request(
91
+ url=endpoint_info_data["url"], **request_params
92
+ )
93
+ else:
94
+ async with httpx.AsyncClient(verify=False, timeout=None) as client:
95
+ resp = await client.request(
96
+ url=endpoint_info_data["url"], **request_params
97
+ )
98
+
99
+ _check_response_error(resp, function_type, function_id, data)
100
+ return resp
101
+
102
+
103
+ def direct_execute(function_type, function_id, data) -> httpx.Response:
104
+ """ execute a specific function id/type (sync)
105
+ """
106
+ return _sync_direct_execute(function_type, function_id, data)
107
+
108
+
109
+ async def direct_execute_async(function_type, function_id, data) -> httpx.Response:
110
+ """ execute a specific function id/type (async)
111
+ """
112
+ return await _async_direct_execute(function_type, function_id, data)
113
+
114
+
115
+ def _sync_execute(function_type, function_id, data) -> httpx.Response:
116
+ api_key, api_url = get_api_key_and_url()
117
+ headers = {"Authorization": f"Bearer {api_key}"}
118
+ url = f"{api_url}/functions/{function_type}/{function_id}/execute"
119
+
120
+ resp = http_client.post(url, json=data, headers=headers)
121
+ _check_response_error(resp, function_type, function_id, data)
122
+ return resp
123
+
124
+
125
+ async def _async_execute(function_type, function_id, data) -> httpx.Response:
126
+ api_key, api_url = get_api_key_and_url()
127
+ headers = {"Authorization": f"Bearer {api_key}"}
128
+ url = f"{api_url}/functions/{function_type}/{function_id}/execute"
129
+
130
+ resp = await http_client.async_post(url, json=data, headers=headers)
131
+ _check_response_error(resp, function_type, function_id, data)
132
+ return resp
133
+
134
+
135
+ def execute(function_type, function_id, data) -> httpx.Response:
136
+ """ execute a specific function id/type (sync)
137
+ """
138
+ return _sync_execute(function_type, function_id, data)
139
+
140
+
141
+ async def execute_async(function_type, function_id, data) -> httpx.Response:
142
+ """ execute a specific function id/type (async)
143
+ """
144
+ return await _async_execute(function_type, function_id, data)
145
+
146
+
147
+ def _sync_execute_post(path, data):
148
+ api_key, api_url = get_api_key_and_url()
149
+ headers = {"Authorization": f"Bearer {api_key}"}
150
+ return http_client.post(api_url + path, json=data, headers=headers)
151
+
152
+
153
+ async def _async_execute_post(path, data):
154
+ api_key, api_url = get_api_key_and_url()
155
+ headers = {"Authorization": f"Bearer {api_key}"}
156
+ return await http_client.async_post(api_url + path, json=data, headers=headers)
157
+
158
+
159
+ def execute_post(path, data):
160
+ return _sync_execute_post(path, data)
161
+
162
+
163
+ async def execute_post_async(path, data):
164
+ return await _async_execute_post(path, data)
165
+
166
+
167
+ def _sync_variable_get(variable_id: str) -> httpx.Response:
168
+ api_key, base_url = get_api_key_and_url()
169
+ headers = {"Authorization": f"Bearer {api_key}"}
170
+ url = f"{base_url}/variables/{variable_id}/value"
171
+ resp = http_client.get(url, headers=headers)
172
+ if resp.status_code != 200 and resp.status_code != 201:
173
+ error_content = resp.content.decode("utf-8", errors="ignore")
174
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
175
+ return resp
176
+
177
+
178
+ async def _async_variable_get(variable_id: str) -> httpx.Response:
179
+ api_key, base_url = get_api_key_and_url()
180
+ headers = {"Authorization": f"Bearer {api_key}"}
181
+ url = f"{base_url}/variables/{variable_id}/value"
182
+ resp = await http_client.async_get(url, headers=headers)
183
+ if resp.status_code != 200 and resp.status_code != 201:
184
+ error_content = resp.content.decode("utf-8", errors="ignore")
185
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
186
+ return resp
187
+
188
+
189
+ def variable_get(variable_id: str) -> httpx.Response:
190
+ return _sync_variable_get(variable_id)
191
+
192
+
193
+ async def variable_get_async(variable_id: str) -> httpx.Response:
194
+ return await _async_variable_get(variable_id)
195
+
196
+
197
+ def _sync_variable_update(variable_id: str, value) -> httpx.Response:
198
+ api_key, base_url = get_api_key_and_url()
199
+ headers = {"Authorization": f"Bearer {api_key}"}
200
+ url = f"{base_url}/variables/{variable_id}"
201
+ resp = http_client.patch(url, data={"value": value}, headers=headers)
202
+ if resp.status_code != 200 and resp.status_code != 201:
203
+ error_content = resp.content.decode("utf-8", errors="ignore")
204
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
205
+ return resp
206
+
207
+
208
+ async def _async_variable_update(variable_id: str, value) -> httpx.Response:
209
+ api_key, base_url = get_api_key_and_url()
210
+ headers = {"Authorization": f"Bearer {api_key}"}
211
+ url = f"{base_url}/variables/{variable_id}"
212
+ resp = await http_client.async_patch(url, data={"value": value}, headers=headers)
213
+ if resp.status_code != 200 and resp.status_code != 201:
214
+ error_content = resp.content.decode("utf-8", errors="ignore")
215
+ raise PolyApiException(f"{resp.status_code}: {error_content}")
216
+ return resp
217
+
218
+
219
+ def variable_update(variable_id: str, value) -> httpx.Response:
220
+ return _sync_variable_update(variable_id, value)
221
+
222
+
223
+ async def variable_update_async(variable_id: str, value) -> httpx.Response:
224
+ return await _async_variable_update(variable_id, value)
@@ -1,7 +1,6 @@
1
1
  import sys
2
2
  from typing import Any, List, Optional
3
- import requests
4
-
3
+ from polyapi import http_client
5
4
  from polyapi.config import get_api_key_and_url
6
5
  from polyapi.utils import get_auth_headers, print_green, print_red, print_yellow
7
6
  from polyapi.parser import parse_function_code, get_jsonschema_type
@@ -87,7 +86,7 @@ def function_add_or_update(
87
86
  sys.exit(1)
88
87
 
89
88
  headers = get_auth_headers(api_key)
90
- resp = requests.post(url, headers=headers, json=data)
89
+ resp = http_client.post(url, headers=headers, json=data)
91
90
  if resp.status_code in [200, 201]:
92
91
  print_green("DEPLOYED")
93
92
  function_id = resp.json()["id"]
@@ -126,5 +125,5 @@ def spec_delete(function_type: str, function_id: str):
126
125
  print(f"Unknown function type: {function_type}")
127
126
  sys.exit(1)
128
127
  headers = get_auth_headers(api_key)
129
- resp = requests.delete(url, headers=headers)
128
+ resp = http_client.delete(url, headers=headers)
130
129
  return resp
@@ -1,5 +1,4 @@
1
1
  import json
2
- import requests
3
2
  import os
4
3
  import uuid
5
4
  import shutil
@@ -20,6 +19,7 @@ from .server import render_server_function
20
19
  from .utils import add_import_to_init, get_auth_headers, init_the_init, print_green, to_func_namespace
21
20
  from .variables import generate_variables
22
21
  from .poly_tables import generate_tables
22
+ from . import http_client
23
23
  from .config import get_api_key_and_url, get_direct_execute_config, get_cached_generate_args
24
24
 
25
25
  SUPPORTED_FUNCTION_TYPES = {
@@ -62,7 +62,7 @@ def get_specs(contexts: Optional[List[str]] = None, names: Optional[List[str]] =
62
62
  if get_direct_execute_config():
63
63
  params["apiFunctionDirectExecute"] = "true"
64
64
 
65
- resp = requests.get(url, headers=headers, params=params)
65
+ resp = http_client.get(url, headers=headers, params=params)
66
66
  if resp.status_code == 200:
67
67
  return resp.json()
68
68
  else: