HedgeTech 0.3.2b1__tar.gz → 0.4.0b0__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 (46) hide show
  1. hedgetech-0.4.0b0/HedgeTech/Auth/__AuthAsyncClient.py +224 -0
  2. hedgetech-0.4.0b0/HedgeTech/Auth/__AuthSyncClient.py +230 -0
  3. hedgetech-0.4.0b0/HedgeTech/DataEngine/__ime/__AsyncClient.py +868 -0
  4. hedgetech-0.4.0b0/HedgeTech/DataEngine/__ime/__SyncClient.py +867 -0
  5. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__ime/__io_types/__response.py +204 -117
  6. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__tse_ifb/__AsyncClient.py +127 -59
  7. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__tse_ifb/__SyncClient.py +169 -66
  8. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__tse_ifb/__io_types/__response.py +286 -100
  9. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__ime/__AsyncClient.py +414 -0
  10. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__ime/__SyncClient.py +405 -0
  11. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__ime/__init__.py +2 -0
  12. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__ime/__io_types/__response.py +72 -0
  13. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/EmsEngine/__init__.py +4 -0
  14. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__tse_ifb/__AsyncClient.py +981 -0
  15. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__tse_ifb/__SyncClient.py +994 -0
  16. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__tse_ifb/__io_types/__init__.py +4 -0
  17. hedgetech-0.4.0b0/HedgeTech/EmsEngine/__tse_ifb/__io_types/__response.py +88 -0
  18. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech.egg-info/PKG-INFO +5 -1
  19. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech.egg-info/SOURCES.txt +5 -0
  20. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/PKG-INFO +5 -1
  21. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/pyproject.toml +6 -2
  22. hedgetech-0.3.2b1/HedgeTech/Auth/__AuthAsyncClient.py +0 -154
  23. hedgetech-0.3.2b1/HedgeTech/Auth/__AuthSyncClient.py +0 -157
  24. hedgetech-0.3.2b1/HedgeTech/DataEngine/__ime/__AsyncClient.py +0 -349
  25. hedgetech-0.3.2b1/HedgeTech/DataEngine/__ime/__SyncClient.py +0 -339
  26. hedgetech-0.3.2b1/HedgeTech/EmsEngine/__tse_ifb/__AsyncClient.py +0 -858
  27. hedgetech-0.3.2b1/HedgeTech/EmsEngine/__tse_ifb/__SyncClient.py +0 -875
  28. hedgetech-0.3.2b1/HedgeTech/EmsEngine/__tse_ifb/__io_types/__response.py +0 -79
  29. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/Auth/__init__.py +0 -0
  30. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/Auth/__utils/__RetriableAsyncClient.py +0 -0
  31. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/Auth/__utils/__RetriableSyncClient.py +0 -0
  32. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/Auth/__utils/__init__.py +0 -0
  33. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__ime/__init__.py +0 -0
  34. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__ime/__io_types/__init__.py +0 -0
  35. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__init__.py +0 -0
  36. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__tse_ifb/__init__.py +0 -0
  37. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/DataEngine/__tse_ifb/__io_types/__init__.py +0 -0
  38. {hedgetech-0.3.2b1/HedgeTech/EmsEngine/__tse_ifb → hedgetech-0.4.0b0/HedgeTech/EmsEngine/__ime}/__io_types/__init__.py +0 -0
  39. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech/EmsEngine/__tse_ifb/__init__.py +0 -0
  40. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech.egg-info/dependency_links.txt +0 -0
  41. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech.egg-info/requires.txt +0 -0
  42. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/HedgeTech.egg-info/top_level.txt +0 -0
  43. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/LICENSE +0 -0
  44. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/NOTICE +0 -0
  45. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/README.md +0 -0
  46. {hedgetech-0.3.2b1 → hedgetech-0.4.0b0}/setup.cfg +0 -0
