polyapi-python 0.1.0.dev14__tar.gz → 0.1.1__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 (34) hide show
  1. {polyapi-python-0.1.0.dev14/polyapi_python.egg-info → polyapi-python-0.1.1}/PKG-INFO +3 -1
  2. polyapi-python-0.1.1/polyapi/auth.py +153 -0
  3. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/generate.py +3 -0
  4. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/utils.py +1 -1
  5. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1/polyapi_python.egg-info}/PKG-INFO +3 -1
  6. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi_python.egg-info/requires.txt +2 -0
  7. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/pyproject.toml +2 -2
  8. polyapi-python-0.1.0.dev14/polyapi/auth.py +0 -80
  9. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/LICENSE +0 -0
  10. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/README.md +0 -0
  11. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/__init__.py +0 -0
  12. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/__main__.py +0 -0
  13. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/api.py +0 -0
  14. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/cli.py +0 -0
  15. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/config.py +0 -0
  16. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/constants.py +0 -0
  17. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/exceptions.py +0 -0
  18. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/execute.py +0 -0
  19. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/function_cli.py +0 -0
  20. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/py.typed +0 -0
  21. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/schema.py +0 -0
  22. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/server.py +0 -0
  23. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/typedefs.py +0 -0
  24. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi/variables.py +0 -0
  25. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi_python.egg-info/SOURCES.txt +0 -0
  26. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi_python.egg-info/dependency_links.txt +0 -0
  27. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/polyapi_python.egg-info/top_level.txt +0 -0
  28. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/setup.cfg +0 -0
  29. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_api.py +0 -0
  30. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_auth.py +0 -0
  31. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_function_cli.py +0 -0
  32. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_server.py +0 -0
  33. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_utils.py +0 -0
  34. {polyapi-python-0.1.0.dev14 → polyapi-python-0.1.1}/tests/test_variables.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polyapi-python
3
- Version: 0.1.0.dev14
3
+ Version: 0.1.1
4
4
  Summary: The PolyAPI Python Client
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -34,6 +34,8 @@ Requires-Dist: jsonschema-gentypes
34
34
  Requires-Dist: pydantic>=2.5.3
35
35
  Requires-Dist: stdlib_list
36
36
  Requires-Dist: colorama
37
+ Requires-Dist: python-socketio[asyncio_client]
38
+ Requires-Dist: truststore
37
39
 
38
40
  # PolyAPI Python Library
39
41
 
