diracx-client 0.0.1a20__py3-none-any.whl → 0.0.1a21__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,11 +9,12 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python
9
9
  from __future__ import annotations
10
10
 
11
11
  import abc
12
- import json
13
12
  from importlib.metadata import PackageNotFoundError, distribution
14
13
  from types import TracebackType
15
14
  from pathlib import Path
16
- from typing import Any, List, Optional, Self
15
+
16
+ from typing import Any, List, Optional, cast
17
+
17
18
  from azure.core.credentials import AccessToken
18
19
  from azure.core.credentials_async import AsyncTokenCredential
19
20
  from azure.core.pipeline import PipelineRequest
@@ -24,8 +25,6 @@ from diracx.core.preferences import get_diracx_preferences, DiracxPreferences
24
25
  from ..utils import (
25
26
  get_openid_configuration,
26
27
  get_token,
27
- refresh_token,
28
- is_refresh_token_valid,
29
28
  )
30
29
 
31
30
  __all__: List[str] = [
@@ -56,20 +55,12 @@ class DiracTokenCredential(AsyncTokenCredential):
56
55
  tenant_id: Optional[str] = None,
57
56
  **kwargs: Any,
58
57
  ) -> AccessToken:
59
- """Refresh the access token using the refresh_token flow.
60
- :param str scopes: The type of access needed.
61
- :keyword str claims: Additional claims required in the token, such as those returned in a resource
62
- provider's claims challenge following an authorization failure.
63
- :keyword str tenant_id: Optional tenant to include in the token request.
64
- :rtype: AccessToken
65
- :return: An AccessToken instance containing the token string and its expiration time in Unix time.
66
- """
67
- return refresh_token(
58
+ return get_token(
68
59
  self.location,
60
+ kwargs.get("token"),
69
61
  self.token_endpoint,
70
62
  self.client_id,
71
- kwargs["refresh_token"],
72
- verify=self.verify,
63
+ self.verify,
73
64
  )
74
65
 
75
66
  async def close(self) -> None:
@@ -97,6 +88,9 @@ class DiracBearerTokenCredentialPolicy(AsyncBearerTokenCredentialPolicy):
97
88
  * It does not ensure that an access token is available.
98
89
  """
99
90
 
91
+ # Make mypy happy
92
+ _token: Optional[AccessToken] = None
93
+
100
94
  def __init__(
101
95
  self, credential: DiracTokenCredential, *scopes: str, **kwargs: Any
102
96
  ) -> None:
@@ -110,28 +104,19 @@ class DiracBearerTokenCredentialPolicy(AsyncBearerTokenCredentialPolicy):
110
104
  :type request: ~azure.core.pipeline.PipelineRequest
111
105
  :raises: :class:`~azure.core.exceptions.ServiceRequestError`
112
106
  """
113
- self._token: AccessToken | None
114
- self._credential: DiracTokenCredential
115
- credentials: dict[str, Any]
116
- try:
117
- self._token = get_token(self._credential.location, self._token)
118
- except RuntimeError:
119
- # If we are here, it means the credentials path does not exist
107
+ # Make mypy happy
108
+ if not isinstance(self._credential, AsyncTokenCredential):
109
+ return
110
+
111
+ self._token = await self._credential.get_token("", token=self._token)
112
+ if not self._token.token:
113
+ # If we are here, it means the token is not available
120
114
  # we suppose it is not needed to perform the request
121
115
  return
122
116
 
123
- if not self._token:
124
- credentials = json.loads(self._credential.location.read_text())
125
- refresh_token = credentials["refresh_token"]
126
- if not is_refresh_token_valid(refresh_token):
127
- # If we are here, it means the refresh token is not valid anymore
128
- # we suppose it is not needed to perform the request
129
- return
130
- self._token = await self._credential.get_token(
131
- "", refresh_token=refresh_token
132
- )
133
-
134
- request.http_request.headers["Authorization"] = f"Bearer {self._token.token}"
117
+ request.http_request.headers["Authorization"] = (
118
+ "Bearer " + cast(AccessToken, self._token).token
119
+ )
135
120
 
136
121
 
137
122
  class DiracClientMixin(metaclass=abc.ABCMeta):
@@ -1,7 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
-
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timedelta, timezone
5
+ from enum import Enum
6
+ import fcntl
4
7
  import json
8
+ import os
9
+ from diracx.core.utils import EXPIRES_GRACE_SECONDS, serialize_credentials
5
10
  import jwt
6
11
  import requests
7
12
 
@@ -9,31 +14,115 @@ from datetime import datetime, timezone
9
14
  from importlib.metadata import PackageNotFoundError, distribution
10
15
 
11
16
  from pathlib import Path
12
- from typing import Any, Dict, List, Optional, cast, Self
17
+
18
+ from typing import Any, Dict, Optional, TextIO
13
19
  from urllib import parse
14
20
  from azure.core.credentials import AccessToken
15
21
  from azure.core.credentials import TokenCredential
16
22
  from azure.core.pipeline import PipelineRequest
17
23
  from azure.core.pipeline.policies import BearerTokenCredentialPolicy
18
24
 
19
- from ..generated.models import TokenResponse
20
- from diracx.core.models import TokenResponse as CoreTokenResponse
25
+ from diracx.core.models import TokenResponse
21
26
  from diracx.core.preferences import DiracxPreferences, get_diracx_preferences
22
27
 
23
- import sys
24
28
 
29
+ class TokenStatus(Enum):
30
+ VALID = "valid"
31
+ REFRESH = "refresh"
32
+ INVALID = "invalid"
25
33
 
26
- def refresh_token(
34
+
35
+ @dataclass
36
+ class TokenResult:
37
+ status: TokenStatus
38
+ access_token: Optional[AccessToken] = None
39
+ refresh_token: Optional[str] = None
40
+
41
+
42
+ def get_openid_configuration(
43
+ endpoint: str, *, verify: bool | str = True
44
+ ) -> Dict[str, str]:
45
+ """Get the openid configuration from the .well-known endpoint"""
46
+ response = requests.get(
47
+ url=parse.urljoin(endpoint, ".well-known/openid-configuration"),
48
+ verify=verify,
49
+ )
50
+ if not response.ok:
51
+ raise RuntimeError("Cannot fetch any information from the .well-known endpoint")
52
+ return response.json()
53
+
54
+
55
+ def get_token(
27
56
  location: Path,
57
+ token: AccessToken | None,
58
+ token_endpoint: str,
59
+ client_id: str,
60
+ verify: bool | str,
61
+ ) -> AccessToken:
62
+ """Get the access token if available and still valid."""
63
+ # Immediately return the token if it is available and still valid
64
+ if token and is_token_valid(token):
65
+ return token
66
+
67
+ if not location.exists():
68
+ # If we are here, it means the credentials path does not exist
69
+ # we suppose access token is not needed to perform the request
70
+ # we return an empty token to align with the expected return type
71
+ return AccessToken(token="", expires_on=0)
72
+
73
+ with open(location, "r+") as f:
74
+ # Acquire exclusive lock
75
+ fcntl.flock(f, fcntl.LOCK_EX)
76
+ try:
77
+ response = extract_token_from_credentials(f, token)
78
+ if response.status == TokenStatus.VALID and response.access_token:
79
+ # Lock is released in the finally block
80
+ return response.access_token
81
+
82
+ if response.status == TokenStatus.REFRESH and response.refresh_token:
83
+ # If we are here, it means the token needs to be refreshed
84
+ token_response = refresh_token(
85
+ token_endpoint,
86
+ client_id,
87
+ response.refresh_token,
88
+ verify=verify,
89
+ )
90
+
91
+ # Write the new credentials to the file
92
+ f.seek(0)
93
+ f.truncate()
94
+ f.write(serialize_credentials(token_response))
95
+ f.flush()
96
+ os.fsync(f.fileno())
97
+
98
+ # Get an AccessToken instance
99
+ return AccessToken(
100
+ token=token_response.access_token,
101
+ expires_on=int(
102
+ (
103
+ datetime.now(tz=timezone.utc)
104
+ + timedelta(
105
+ seconds=token_response.expires_in
106
+ - EXPIRES_GRACE_SECONDS
107
+ )
108
+ ).timestamp()
109
+ ),
110
+ )
111
+ # If we are here, it means the token is not available or not valid anymore
112
+ return AccessToken(token="", expires_on=0)
113
+ finally:
114
+ # Release the lock
115
+ fcntl.flock(f, fcntl.LOCK_UN)
116
+
117
+
118
+ def refresh_token(
28
119
  token_endpoint: str,
29
120
  client_id: str,
30
121
  refresh_token: str,
31
122
  *,
32
123
  verify: bool | str = True,
33
- ) -> AccessToken:
124
+ ) -> TokenResponse:
34
125
  """Refresh the access token using the refresh_token flow."""
35
- from diracx.core.utils import write_credentials
36
-
37
126
  response = requests.post(
38
127
  url=token_endpoint,
39
128
  data={
@@ -50,56 +139,49 @@ def refresh_token(
50
139
  )
51
140
 
52
141
  res = response.json()
53
- token_response = TokenResponse(
142
+ return TokenResponse(
54
143
  access_token=res["access_token"],
55
144
  expires_in=res["expires_in"],
56
145
  token_type=res.get("token_type"),
57
146
  refresh_token=res.get("refresh_token"),
58
147
  )
59
148
 
60
- write_credentials(cast(CoreTokenResponse, token_response), location=location)
61
- credentials = json.loads(location.read_text())
62
- return AccessToken(credentials.get("access_token"), credentials.get("expires_on"))
63
149
 
64
-
65
- def get_openid_configuration(
66
- endpoint: str, *, verify: bool | str = True
67
- ) -> Dict[str, str]:
68
- """Get the openid configuration from the .well-known endpoint"""
69
- response = requests.get(
70
- url=parse.urljoin(endpoint, ".well-known/openid-configuration"),
71
- verify=verify,
72
- )
73
- if not response.ok:
74
- raise RuntimeError("Cannot fetch any information from the .well-known endpoint")
75
- return response.json()
76
-
77
-
78
- def get_token(location: Path, token: AccessToken | None) -> AccessToken | None:
150
+ def extract_token_from_credentials(
151
+ token_file_descriptor: TextIO, token: AccessToken | None
152
+ ) -> TokenResult:
79
153
  """Get token if available and still valid."""
80
- # If the credentials path does not exist, raise an error
81
- if not location.exists():
82
- raise RuntimeError("credentials are not set")
83
-
84
- # Load the existing credentials
85
- if not token:
86
- credentials = json.loads(location.read_text())
154
+ # If we are here, it means the token is not available or not valid anymore
155
+ # We try to get it from the file
156
+ try:
157
+ credentials = json.load(token_file_descriptor)
158
+ except json.JSONDecodeError:
159
+ return TokenResult(TokenStatus.INVALID)
160
+
161
+ try:
87
162
  token = AccessToken(
88
- cast(str, credentials.get("access_token")),
89
- cast(int, credentials.get("expires_on")),
163
+ token=credentials["access_token"],
164
+ expires_on=credentials["expires_on"],
90
165
  )
166
+ refresh_token = credentials["refresh_token"]
167
+ except KeyError:
168
+ return TokenResult(TokenStatus.INVALID)
169
+
170
+ # We check the validity of the tokens
171
+ if is_token_valid(token):
172
+ return TokenResult(TokenStatus.VALID, access_token=token)
91
173
 
92
- # We check the validity of the token
93
- # If not valid, then return None to inform the caller that a new token
94
- # is needed
95
- if not is_token_valid(token):
96
- return None
174
+ if is_refresh_token_valid(refresh_token):
175
+ return TokenResult(TokenStatus.REFRESH, refresh_token=refresh_token)
97
176
 
98
- return token
177
+ # If we are here, it means the refresh token is not valid anymore
178
+ return TokenResult(TokenStatus.INVALID)
99
179
 
100
180
 
101
- def is_refresh_token_valid(refresh_token: str) -> bool:
181
+ def is_refresh_token_valid(refresh_token: str | None) -> bool:
102
182
  """Check if the refresh token is still valid."""
183
+ if not refresh_token:
184
+ return False
103
185
  # Decode the refresh token
104
186
  refresh_payload = jwt.decode(refresh_token, options={"verify_signature": False})
105
187
  if not refresh_payload or "exp" not in refresh_payload:
@@ -140,20 +222,12 @@ class DiracTokenCredential(TokenCredential):
140
222
  tenant_id: Optional[str] = None,
141
223
  **kwargs: Any,
142
224
  ) -> AccessToken:
143
- """Refresh the access token using the refresh_token flow.
144
- :param str scopes: The type of access needed.
145
- :keyword str claims: Additional claims required in the token, such as those returned in a resource
146
- provider's claims challenge following an authorization failure.
147
- :keyword str tenant_id: Optional tenant to include in the token request.
148
- :rtype: AccessToken
149
- :return: An AccessToken instance containing the token string and its expiration time in Unix time.
150
- """
151
- return refresh_token(
225
+ return get_token(
152
226
  self.location,
227
+ kwargs.get("token"),
153
228
  self.token_endpoint,
154
229
  self.client_id,
155
- kwargs["refresh_token"],
156
- verify=self.verify,
230
+ self.verify,
157
231
  )
158
232
 
159
233
 
@@ -164,40 +238,31 @@ class DiracBearerTokenCredentialPolicy(BearerTokenCredentialPolicy):
164
238
  * It does not ensure that an access token is available.
165
239
  """
166
240
 
241
+ # Make mypy happy
242
+ _token: Optional[AccessToken] = None
243
+
167
244
  def __init__(
168
245
  self, credential: DiracTokenCredential, *scopes: str, **kwargs: Any
169
246
  ) -> None:
170
247
  super().__init__(credential, *scopes, **kwargs)
171
248
 
172
- def on_request(
173
- self, request: PipelineRequest
174
- ) -> None: # pylint:disable=invalid-overridden-method
249
+ def on_request(self, request: PipelineRequest) -> None:
175
250
  """Authorization Bearer is optional here.
176
251
  :param request: The pipeline request object to be modified.
177
252
  :type request: ~azure.core.pipeline.PipelineRequest
178
253
  :raises: :class:`~azure.core.exceptions.ServiceRequestError`
179
254
  """
180
- self._token: AccessToken | None
181
- self._credential: DiracTokenCredential
182
- credentials: dict[str, Any]
255
+ # Make mypy happy
256
+ if not isinstance(self._credential, TokenCredential):
257
+ return
183
258
 
184
- try:
185
- self._token = get_token(self._credential.location, self._token)
186
- except RuntimeError:
187
- # If we are here, it means the credentials path does not exist
259
+ self._token = self._credential.get_token("", token=self._token)
260
+ if not self._token.token:
261
+ # If we are here, it means the token is not available
188
262
  # we suppose it is not needed to perform the request
189
263
  return
190
264
 
191
- if not self._token:
192
- credentials = json.loads(self._credential.location.read_text())
193
- refresh_token = credentials["refresh_token"]
194
- if not is_refresh_token_valid(refresh_token):
195
- # If we are here, it means the refresh token is not valid anymore
196
- # we suppose it is not needed to perform the request
197
- return
198
- self._token = self._credential.get_token("", refresh_token=refresh_token)
199
-
200
- request.http_request.headers["Authorization"] = f"Bearer {self._token.token}"
265
+ self._update_headers(request.http_request.headers, self._token.token)
201
266
 
202
267
 
203
268
  class DiracClientMixin:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diracx-client
3
- Version: 0.0.1a20
3
+ Version: 0.0.1a21
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -0,0 +1,36 @@
1
+ diracx/client/__init__.py,sha256=aLo7lP4xwlCtxs7MKD55gr2oDLQyWEvRHZVHwj5Sl2c,165
2
+ diracx/client/aio.py,sha256=gqVCOxYYl-q6hrz6dbhiT8kXuYWZfQeIQLHAHF9liI4,37
3
+ diracx/client/extensions.py,sha256=igHJAXhgpYQq-Di1ZOX2b2okqgjQHTs9HL8mBTHb6ss,3385
4
+ diracx/client/models.py,sha256=ToGTZHywDTtn-uw1woTLxNAcSw1eRCx2A_kr67ix2Hw,163
5
+ diracx/client/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
6
+ diracx/client/generated/__init__.py,sha256=nlsFCxdUj1egqs6PF6vmNpl8Dd4B5Q3ewsO0QdxqJNM,854
7
+ diracx/client/generated/_client.py,sha256=F8bgxclyyUdLUQ1Elob20q_kXrobov_IRT1KNn_YmdY,4831
8
+ diracx/client/generated/_configuration.py,sha256=-Edgj-iuZW5SXOcCdS7jiv6UFauzO0GItg2ZnLp_xpA,1936
9
+ diracx/client/generated/_patch.py,sha256=ZsuUeieEbKp0OjXJz2qAW-z6W0Xt8wwb38J-RvQxfNE,1328
10
+ diracx/client/generated/_serialization.py,sha256=xx1ZQCrGqaBTG6N7TNUFRw7FT09rzJhpl33o6M_Fi88,86947
11
+ diracx/client/generated/_vendor.py,sha256=7SFDHLgkg4kHcXdnQhP4AqRKTW3x0UCwRikNL2jLYJ0,1936
12
+ diracx/client/generated/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
13
+ diracx/client/generated/aio/__init__.py,sha256=nlsFCxdUj1egqs6PF6vmNpl8Dd4B5Q3ewsO0QdxqJNM,854
14
+ diracx/client/generated/aio/_client.py,sha256=L422ZtLs9A5rw9opXWEOwko-ZCL3TrtZtdmkUR03Mfc,4952
15
+ diracx/client/generated/aio/_configuration.py,sha256=oAz-SEZeCR4r-Rr0kxL44w56lRG1Gdw7iCIAC57CZDw,1968
16
+ diracx/client/generated/aio/_patch.py,sha256=6FYNV6Yt0ttTc7A5EQui764Ujuzypkjpv47LVdccmD8,697
17
+ diracx/client/generated/aio/_vendor.py,sha256=7SFDHLgkg4kHcXdnQhP4AqRKTW3x0UCwRikNL2jLYJ0,1936
18
+ diracx/client/generated/aio/operations/__init__.py,sha256=IdqXuE4gwqoRuocKXVW4jJGe8UtHfe-8WhCwn-ApVek,1070
19
+ diracx/client/generated/aio/operations/_operations.py,sha256=sMeIr-uvDuvT9qoU8NEyG5genE86uwNBnCKuaYhtiU4,68092
20
+ diracx/client/generated/aio/operations/_patch.py,sha256=3oHjHqBF7DXruMSVUTRxW0Xpv_mY1WaB8iyo47YBTec,4229
21
+ diracx/client/generated/models/__init__.py,sha256=Gjlh_zYz0ZAFpB1gqFvz8CdEzlGkLQKx25uoUJ1X-Gg,2512
22
+ diracx/client/generated/models/_enums.py,sha256=TEJYnmO0ax5GNhTb-qvUADe3wfLw-ji375Xn7Sgc7Ks,1738
23
+ diracx/client/generated/models/_models.py,sha256=UD4bVPgZRZpfTlb7ug9jvJyRBeVdqYDFKffRiMkC3BE,36407
24
+ diracx/client/generated/models/_patch.py,sha256=uvLwKzjWO_t-VZ4aSuLhuJ05RVxAP9UJxZV3XDeGMnU,1497
25
+ diracx/client/generated/operations/__init__.py,sha256=IdqXuE4gwqoRuocKXVW4jJGe8UtHfe-8WhCwn-ApVek,1070
26
+ diracx/client/generated/operations/_operations.py,sha256=xXzbVb8T6pyAaanYLuXprN4IhcYzPn1P-UNg8jdwp0w,84601
27
+ diracx/client/generated/operations/_patch.py,sha256=FvemlcswH_zZkdyoGObyTwRnwTsYIZJa3seO66C2BQI,4202
28
+ diracx/client/patches/__init__.py,sha256=8mzMyg1Kd9lJH1K7DYJ6FgjkTJgPRJmF0sYmuFv5wcs,468
29
+ diracx/client/patches/utils.py,sha256=7VaGp7IoAMMfotW3N9BrMb7h59mHjfkGgwFnLnIdNEs,10733
30
+ diracx/client/patches/aio/__init__.py,sha256=qIy1qj8HzaZDEU2PCjEHjFbylwfYRAM0i90WEDs2WuQ,471
31
+ diracx/client/patches/aio/utils.py,sha256=Bno4DntLGWEB88UO9eaBtZjG8K3QAJNaT2RI-_mQWgc,5949
32
+ diracx_client-0.0.1a21.dist-info/METADATA,sha256=MW4VLlkv77G0H-E7Osf03iCInid4Bdqv1txHeoICKn8,676
33
+ diracx_client-0.0.1a21.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
34
+ diracx_client-0.0.1a21.dist-info/entry_points.txt,sha256=NP67B7z-VIy8vEG3ZYtOAyxZqLtrOAD5hh2pA2AFBKI,123
35
+ diracx_client-0.0.1a21.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
36
+ diracx_client-0.0.1a21.dist-info/RECORD,,
@@ -1,36 +0,0 @@
1
- diracx/client/__init__.py,sha256=aLo7lP4xwlCtxs7MKD55gr2oDLQyWEvRHZVHwj5Sl2c,165
2
- diracx/client/aio.py,sha256=gqVCOxYYl-q6hrz6dbhiT8kXuYWZfQeIQLHAHF9liI4,37
3
- diracx/client/extensions.py,sha256=igHJAXhgpYQq-Di1ZOX2b2okqgjQHTs9HL8mBTHb6ss,3385
4
- diracx/client/models.py,sha256=ToGTZHywDTtn-uw1woTLxNAcSw1eRCx2A_kr67ix2Hw,163
5
- diracx/client/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
6
- diracx/client/generated/__init__.py,sha256=vJe8ZP3hLFwRK36KPA2n6P4ti0nOXJgrOAhxN6bRuzU,719
7
- diracx/client/generated/_client.py,sha256=e_LERq7nLIMtOUL84foK5S4kZAOF9mJlFOdAcdGCwDs,4831
8
- diracx/client/generated/_configuration.py,sha256=qzFZ089UDtXIYEClN5w6iJj0Hm72qy_FL0pJsXathfM,1936
9
- diracx/client/generated/_patch.py,sha256=ZsuUeieEbKp0OjXJz2qAW-z6W0Xt8wwb38J-RvQxfNE,1328
10
- diracx/client/generated/_serialization.py,sha256=4C5vtTgquShn3QH7J2QaSEukQIMLW67tfNoEdGvWn5k,86948
11
- diracx/client/generated/_vendor.py,sha256=M1s4hEh-jejSih4eDGzFu1MQkNyWQM5pmzMxyp0eBCE,1936
12
- diracx/client/generated/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
13
- diracx/client/generated/aio/__init__.py,sha256=vJe8ZP3hLFwRK36KPA2n6P4ti0nOXJgrOAhxN6bRuzU,719
14
- diracx/client/generated/aio/_client.py,sha256=ctZbEdAhSPJtDYWsbh8nfvbXI_C932xd58T0Mw0q-dk,4952
15
- diracx/client/generated/aio/_configuration.py,sha256=6V0bK2A8i_0Au-ojhZOSqYIgYTe3QkVyFADKygWWHDQ,1968
16
- diracx/client/generated/aio/_patch.py,sha256=6FYNV6Yt0ttTc7A5EQui764Ujuzypkjpv47LVdccmD8,697
17
- diracx/client/generated/aio/_vendor.py,sha256=M1s4hEh-jejSih4eDGzFu1MQkNyWQM5pmzMxyp0eBCE,1936
18
- diracx/client/generated/aio/operations/__init__.py,sha256=FcU_imELohqiaOtPzeopEEPTAXgsvrIqgXjFK6VmltU,887
19
- diracx/client/generated/aio/operations/_operations.py,sha256=JelQdNzyG5bBISE42vtbt0PL4E2iJLBXKONNMdxVhgM,95035
20
- diracx/client/generated/aio/operations/_patch.py,sha256=3oHjHqBF7DXruMSVUTRxW0Xpv_mY1WaB8iyo47YBTec,4229
21
- diracx/client/generated/models/__init__.py,sha256=dWjCnKAE_-4-biZ5yX9TTRZnKgtqh4psNmGOL5tFwwU,3129
22
- diracx/client/generated/models/_enums.py,sha256=5JfOHTo7OQXAHqaoRDwiyKI3LyS0sTgxetEJ0Wjk2_I,2389
23
- diracx/client/generated/models/_models.py,sha256=k-YMiEs8SO3ArL6Q5dcRWoW8faM_4I17MBQsdssSwa8,39708
24
- diracx/client/generated/models/_patch.py,sha256=uvLwKzjWO_t-VZ4aSuLhuJ05RVxAP9UJxZV3XDeGMnU,1497
25
- diracx/client/generated/operations/__init__.py,sha256=FcU_imELohqiaOtPzeopEEPTAXgsvrIqgXjFK6VmltU,887
26
- diracx/client/generated/operations/_operations.py,sha256=iXr64Yr519jJtLjjoWVM4FNtiaqqg9cAS2GSIlfS8Nw,119966
27
- diracx/client/generated/operations/_patch.py,sha256=FvemlcswH_zZkdyoGObyTwRnwTsYIZJa3seO66C2BQI,4202
28
- diracx/client/patches/__init__.py,sha256=8mzMyg1Kd9lJH1K7DYJ6FgjkTJgPRJmF0sYmuFv5wcs,468
29
- diracx/client/patches/utils.py,sha256=3HSRDgdv0Ssxe53lVRFp-qlXU0Gz5mse2EqXcVmL9a0,8978
30
- diracx/client/patches/aio/__init__.py,sha256=qIy1qj8HzaZDEU2PCjEHjFbylwfYRAM0i90WEDs2WuQ,471
31
- diracx/client/patches/aio/utils.py,sha256=smZhoXpqZaWh1GV34oJdNcLRgogZtkWPmflHPq49O3A,6986
32
- diracx_client-0.0.1a20.dist-info/METADATA,sha256=R20omnd-mfFWp-xo45anxzMM72tqbb9-boSqyA5yYzA,676
33
- diracx_client-0.0.1a20.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
34
- diracx_client-0.0.1a20.dist-info/entry_points.txt,sha256=NP67B7z-VIy8vEG3ZYtOAyxZqLtrOAD5hh2pA2AFBKI,123
35
- diracx_client-0.0.1a20.dist-info/top_level.txt,sha256=vJx10tdRlBX3rF2Psgk5jlwVGZNcL3m_7iQWwgPXt-U,7
36
- diracx_client-0.0.1a20.dist-info/RECORD,,