vortex-python-sdk 0.0.5__tar.gz → 0.0.6__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.
- {vortex_python_sdk-0.0.5/src/vortex_python_sdk.egg-info → vortex_python_sdk-0.0.6}/PKG-INFO +1 -1
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/pyproject.toml +4 -2
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6/src/vortex_python_sdk.egg-info}/PKG-INFO +1 -1
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_sdk/__init__.py +15 -3
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_sdk/types.py +72 -11
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_sdk/vortex.py +28 -30
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/CHANGELOG.md +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/LICENSE +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/MANIFEST.in +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/README.md +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/setup.cfg +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/SOURCES.txt +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/dependency_links.txt +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/requires.txt +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/top_level.txt +0 -0
- {vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_sdk/py.typed +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vortex-python-sdk"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.6"
|
|
8
8
|
description = "Vortex Python SDK for invitation management and JWT generation"
|
|
9
9
|
authors = [{name = "TeamVortexSoftware", email = "support@vortexsoftware.com"}]
|
|
10
10
|
readme = "README.md"
|
|
@@ -68,7 +68,7 @@ profile = "black"
|
|
|
68
68
|
line_length = 88
|
|
69
69
|
|
|
70
70
|
[tool.mypy]
|
|
71
|
-
python_version = "3.
|
|
71
|
+
python_version = "3.9"
|
|
72
72
|
warn_return_any = true
|
|
73
73
|
warn_unused_configs = true
|
|
74
74
|
disallow_untyped_defs = true
|
|
@@ -83,6 +83,8 @@ warn_unreachable = true
|
|
|
83
83
|
[tool.ruff]
|
|
84
84
|
target-version = "py38"
|
|
85
85
|
line-length = 88
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint]
|
|
86
88
|
select = [
|
|
87
89
|
"E", # pycodestyle errors
|
|
88
90
|
"W", # pycodestyle warnings
|
|
@@ -5,20 +5,26 @@ A Python SDK for Vortex invitation management and JWT generation.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from .types import (
|
|
8
|
+
AcceptInvitationRequest,
|
|
8
9
|
AcceptInvitationsRequest,
|
|
10
|
+
ApiRequestBody,
|
|
9
11
|
ApiResponse,
|
|
12
|
+
ApiResponseJson,
|
|
10
13
|
AuthenticatedUser,
|
|
11
14
|
CreateInvitationRequest,
|
|
12
15
|
GroupInput,
|
|
13
16
|
IdentifierInput,
|
|
14
17
|
Invitation,
|
|
18
|
+
InvitationAcceptance,
|
|
19
|
+
InvitationGroup,
|
|
20
|
+
InvitationResult,
|
|
15
21
|
InvitationTarget,
|
|
16
22
|
JwtPayload,
|
|
17
23
|
VortexApiError,
|
|
18
24
|
)
|
|
19
25
|
from .vortex import Vortex
|
|
20
26
|
|
|
21
|
-
__version__ = "0.0.
|
|
27
|
+
__version__ = "0.0.6"
|
|
22
28
|
__author__ = "TeamVortexSoftware"
|
|
23
29
|
__email__ = "support@vortexsoftware.com"
|
|
24
30
|
|
|
@@ -29,9 +35,15 @@ __all__ = [
|
|
|
29
35
|
"IdentifierInput",
|
|
30
36
|
"GroupInput",
|
|
31
37
|
"InvitationTarget",
|
|
32
|
-
"
|
|
38
|
+
"InvitationGroup",
|
|
39
|
+
"InvitationAcceptance",
|
|
40
|
+
"InvitationResult",
|
|
41
|
+
"Invitation", # Alias for InvitationResult
|
|
33
42
|
"CreateInvitationRequest",
|
|
34
|
-
"
|
|
43
|
+
"AcceptInvitationRequest",
|
|
44
|
+
"AcceptInvitationsRequest", # Alias for AcceptInvitationRequest
|
|
35
45
|
"ApiResponse",
|
|
46
|
+
"ApiResponseJson",
|
|
47
|
+
"ApiRequestBody",
|
|
36
48
|
"VortexApiError",
|
|
37
49
|
]
|
|
@@ -68,24 +68,69 @@ class JwtPayload(BaseModel):
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
class InvitationTarget(BaseModel):
|
|
71
|
-
type: Literal["email", "
|
|
71
|
+
type: Literal["email", "sms"]
|
|
72
72
|
value: str
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
class
|
|
75
|
+
class InvitationAcceptance(BaseModel):
|
|
76
|
+
"""Represents an acceptance of an invitation"""
|
|
77
|
+
|
|
76
78
|
id: str
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
account_id: str = Field(alias="accountId")
|
|
80
|
+
project_id: str = Field(alias="projectId")
|
|
81
|
+
accepted_at: str = Field(alias="acceptedAt")
|
|
82
|
+
target: InvitationTarget
|
|
83
|
+
|
|
84
|
+
class Config:
|
|
85
|
+
populate_by_name = True
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class InvitationResult(BaseModel):
|
|
89
|
+
"""
|
|
90
|
+
Complete invitation result from API responses.
|
|
91
|
+
This is the exact port of the Node.js SDK's InvitationResult type.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
id: str
|
|
95
|
+
account_id: str = Field(alias="accountId")
|
|
96
|
+
click_throughs: int = Field(alias="clickThroughs")
|
|
97
|
+
configuration_attributes: Optional[Dict[str, Any]] = Field(
|
|
98
|
+
None, alias="configurationAttributes"
|
|
99
|
+
)
|
|
100
|
+
attributes: Optional[Dict[str, Any]] = None
|
|
101
|
+
created_at: str = Field(alias="createdAt")
|
|
102
|
+
deactivated: bool
|
|
103
|
+
delivery_count: int = Field(alias="deliveryCount")
|
|
104
|
+
delivery_types: List[Literal["email", "sms", "share"]] = Field(
|
|
105
|
+
alias="deliveryTypes"
|
|
106
|
+
)
|
|
107
|
+
foreign_creator_id: str = Field(alias="foreignCreatorId")
|
|
108
|
+
invitation_type: Literal["single_use", "multi_use"] = Field(alias="invitationType")
|
|
109
|
+
modified_at: Optional[str] = Field(None, alias="modifiedAt")
|
|
110
|
+
status: Literal[
|
|
111
|
+
"queued",
|
|
112
|
+
"sending",
|
|
113
|
+
"delivered",
|
|
114
|
+
"accepted",
|
|
115
|
+
"shared",
|
|
116
|
+
"unfurled",
|
|
117
|
+
"accepted_elsewhere",
|
|
118
|
+
]
|
|
119
|
+
target: List[InvitationTarget]
|
|
120
|
+
views: int
|
|
121
|
+
widget_configuration_id: str = Field(alias="widgetConfigurationId")
|
|
122
|
+
project_id: str = Field(alias="projectId")
|
|
123
|
+
groups: List[Optional[InvitationGroup]] = Field(default_factory=list)
|
|
124
|
+
accepts: List[InvitationAcceptance] = Field(default_factory=list)
|
|
84
125
|
|
|
85
126
|
class Config:
|
|
86
127
|
populate_by_name = True
|
|
87
128
|
|
|
88
129
|
|
|
130
|
+
# Alias for backward compatibility
|
|
131
|
+
Invitation = InvitationResult
|
|
132
|
+
|
|
133
|
+
|
|
89
134
|
class CreateInvitationRequest(BaseModel):
|
|
90
135
|
target: InvitationTarget
|
|
91
136
|
group_type: Optional[str] = None
|
|
@@ -94,10 +139,19 @@ class CreateInvitationRequest(BaseModel):
|
|
|
94
139
|
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
95
140
|
|
|
96
141
|
|
|
97
|
-
class
|
|
98
|
-
|
|
142
|
+
class AcceptInvitationRequest(BaseModel):
|
|
143
|
+
"""Request to accept one or more invitations"""
|
|
144
|
+
|
|
145
|
+
invitation_ids: List[str] = Field(alias="invitationIds")
|
|
99
146
|
target: InvitationTarget
|
|
100
147
|
|
|
148
|
+
class Config:
|
|
149
|
+
populate_by_name = True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Alias for backward compatibility
|
|
153
|
+
AcceptInvitationsRequest = AcceptInvitationRequest
|
|
154
|
+
|
|
101
155
|
|
|
102
156
|
class ApiResponse(BaseModel):
|
|
103
157
|
data: Optional[Dict] = None
|
|
@@ -110,3 +164,10 @@ class VortexApiError(Exception):
|
|
|
110
164
|
self.message = message
|
|
111
165
|
self.status_code = status_code
|
|
112
166
|
super().__init__(message)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# Type aliases to match Node.js SDK
|
|
170
|
+
ApiResponseJson = Union[
|
|
171
|
+
InvitationResult, Dict[str, List[InvitationResult]], Dict[str, Any]
|
|
172
|
+
]
|
|
173
|
+
ApiRequestBody = Union[AcceptInvitationRequest, None]
|
|
@@ -4,15 +4,11 @@ import hmac
|
|
|
4
4
|
import json
|
|
5
5
|
import time
|
|
6
6
|
import uuid
|
|
7
|
-
from typing import Dict, List, Literal, Optional, Union
|
|
8
|
-
from urllib.parse import urlencode
|
|
7
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
|
9
8
|
|
|
10
9
|
import httpx
|
|
11
10
|
|
|
12
11
|
from .types import (
|
|
13
|
-
AcceptInvitationsRequest,
|
|
14
|
-
ApiResponse,
|
|
15
|
-
CreateInvitationRequest,
|
|
16
12
|
Invitation,
|
|
17
13
|
InvitationTarget,
|
|
18
14
|
JwtPayload,
|
|
@@ -20,9 +16,10 @@ from .types import (
|
|
|
20
16
|
)
|
|
21
17
|
|
|
22
18
|
|
|
23
|
-
def _get_version():
|
|
19
|
+
def _get_version() -> str:
|
|
24
20
|
"""Lazy import of version to avoid circular import"""
|
|
25
21
|
from . import __version__
|
|
22
|
+
|
|
26
23
|
return __version__
|
|
27
24
|
|
|
28
25
|
|
|
@@ -80,7 +77,7 @@ class Vortex:
|
|
|
80
77
|
uuid_bytes = base64.urlsafe_b64decode(encoded_id_padded)
|
|
81
78
|
kid = str(uuid.UUID(bytes=uuid_bytes))
|
|
82
79
|
except Exception as e:
|
|
83
|
-
raise ValueError(f"Invalid UUID in API key: {e}")
|
|
80
|
+
raise ValueError(f"Invalid UUID in API key: {e}") from e
|
|
84
81
|
|
|
85
82
|
# Generate timestamps
|
|
86
83
|
iat = int(time.time())
|
|
@@ -106,16 +103,11 @@ class Vortex:
|
|
|
106
103
|
groups_list = None
|
|
107
104
|
if payload.groups is not None:
|
|
108
105
|
groups_list = [
|
|
109
|
-
|
|
110
|
-
k: v
|
|
111
|
-
for k, v in group.model_dump(
|
|
112
|
-
by_alias=True, exclude_none=True
|
|
113
|
-
).items()
|
|
114
|
-
}
|
|
106
|
+
group.model_dump(by_alias=True, exclude_none=True)
|
|
115
107
|
for group in payload.groups
|
|
116
108
|
]
|
|
117
109
|
|
|
118
|
-
jwt_payload = {
|
|
110
|
+
jwt_payload: Dict[str, Any] = {
|
|
119
111
|
"userId": payload.user_id,
|
|
120
112
|
"groups": groups_list,
|
|
121
113
|
"role": payload.role,
|
|
@@ -185,17 +177,17 @@ class Vortex:
|
|
|
185
177
|
"error",
|
|
186
178
|
f"API request failed with status {response.status_code}",
|
|
187
179
|
)
|
|
188
|
-
except:
|
|
180
|
+
except Exception:
|
|
189
181
|
error_message = (
|
|
190
182
|
f"API request failed with status {response.status_code}"
|
|
191
183
|
)
|
|
192
184
|
|
|
193
185
|
raise VortexApiError(error_message, response.status_code)
|
|
194
186
|
|
|
195
|
-
return response.json()
|
|
187
|
+
return response.json() # type: ignore[no-any-return]
|
|
196
188
|
|
|
197
189
|
except httpx.RequestError as e:
|
|
198
|
-
raise VortexApiError(f"Request failed: {str(e)}")
|
|
190
|
+
raise VortexApiError(f"Request failed: {str(e)}") from e
|
|
199
191
|
|
|
200
192
|
def _vortex_api_request_sync(
|
|
201
193
|
self,
|
|
@@ -238,17 +230,17 @@ class Vortex:
|
|
|
238
230
|
"error",
|
|
239
231
|
f"API request failed with status {response.status_code}",
|
|
240
232
|
)
|
|
241
|
-
except:
|
|
233
|
+
except Exception:
|
|
242
234
|
error_message = (
|
|
243
235
|
f"API request failed with status {response.status_code}"
|
|
244
236
|
)
|
|
245
237
|
|
|
246
238
|
raise VortexApiError(error_message, response.status_code)
|
|
247
239
|
|
|
248
|
-
return response.json()
|
|
240
|
+
return response.json() # type: ignore[no-any-return]
|
|
249
241
|
|
|
250
242
|
except httpx.RequestError as e:
|
|
251
|
-
raise VortexApiError(f"Request failed: {str(e)}")
|
|
243
|
+
raise VortexApiError(f"Request failed: {str(e)}") from e
|
|
252
244
|
|
|
253
245
|
async def get_invitations_by_target(
|
|
254
246
|
self,
|
|
@@ -335,10 +327,13 @@ class Vortex:
|
|
|
335
327
|
Returns:
|
|
336
328
|
API response
|
|
337
329
|
"""
|
|
330
|
+
target_obj: InvitationTarget
|
|
338
331
|
if isinstance(target, dict):
|
|
339
|
-
|
|
332
|
+
target_obj = InvitationTarget(**target) # type: ignore[arg-type]
|
|
333
|
+
else:
|
|
334
|
+
target_obj = target
|
|
340
335
|
|
|
341
|
-
data = {"invitationIds": invitation_ids, "target":
|
|
336
|
+
data = {"invitationIds": invitation_ids, "target": target_obj.model_dump()}
|
|
342
337
|
|
|
343
338
|
return await self._vortex_api_request("POST", "/invitations/accept", data=data)
|
|
344
339
|
|
|
@@ -355,10 +350,13 @@ class Vortex:
|
|
|
355
350
|
Returns:
|
|
356
351
|
API response
|
|
357
352
|
"""
|
|
353
|
+
target_obj: InvitationTarget
|
|
358
354
|
if isinstance(target, dict):
|
|
359
|
-
|
|
355
|
+
target_obj = InvitationTarget(**target) # type: ignore[arg-type]
|
|
356
|
+
else:
|
|
357
|
+
target_obj = target
|
|
360
358
|
|
|
361
|
-
data = {"invitationIds": invitation_ids, "target":
|
|
359
|
+
data = {"invitationIds": invitation_ids, "target": target_obj.model_dump()}
|
|
362
360
|
|
|
363
361
|
return self._vortex_api_request_sync("POST", "/invitations/accept", data=data)
|
|
364
362
|
|
|
@@ -482,26 +480,26 @@ class Vortex:
|
|
|
482
480
|
)
|
|
483
481
|
return Invitation(**response)
|
|
484
482
|
|
|
485
|
-
async def close(self):
|
|
483
|
+
async def close(self) -> None:
|
|
486
484
|
"""Close the HTTP client"""
|
|
487
485
|
await self._client.aclose()
|
|
488
486
|
|
|
489
|
-
def close_sync(self):
|
|
487
|
+
def close_sync(self) -> None:
|
|
490
488
|
"""Close the synchronous HTTP client"""
|
|
491
489
|
self._sync_client.close()
|
|
492
490
|
|
|
493
|
-
async def __aenter__(self):
|
|
491
|
+
async def __aenter__(self) -> "Vortex":
|
|
494
492
|
"""Async context manager entry"""
|
|
495
493
|
return self
|
|
496
494
|
|
|
497
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
495
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
498
496
|
"""Async context manager exit"""
|
|
499
497
|
await self.close()
|
|
500
498
|
|
|
501
|
-
def __enter__(self):
|
|
499
|
+
def __enter__(self) -> "Vortex":
|
|
502
500
|
"""Context manager entry"""
|
|
503
501
|
return self
|
|
504
502
|
|
|
505
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
503
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
506
504
|
"""Context manager exit"""
|
|
507
505
|
self.close_sync()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/requires.txt
RENAMED
|
File without changes
|
{vortex_python_sdk-0.0.5 → vortex_python_sdk-0.0.6}/src/vortex_python_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|