@@ -0,0 +1,153 @@
1
+ from typing import List, Dict, Any, Tuple
2
+ import uuid
3
+
4
+ from polyapi.typedefs import PropertySpecification
5
+ from polyapi.utils import parse_arguments, get_type_and_def
6
+
7
+
8
+ AUTH_DEFS_TEMPLATE = """
9
+ from typing import List, Dict, Any, TypedDict, Optional
10
+ {args_def}
11
+ {return_type_def}
12
+ """
13
+
14
+ GET_TOKEN_TEMPLATE = """
15
+ import asyncio
16
+ import socketio # type: ignore
17
+ import truststore
18
+ truststore.inject_into_ssl()
19
+ from polyapi.config import get_api_key_and_url
20
+
21
+
22
+ async def getToken(clientId: str, clientSecret: str, scopes: List[str], callback, options: Optional[Dict[str, Any]] = None):
23
+ {description}
24
+ eventsClientId = "{client_id}"
25
+ function_id = "{function_id}"
26
+
27
+ options = options or {{}}
28
+ path = "/auth-providers/{function_id}/execute"
29
+ data = {{
30
+ "clientId": clientId,
31
+ "clientSecret": clientSecret,
32
+ "scopes": scopes,
33
+ "audience": options.get("audience"),
34
+ "callbackUrl": options.get("callbackUrl"),
35
+ "userId": options.get("userId"),
36
+ }}
37
+ resp = execute_post(path, data)
38
+ data = resp.json()
39
+ assert resp.status_code == 201, (resp.status_code, resp.content)
40
+
41
+ token = data.get("token")
42
+ url = data.get("url")
43
+ error = data.get("error")
44
+ if token:
45
+ return callback(token, url, error)
46
+ elif url and options.get("autoCloseOnUrl"):
47
+ return callback(token, url, error)
48
+
49
+ timeout = options.get("timeout", 120)
50
+
51
+ api_key, base_url = get_api_key_and_url()
52
+ socket = socketio.AsyncClient()
53
+ await socket.connect(base_url, transports=['websocket'], namespaces=['/events'])
54
+
55
+ async def closeEventHandler():
56
+ nonlocal socket
57
+ if not socket:
58
+ return
59
+
60
+ del socket.handlers['/events']['handleAuthFunctionEvent:{function_id}']
61
+ await socket.emit('unregisterAuthFunctionEventHandler', {{
62
+ "clientID": eventsClientId,
63
+ "functionId": function_id,
64
+ "apiKey": api_key
65
+ }}, namespace="/events")
66
+ await socket.disconnect()
67
+ socket = None
68
+
69
+
70
+ async def waitUntilTimeout(timeout):
71
+ await asyncio.sleep(timeout)
72
+ await closeEventHandler()
73
+
74
+
75
+ async def handleEvent(data):
76
+ nonlocal options
77
+ callback(data.get('token'), data.get('url'), data.get('error'))
78
+ if data.get('token') and options.get("autoCloseOnToken", True):
79
+ await closeEventHandler()
80
+
81
+
82
+ def registerCallback(registered: bool):
83
+ nonlocal socket
84
+ if registered:
85
+ socket.on('handleAuthFunctionEvent:{function_id}', handleEvent, namespace="/events")
86
+ callback(data.get('token'), data.get('url'), data.get('error'))
87
+
88
+ data2 = {{
89
+ "clientID": eventsClientId,
90
+ "functionId": function_id,
91
+ "apiKey": api_key
92
+ }}
93
+ await socket.emit('registerAuthFunctionEventHandler', data2, namespace="/events", callback=registerCallback)
94
+
95
+ # run timeout task in background
96
+ timeout = options.get("timeout", 120)
97
+ timeout_task = asyncio.create_task(waitUntilTimeout(timeout))
98
+
99
+ # cancel timeout task if socket.wait finishes before timeout up
100
+ await socket.wait()
101
+ timeout_task.cancel()
102
+
103
+ return {{"close": closeEventHandler}}
104
+ """
105
+
106
+ REFRESH_TOKEN_TEMPLATE = """
107
+ def refreshToken(token: str) -> str:
108
+ {description}
109
+ url = "/auth-providers/{function_id}/refresh"
110
+ resp = execute_post(url, {{"token": token}})
111
+ assert resp.status_code == 201, (resp.status_code, resp.content)
112
+ return resp.text
113
+ """
114
+
115
+ REVOKE_TOKEN_TEMPLATE = """
116
+ def revokeToken(token: str) -> None:
117
+ {description}
118
+ url = "/auth-providers/{function_id}/revoke"
119
+ resp = execute_post(url, {{"token": token}})
120
+ assert resp.status_code == 201, (resp.status_code, resp.content)
121
+ """
122
+
123
+
124
+ def render_auth_function(
125
+ function_type: str,
126
+ function_name: str,
127
+ function_id: str,
128
+ function_description: str,
129
+ arguments: List[PropertySpecification],
130
+ return_type: Dict[str, Any],
131
+ ) -> Tuple[str, str]:
132
+ """ renders getToken, revokeToken, refreshToken as appropriate
133
+ """
134
+ args, args_def = parse_arguments(function_name, arguments)
135
+ return_type_name, return_type_def = get_type_and_def(return_type) # type: ignore
136
+ func_type_defs = AUTH_DEFS_TEMPLATE.format(
137
+ args_def=args_def,
138
+ return_type_def=return_type_def,
139
+ )
140
+
141
+ func_str = ""
142
+
143
+ if function_description:
144
+ function_description = f'"""{function_description}"""'
145
+
146
+ if function_name == "getToken":
147
+ func_str = GET_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description, client_id=uuid.uuid4().hex)
148
+ elif function_name == "refreshToken":
149
+ func_str = REFRESH_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description)
150
+ elif function_name == "revokeToken":
151
+ func_str = REVOKE_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description)
152
+
153
+ return func_str, func_type_defs
@@ -235,6 +235,9 @@ def create_function(
235
235
  add_import_to_init(full_path, next)
236
236
 
237
237
 
238
+ # TODO create the socket and pass to create_function?
239
+
240
+
238
241
  def generate_functions(functions: List) -> None:
239
242
  for func in functions:
240
243
  create_function(*func)
@@ -9,7 +9,7 @@ from polyapi.schema import generate_schema_types, clean_title, map_primitive_typ
9
9
 
10
10
  # this string should be in every __init__ file.
11
11
  # it contains all the imports needed for the function or variable code to run
12
- CODE_IMPORTS = "from typing import List, Dict, Any, TypedDict\nimport requests\nfrom polyapi.execute import execute, execute_post, variable_get, variable_update\n\n"
12
+ CODE_IMPORTS = "from typing import List, Dict, Any, TypedDict, Optional\nimport requests\nfrom polyapi.execute import execute, execute_post, variable_get, variable_update\n\n"
13
13
 
14
14
 
15
15
  def init_the_init(full_path: str) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: polyapi-python
3
- Version: 0.1.0.dev14
3
+ Version: 0.1.1
4
4
  Summary: The PolyAPI Python Client
5
5
  Author-email: Dan Fellin <dan@polyapi.io>
6
6
  License: MIT License
@@ -34,6 +34,8 @@ Requires-Dist: jsonschema-gentypes
34
34
  Requires-Dist: pydantic>=2.5.3
35
35
  Requires-Dist: stdlib_list
36
36
  Requires-Dist: colorama
37
+ Requires-Dist: python-socketio[asyncio_client]
38
+ Requires-Dist: truststore
37
39
 
38
40
  # PolyAPI Python Library
39
41
 
@@ -4,3 +4,5 @@ jsonschema-gentypes
4
4
  pydantic>=2.5.3
5
5
  stdlib_list
6
6
  colorama
7
+ python-socketio[asyncio_client]
8
+ truststore
@@ -3,10 +3,10 @@ requires = ["setuptools>=61.2", "wheel"]
3
3
 
4
4
  [project]
5
5
  name = "polyapi-python"
6
- version = "0.1.0.dev14"
6
+ version = "0.1.1"
7
7
  description = "The PolyAPI Python Client"
8
8
  authors = [{ name = "Dan Fellin", email = "dan@polyapi.io" }]
9
- dependencies = ["requests", "typing_extensions", "jsonschema-gentypes", "pydantic>=2.5.3", "stdlib_list", "colorama"]
9
+ dependencies = ["requests", "typing_extensions", "jsonschema-gentypes", "pydantic>=2.5.3", "stdlib_list", "colorama", "python-socketio[asyncio_client]", "truststore"]
10
10
  readme = "README.md"
11
11
  license = { file = "LICENSE" }
12
12
  requires-python = ">=3.10"
@@ -1,80 +0,0 @@
1
- from typing import List, Dict, Any, Tuple
2
-
3
- from polyapi.typedefs import PropertySpecification
4
- from polyapi.utils import parse_arguments, get_type_and_def
5
-
6
-
7
- AUTH_DEFS_TEMPLATE = """
8
- from typing import List, Dict, Any, TypedDict
9
- {args_def}
10
- {return_type_def}
11
- """
12
-
13
- GET_TOKEN_TEMPLATE = """
14
- def getToken(clientId: str, clientSecret: str, scopes: List[str], callback, options: Dict[str, Any] = None):
15
- {description}
16
- # TODO timeout, autoCloseOnUrl, autoCloseOnToken
17
- options = options or {{}}
18
- url = "/auth-providers/{function_id}/execute"
19
- data = {{
20
- "clientId": clientId,
21
- "clientSecret": clientSecret,
22
- "scopes": scopes,
23
- "audience": options.get("audience"),
24
- "callbackUrl": options.get("callbackUrl"),
25
- "userId": options.get("userId"),
26
- }}
27
- resp = execute_post(url, data)
28
- data = resp.json()
29
- assert resp.status_code == 201, (resp.status_code, resp.content)
30
- return callback(data.get("token"), data.get("url"), data.get("error"))
31
- """
32
-
33
- REFRESH_TOKEN_TEMPLATE = """
34
- def refreshToken(token: str) -> str:
35
- {description}
36
- url = "/auth-providers/{function_id}/refresh"
37
- resp = execute_post(url, {{"token": token}})
38
- assert resp.status_code == 201, (resp.status_code, resp.content)
39
- return resp.text
40
- """
41
-
42
- REVOKE_TOKEN_TEMPLATE = """
43
- def revokeToken(token: str) -> None:
44
- {description}
45
- url = "/auth-providers/{function_id}/revoke"
46
- resp = execute_post(url, {{"token": token}})
47
- assert resp.status_code == 201, (resp.status_code, resp.content)
48
- """
49
-
50
-
51
- def render_auth_function(
52
- function_type: str,
53
- function_name: str,
54
- function_id: str,
55
- function_description: str,
56
- arguments: List[PropertySpecification],
57
- return_type: Dict[str, Any],
58
- ) -> Tuple[str, str]:
59
- """ renders getToken, revokeToken, refreshToken as appropriate
60
- """
61
- args, args_def = parse_arguments(function_name, arguments)
62
- return_type_name, return_type_def = get_type_and_def(return_type) # type: ignore
63
- func_type_defs = AUTH_DEFS_TEMPLATE.format(
64
- args_def=args_def,
65
- return_type_def=return_type_def,
66
- )
67
-
68
- func_str = ""
69
-
70
- if function_description:
71
- function_description = f'"""{function_description}"""'
72
-
73
- if function_name == "getToken":
74
- func_str = GET_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description)
75
- elif function_name == "refreshToken":
76
- func_str = REFRESH_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description)
77
- elif function_name == "revokeToken":
78
- func_str = REVOKE_TOKEN_TEMPLATE.format(function_id=function_id, description=function_description)
79
-
80
- return func_str, func_type_defs