@@ -0,0 +1,224 @@
1
+ # ========================================|======================================== #
2
+ # Imports #
3
+ # ========================================|======================================== #
4
+
5
+ from .__utils import RetriableAsyncClient
6
+ from httpx import (
7
+ AsyncClient ,
8
+ Timeout ,
9
+ )
10
+ from jwt import decode
11
+
12
+ # ========================================|======================================== #
13
+ # Class Definitions #
14
+ # ========================================|======================================== #
15
+
16
+ class AuthAsyncClient:
17
+ """
18
+ Asynchronous client for interacting with the HedgeTech API using JWT-based authentication.
19
+
20
+ This class provides a high-level interface to authenticate users, manage JWT tokens,
21
+ and make authorized HTTP requests using an `httpx.AsyncClient`.
22
+
23
+ Normally an instance is created with ``AuthAsyncClient.login(...)``. Calling the
24
+ constructor directly is only useful when you already have a configured HTTP client and
25
+ a valid token. The resulting object is what the data clients
26
+ (``DataEngine_Ime_AsyncClient``, ``DataEngine_TseIfb_AsyncClient``) receive: they use
27
+ ``httpx_Client`` for REST requests and ``token`` as the WebSocket headers.
28
+
29
+ Note:
30
+ * The client does not refresh the token. When the JWT expires, requests start to
31
+ fail and you need to call ``login`` again to get a new client.
32
+ * ``Permissions`` is decoded WITHOUT verifying the signature or the expiry, so it is
33
+ only meant for reading the claims (e.g. to display them), never for making
34
+ security decisions.
35
+
36
+ Attributes:
37
+ httpx_Client (AsyncClient): The HTTP client used for authorized requests. When created
38
+ by ``login`` it is a ``RetriableAsyncClient`` (a wrapper around ``httpx.AsyncClient``
39
+ that retries failed requests, up to 10 times) configured with:
40
+
41
+ - the authentication headers (the token returned by the server plus an ``origin``
42
+ header) and the cookies received at login;
43
+ - HTTP/2 only (``http1=False``, ``http2=True``) with TLS verification enabled;
44
+ - short timeouts: connect 0.25 s, read 1.5 s, write 1.5 s, pool 0.25 s.
45
+ token (dict[str, str]): Dictionary containing the authentication tokens. It must contain
46
+ the ``'Authorization'`` key holding the JWT string. It is also passed as the
47
+ ``additional_headers`` of WebSocket connections.
48
+ Permissions (dict): The decoded JWT payload (its claims), set by ``UpdatePermission``
49
+ when the object is created. The available claims depend on the server.
50
+
51
+ Example:
52
+ >>> client = await AuthAsyncClient.login(
53
+ ... UserName_or_Email="user@example.com",
54
+ ... Password="secure_password"
55
+ ... )
56
+ >>> client.token['Authorization'][:10]
57
+ 'eyJ0eXAiOi'
58
+ >>> client.Permissions # Decoded JWT payload
59
+ {'sub': 'user_id', 'exp': 1700350200, ...}
60
+ >>> data_client = DataEngine_TseIfb_AsyncClient(AuthAsyncClient=client)
61
+ """
62
+
63
+ def __init__(
64
+ self,
65
+ *,
66
+ httpx_Client:AsyncClient,
67
+ token:dict[str,str],
68
+ ):
69
+ """
70
+ Initialize the AuthAsyncClient with an existing httpx.AsyncClient and authentication token.
71
+
72
+ Both arguments are keyword-only. The token is decoded immediately (see
73
+ ``UpdatePermission``), so ``Permissions`` is available right after construction.
74
+
75
+ Args:
76
+ httpx_Client (AsyncClient): Preconfigured AsyncClient for making authorized requests.
77
+ It should already send the authentication headers (``login`` does this for you).
78
+ token (dict[str, str]): Dictionary containing authentication tokens. It must contain
79
+ the ``'Authorization'`` key with the JWT string.
80
+
81
+ Raises:
82
+ ValueError: If the token cannot be decoded (see ``UpdatePermission``).
83
+
84
+ Example:
85
+ >>> client = AuthAsyncClient(
86
+ ... httpx_Client=my_httpx_client,
87
+ ... token={"Authorization": "<jwt>"}
88
+ ... )
89
+ >>> client.Permissions
90
+ {'sub': 'user_id', 'exp': 1700350200, ...}
91
+ """
92
+
93
+ self.httpx_Client : AsyncClient = httpx_Client
94
+ self.token : dict[str,str] = token
95
+
96
+ self.UpdatePermission
97
+
98
+
99
+ @property
100
+ def UpdatePermission(self)-> None:
101
+
102
+ """
103
+ Decodes the JWT 'Authorization' token to extract user permissions.
104
+
105
+ This is a **property**, not a method: reading ``client.UpdatePermission`` (without
106
+ parentheses) performs the work and returns ``None``. It is read once in ``__init__``;
107
+ read it again to re-decode ``token`` after you replace it.
108
+
109
+ The decoded payload is stored in ``self.Permissions``. The token is decoded
110
+ WITHOUT verifying the signature, and the expiry (``exp``) is not checked either.
111
+
112
+ Raises:
113
+ ValueError: If the JWT cannot be decoded. Any underlying error is wrapped in
114
+ ``ValueError``, including a missing ``'Authorization'`` key in ``token``.
115
+
116
+ Example:
117
+ >>> client.token = new_token
118
+ >>> client.UpdatePermission # no parentheses; re-decodes the token
119
+ >>> client.Permissions
120
+ {'sub': 'user_id', 'exp': 1700350200, ...}
121
+ """
122
+
123
+ try :
124
+
125
+ self.Permissions = decode(
126
+ jwt=self.token['Authorization'].encode(),
127
+ algorithms='HS256',
128
+ options={"verify_signature": False},
129
+ )
130
+
131
+ except Exception as e:
132
+
133
+ raise ValueError(e)
134
+
135
+
136
+ @classmethod
137
+ async def login(
138
+ cls,
139
+ *,
140
+ UserName_or_Email : str,
141
+ Password : str
142
+ )-> "AuthAsyncClient":
143
+
144
+ """
145
+ Authenticate a user and return an instance of `AuthAsyncClient`.
146
+
147
+ This method performs the login request to the HedgeTech API, retrieves JWT tokens,
148
+ and configures an `httpx.AsyncClient` with authentication headers and cookies.
149
+
150
+ It sends ``POST https://core.hedgetech.ir/auth/user/token/issue`` with the credentials as
151
+ form data. The login succeeds only when the server answers with HTTP status ``201``.
152
+ The JSON body of that answer is used as ``token`` and is also sent as headers on every
153
+ later request, together with an ``origin: https://core.hedgetech.ir`` header. The cookies
154
+ set at login are kept.
155
+
156
+ Args:
157
+ UserName_or_Email (str): The username or email of the user.
158
+ Password (str): The user's password.
159
+
160
+ Returns:
161
+ AuthAsyncClient: An initialized client ready to make authorized requests. Its
162
+ ``httpx_Client`` is a ``RetriableAsyncClient`` (10 retries) using HTTP/2 with the
163
+ short timeouts described in the class docstring.
164
+
165
+ Raises:
166
+ ValueError: If the login attempt fails (e.g., wrong credentials), i.e. the status is
167
+ not ``201``. The message is the server's ``detail`` field, which is ``None`` if
168
+ the server did not send one. The same exception is raised if the token returned
169
+ by the server cannot be decoded (see ``UpdatePermission``).
170
+
171
+ Note:
172
+ Network errors while sending the login request (for example a connection failure or
173
+ timeout) are raised by ``httpx`` as they are and are not converted to ``ValueError``.
174
+
175
+ Example:
176
+ >>> client = await AuthAsyncClient.login(
177
+ ... UserName_or_Email="user@example.com",
178
+ ... Password="secure_password"
179
+ ... )
180
+ >>> client.token['Authorization'][:10]
181
+ 'eyJ0eXAiOi'
182
+ """
183
+
184
+ httpx_Client = AsyncClient(verify=True ,http1=False ,http2=True)
185
+
186
+ login_res = await httpx_Client.post(
187
+ url='https://core.hedgetech.ir/auth/user/token/issue',
188
+ data={
189
+ 'UserName_or_Email' : UserName_or_Email,
190
+ 'Password' : Password
191
+ }
192
+ )
193
+
194
+ if login_res.status_code == 201:
195
+
196
+ token = login_res.json()
197
+ headers = {'origin' : 'https://core.hedgetech.ir'}
198
+ headers.update(token)
199
+
200
+ httpx_Client = RetriableAsyncClient(
201
+ client = AsyncClient(
202
+ verify=True ,
203
+ http1=False ,
204
+ http2=True ,
205
+ headers=headers,
206
+ cookies=httpx_Client.cookies,
207
+ timeout=Timeout(
208
+ connect=.250,
209
+ read=1.5,
210
+ write=1.5,
211
+ pool=.250,
212
+ ),
213
+ ),
214
+ retries= 10
215
+ )
216
+
217
+ return cls(
218
+ httpx_Client = httpx_Client,
219
+ token = token
220
+ )
221
+
222
+ else :
223
+
224
+ raise ValueError(login_res.json().get('detail'))
@@ -0,0 +1,230 @@
1
+ # ========================================|======================================== #
2
+ # Imports #
3
+ # ========================================|======================================== #
4
+
5
+ from .__utils import RetriableSyncClient
6
+ from httpx import (
7
+ Client ,
8
+ Timeout ,
9
+ )
10
+ from jwt import decode
11
+
12
+ # ========================================|======================================== #
13
+ # Class Definitions #
14
+ # ========================================|======================================== #
15
+
16
+
17
+ class AuthSyncClient:
18
+ """
19
+ Synchronous client for interacting with the HedgeTech API using JWT-based authentication.
20
+
21
+ This class provides a high-level interface to authenticate users, manage JWT tokens,
22
+ and make authorized HTTP requests using an `httpx.Client`.
23
+
24
+ This is the blocking twin of ``AuthAsyncClient``: same login endpoint, token handling and
25
+ configuration, only the calling style differs (plain calls instead of ``await``).
26
+
27
+ Normally an instance is created with ``AuthSyncClient.login(...)``. Calling the
28
+ constructor directly is only useful when you already have a configured HTTP client and
29
+ a valid token. The resulting object is what the data clients
30
+ (``DataEngine_Ime_SyncClient``, ``DataEngine_TseIfb_SyncClient``) receive: they use
31
+ ``httpx_Client`` for REST requests and ``token`` as the WebSocket headers.
32
+
33
+ Note:
34
+ * The client does not refresh the token. When the JWT expires, requests start to
35
+ fail and you need to call ``login`` again to get a new client.
36
+ * ``Permissions`` is decoded WITHOUT verifying the signature or the expiry, so it is
37
+ only meant for reading the claims (e.g. to display them), never for making
38
+ security decisions.
39
+
40
+ Attributes:
41
+ httpx_Client (Client): The HTTP client used for authorized requests. When created
42
+ by ``login`` it is a ``RetriableSyncClient`` (a wrapper around ``httpx.Client``
43
+ that retries failed requests, up to 10 times) configured with:
44
+
45
+ - the authentication headers (the token returned by the server plus an ``origin``
46
+ header) and the cookies received at login;
47
+ - HTTP/2 only (``http1=False``, ``http2=True``) with TLS verification enabled;
48
+ - short timeouts: connect 0.25 s, read 1.5 s, write 1.5 s, pool 0.25 s.
49
+ token (dict[str, str]): Dictionary containing the authentication tokens. It must contain
50
+ the ``'Authorization'`` key holding the JWT string. It is also passed as the
51
+ ``additional_headers`` of WebSocket connections.
52
+ Permissions (dict): The decoded JWT payload (its claims), set by ``UpdatePermission``
53
+ when the object is created. The available claims depend on the server.
54
+
55
+ Example:
56
+ >>> client = AuthSyncClient.login(
57
+ ... UserName_or_Email="user@example.com",
58
+ ... Password="secure_password"
59
+ ... )
60
+ >>> client.token['Authorization'][:10]
61
+ 'eyJ0eXAiOi'
62
+ >>> client.Permissions # Decoded JWT payload
63
+ {'sub': 'user_id', 'exp': 1700350200, ...}
64
+ >>> data_client = DataEngine_TseIfb_SyncClient(AuthSyncClient=client)
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ *,
70
+ httpx_Client:Client,
71
+ token:dict[str,str],
72
+ ):
73
+ """
74
+ Initialize the AuthSyncClient with an existing httpx.Client and authentication token.
75
+
76
+ Both arguments are keyword-only. The token is decoded immediately (see
77
+ ``UpdatePermission``), so ``Permissions`` is available right after construction.
78
+
79
+ Args:
80
+ httpx_Client (Client): Preconfigured Client for making authorized requests.
81
+ It should already send the authentication headers (``login`` does this for you).
82
+ token (dict[str, str]): Dictionary containing authentication tokens. It must contain
83
+ the ``'Authorization'`` key with the JWT string.
84
+
85
+ Raises:
86
+ ValueError: If the token cannot be decoded (see ``UpdatePermission``).
87
+
88
+ Example:
89
+ >>> client = AuthSyncClient(
90
+ ... httpx_Client=my_httpx_client,
91
+ ... token={"Authorization": "<jwt>"}
92
+ ... )
93
+ >>> client.Permissions
94
+ {'sub': 'user_id', 'exp': 1700350200, ...}
95
+ """
96
+
97
+ self.httpx_Client : Client = httpx_Client
98
+ self.token : dict[str,str] = token
99
+
100
+ self.UpdatePermission
101
+
102
+
103
+ @property
104
+ def UpdatePermission(self)-> None:
105
+
106
+ """
107
+ Decodes the JWT 'Authorization' token to extract user permissions.
108
+
109
+ This is a **property**, not a method: reading ``client.UpdatePermission`` (without
110
+ parentheses) performs the work and returns ``None``. It is read once in ``__init__``;
111
+ read it again to re-decode ``token`` after you replace it.
112
+
113
+ The decoded payload is stored in ``self.Permissions``. The token is decoded
114
+ WITHOUT verifying the signature, and the expiry (``exp``) is not checked either.
115
+
116
+ Raises:
117
+ ValueError: If the JWT cannot be decoded. Any underlying error is wrapped in
118
+ ``ValueError``, including a missing ``'Authorization'`` key in ``token``.
119
+
120
+ Example:
121
+ >>> client.token = new_token
122
+ >>> client.UpdatePermission # no parentheses; re-decodes the token
123
+ >>> client.Permissions
124
+ {'sub': 'user_id', 'exp': 1700350200, ...}
125
+ """
126
+
127
+ try :
128
+
129
+ self.Permissions = decode(
130
+ jwt=self.token['Authorization'].encode(),
131
+ algorithms='HS256',
132
+ options={"verify_signature": False},
133
+ )
134
+
135
+ except Exception as e:
136
+
137
+ raise ValueError(e)
138
+
139
+
140
+ @classmethod
141
+ def login(
142
+ cls,
143
+ *,
144
+ UserName_or_Email : str,
145
+ Password : str
146
+ )-> "AuthSyncClient":
147
+
148
+ """
149
+ Authenticate a user synchronously and return an instance of `AuthSyncClient`.
150
+
151
+ This method performs the login request to the HedgeTech API, retrieves JWT tokens,
152
+ and configures an `httpx.Client` with authentication headers and cookies.
153
+
154
+ It sends ``POST https://core.hedgetech.ir/auth/user/token/issue`` with the credentials as
155
+ form data. The login succeeds only when the server answers with HTTP status ``201``.
156
+ The JSON body of that answer is used as ``token`` and is also sent as headers on every
157
+ later request, together with an ``origin: https://core.hedgetech.ir`` header. The cookies
158
+ set at login are kept.
159
+
160
+ Args:
161
+ UserName_or_Email (str): The username or email of the user.
162
+ Password (str): The user's password.
163
+
164
+ Returns:
165
+ AuthSyncClient: An initialized client ready to make authorized requests. Its
166
+ ``httpx_Client`` is a ``RetriableSyncClient`` (10 retries) using HTTP/2 with the
167
+ short timeouts described in the class docstring.
168
+
169
+ Raises:
170
+ ValueError: If the login attempt fails (e.g., wrong credentials), i.e. the status is
171
+ not ``201``. The message is the server's ``detail`` field, which is ``None`` if
172
+ the server did not send one. The same exception is raised if the token returned
173
+ by the server cannot be decoded (see ``UpdatePermission``).
174
+
175
+ Note:
176
+ Network errors while sending the login request (for example a connection failure or
177
+ timeout) are raised by ``httpx`` as they are and are not converted to ``ValueError``.
178
+
179
+ Example:
180
+ >>> client = AuthSyncClient.login(
181
+ ... UserName_or_Email="user@example.com",
182
+ ... Password="secure_password"
183
+ ... )
184
+ >>> client.token['Authorization'][:10]
185
+ 'eyJ0eXAiOi'
186
+ """
187
+
188
+ httpx_Client = Client(verify=True ,http1=False ,http2=True)
189
+
190
+
191
+ login_res = httpx_Client.post(
192
+ url='https://core.hedgetech.ir/auth/user/token/issue',
193
+ data={
194
+ 'UserName_or_Email' : UserName_or_Email,
195
+ 'Password' : Password
196
+ }
197
+ )
198
+
199
+
200
+ if login_res.status_code == 201:
201
+
202
+ token = login_res.json()
203
+ headers = {'origin' : 'https://core.hedgetech.ir'}
204
+ headers.update(token)
205
+
206
+ httpx_Client = RetriableSyncClient(
207
+ client = Client(
208
+ verify=True ,
209
+ http1=False ,
210
+ http2=True ,
211
+ headers=headers,
212
+ cookies=httpx_Client.cookies,
213
+ timeout=Timeout(
214
+ connect=.250,
215
+ read=1.5,
216
+ write=1.5,
217
+ pool=.250,
218
+ ),
219
+ ),
220
+ retries= 10
221
+ )
222
+
223
+ return cls(
224
+ httpx_Client = httpx_Client,
225
+ token = token
226
+ )
227
+
228
+ else :
229
+
230
+ raise ValueError(login_res.json().get('detail'))