scim2-client 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl

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.
scim2_client/client.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import json.decoder
3
+ from typing import Dict
3
4
  from typing import List
4
5
  from typing import Optional
5
6
  from typing import Tuple
@@ -14,8 +15,10 @@ from scim2_models import Context
14
15
  from scim2_models import Error
15
16
  from scim2_models import ListResponse
16
17
  from scim2_models import PatchOp
18
+ from scim2_models import Resource
17
19
  from scim2_models import SearchRequest
18
20
 
21
+ from .errors import SCIMClientError
19
22
  from .errors import UnexpectedContentFormat
20
23
  from .errors import UnexpectedContentType
21
24
  from .errors import UnexpectedStatusCode
@@ -29,6 +32,71 @@ BASE_HEADERS = {
29
32
  class SCIMClient:
30
33
  """An object that perform SCIM requests and validate responses."""
31
34
 
35
+ CREATION_RESPONSE_STATUS_CODES: List[int] = [
36
+ 201,
37
+ 409,
38
+ 307,
39
+ 308,
40
+ 400,
41
+ 401,
42
+ 403,
43
+ 404,
44
+ 500,
45
+ ]
46
+ """Resource creation HTTP codes defined at :rfc:`RFC7644 §3.3
47
+ <7644#section-3.3>` and :rfc:`RFC7644 §3.12 <7644#section-3.12>`"""
48
+
49
+ QUERY_RESPONSE_STATUS_CODES: List[int] = [200, 400, 307, 308, 401, 403, 404, 500]
50
+ """Resource querying HTTP codes defined at :rfc:`RFC7644 §3.4.2
51
+ <7644#section-3.4.2>` and :rfc:`RFC7644 §3.12 <7644#section-3.12>`"""
52
+
53
+ SEARCH_RESPONSE_STATUS_CODES: List[int] = [
54
+ 200,
55
+ 307,
56
+ 308,
57
+ 400,
58
+ 401,
59
+ 403,
60
+ 404,
61
+ 409,
62
+ 413,
63
+ 500,
64
+ 501,
65
+ ]
66
+ """Resource querying HTTP codes defined at :rfc:`RFC7644 §3.4.3
67
+ <7644#section-3.4.3>` and :rfc:`RFC7644 §3.12 <7644#section-3.12>`"""
68
+
69
+ DELETION_RESPONSE_STATUS_CODES: List[int] = [
70
+ 204,
71
+ 307,
72
+ 308,
73
+ 400,
74
+ 401,
75
+ 403,
76
+ 404,
77
+ 412,
78
+ 500,
79
+ 501,
80
+ ]
81
+ """Resource deletion HTTP codes defined at :rfc:`RFC7644 §3.6
82
+ <7644#section-3.6>` and :rfc:`RFC7644 §3.12 <7644#section-3.12>`"""
83
+
84
+ REPLACEMENT_RESPONSE_STATUS_CODES: List[int] = [
85
+ 200,
86
+ 307,
87
+ 308,
88
+ 400,
89
+ 401,
90
+ 403,
91
+ 404,
92
+ 409,
93
+ 412,
94
+ 500,
95
+ 501,
96
+ ]
97
+ """Resource querying HTTP codes defined at :rfc:`RFC7644 §3.4.2
98
+ <7644#section-3.4.2>` and :rfc:`RFC7644 §3.12 <7644#section-3.12>`"""
99
+
32
100
  def __init__(self, client: Client, resource_types: Optional[Tuple[Type]] = None):
33
101
  self.client = client
34
102
  self.resource_types = resource_types or ()
@@ -47,7 +115,7 @@ class SCIMClient:
47
115
  expected_type: Optional[Type] = None,
48
116
  scim_ctx: Optional[Context] = None,
49
117
  ):
50
- if response.status_code not in expected_status_codes:
118
+ if expected_status_codes and response.status_code not in expected_status_codes:
51
119
  raise UnexpectedStatusCode(response)
52
120
 
53
121
  # Interoperability considerations: The "application/scim+json" media
@@ -64,7 +132,8 @@ class SCIMClient:
64
132
  # the errors in the body of the response in a JSON format
65
133
  # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
66
134
 
67
- if response.status_code in (204, 205):
135
+ no_content_status_codes = [204, 205]
136
+ if response.status_code in no_content_status_codes:
68
137
  response_payload = None
69
138
 
70
139
  else:
@@ -79,15 +148,32 @@ class SCIMClient:
79
148
  pass
80
149
 
81
150
  if expected_type:
82
- return expected_type.model_validate(response_payload, scim_ctx=scim_ctx)
151
+ try:
152
+ return expected_type.model_validate(response_payload, scim_ctx=scim_ctx)
153
+ except ValidationError as exc:
154
+ exc.response_payload = response_payload
155
+ raise exc
83
156
 
84
157
  return response_payload
85
158
 
86
- def create(self, resource: AnyResource, **kwargs) -> Union[AnyResource, Error]:
159
+ def create(
160
+ self,
161
+ resource: Union[AnyResource, Dict],
162
+ check_request_payload: bool = True,
163
+ check_response_payload: bool = True,
164
+ check_status_code: bool = True,
165
+ **kwargs,
166
+ ) -> Union[AnyResource, Error, Dict]:
87
167
  """Perform a POST request to create, as defined in :rfc:`RFC7644 §3.3
88
168
  <7644#section-3.3>`.
89
169
 
90
170
  :param resource: The resource to create
171
+ If is a :data:`dict`, the resource type will be guessed from the schema.
172
+ :param check_request_payload: If :data:`False`,
173
+ :code:`resource` is expected to be a dict that will be passed as-is in the request.
174
+ :param check_response_payload: Whether to validate that the response payload is valid.
175
+ If set, the raw payload will be returned.
176
+ :param check_status_code: Whether to validate that the response status code is valid.
91
177
  :param kwargs: Additional parameters passed to the underlying HTTP request
92
178
  library.
93
179
 
@@ -96,30 +182,35 @@ class SCIMClient:
96
182
  - The created object as returned by the server in case of success.
97
183
  """
98
184
 
99
- self.check_resource_type(resource.__class__)
100
- url = self.resource_endpoint(resource.__class__)
101
- dump = resource.model_dump(scim_ctx=Context.RESOURCE_CREATION_REQUEST)
102
- response = self.client.post(url, json=dump, **kwargs)
103
-
104
- expected_status_codes = [
105
- # Resource creation HTTP codes defined at:
106
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.3
107
- 201,
108
- 409,
109
- # Default HTTP codes defined at:
110
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
111
- 307,
112
- 308,
113
- 400,
114
- 401,
115
- 403,
116
- 404,
117
- 500,
118
- ]
185
+ if not check_request_payload:
186
+ payload = resource
187
+ url = kwargs.pop("url", None)
188
+
189
+ else:
190
+ if isinstance(resource, Resource):
191
+ resource_type = resource.__class__
192
+
193
+ else:
194
+ resource_type = Resource.get_by_payload(self.resource_types, resource)
195
+ if not resource_type:
196
+ raise SCIMClientError(
197
+ None, "Cannot guess resource type from the payload"
198
+ )
199
+
200
+ resource = resource_type.model_validate(resource)
201
+
202
+ self.check_resource_type(resource_type)
203
+ url = kwargs.pop("url", self.resource_endpoint(resource_type))
204
+ payload = resource.model_dump(scim_ctx=Context.RESOURCE_CREATION_REQUEST)
205
+
206
+ response = self.client.post(url, json=payload, **kwargs)
207
+
119
208
  return self.check_response(
120
209
  response,
121
- expected_status_codes,
122
- resource.__class__,
210
+ self.CREATION_RESPONSE_STATUS_CODES if check_status_code else None,
211
+ resource.__class__
212
+ if check_request_payload and check_response_payload
213
+ else None,
123
214
  scim_ctx=Context.RESOURCE_CREATION_RESPONSE,
124
215
  )
125
216
 
@@ -127,9 +218,12 @@ class SCIMClient:
127
218
  self,
128
219
  resource_type: Type,
129
220
  id: Optional[str] = None,
130
- search_request: Optional[SearchRequest] = None,
221
+ search_request: Optional[Union[SearchRequest, Dict]] = None,
222
+ check_request_payload: bool = True,
223
+ check_response_payload: bool = True,
224
+ check_status_code: bool = True,
131
225
  **kwargs,
132
- ) -> Union[AnyResource, ListResponse[AnyResource], Error]:
226
+ ) -> Union[AnyResource, ListResponse[AnyResource], Error, Dict]:
133
227
  """Perform a GET request to read resources, as defined in :rfc:`RFC7644
134
228
  §3.4.2 <7644#section-3.4.2>`.
135
229
 
@@ -139,6 +233,11 @@ class SCIMClient:
139
233
  :param resource_type: A :class:`~scim2_models.Resource` subtype or :data:`None`
140
234
  :param id: The SCIM id of an object to get, or :data:`None`
141
235
  :param search_request: An object detailing the search query parameters.
236
+ :param check_request_payload: If :data:`False`,
237
+ :code:`search_request` is expected to be a dict that will be passed as-is in the request.
238
+ :param check_response_payload: Whether to validate that the response payload is valid.
239
+ If set, the raw payload will be returned.
240
+ :param check_status_code: Whether to validate that the response status code is valid.
142
241
  :param kwargs: Additional parameters passed to the underlying HTTP request library.
143
242
 
144
243
  :return:
@@ -148,14 +247,18 @@ class SCIMClient:
148
247
  """
149
248
 
150
249
  self.check_resource_type(resource_type)
151
- payload = (
152
- search_request.model_dump(
153
- exclude_unset=True,
154
- scim_ctx=Context.RESOURCE_QUERY_REQUEST,
250
+ if not check_request_payload:
251
+ payload = search_request
252
+
253
+ else:
254
+ payload = (
255
+ search_request.model_dump(
256
+ exclude_unset=True,
257
+ scim_ctx=Context.RESOURCE_QUERY_REQUEST,
258
+ )
259
+ if search_request
260
+ else None
155
261
  )
156
- if search_request
157
- else None
158
- )
159
262
 
160
263
  if not id:
161
264
  expected_type = ListResponse[resource_type]
@@ -165,37 +268,31 @@ class SCIMClient:
165
268
  expected_type = resource_type
166
269
  url = self.resource_endpoint(resource_type) + f"/{id}"
167
270
 
168
- expected_status_codes = [
169
- # Resource querying HTTP codes defined at:
170
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2
171
- 200,
172
- 400,
173
- # Default HTTP codes defined at:
174
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
175
- 307,
176
- 308,
177
- 401,
178
- 403,
179
- 404,
180
- 500,
181
- ]
182
271
  response = self.client.get(url, params=payload, **kwargs)
183
272
  return self.check_response(
184
273
  response,
185
- expected_status_codes,
186
- expected_type,
274
+ self.QUERY_RESPONSE_STATUS_CODES if check_status_code else None,
275
+ expected_type if check_response_payload else None,
187
276
  scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
188
277
  )
189
278
 
190
279
  def query_all(
191
280
  self,
192
281
  search_request: Optional[SearchRequest] = None,
282
+ check_request_payload: bool = True,
283
+ check_response_payload: bool = True,
284
+ check_status_code: bool = True,
193
285
  **kwargs,
194
- ) -> Union[AnyResource, ListResponse[AnyResource], Error]:
286
+ ) -> Union[AnyResource, ListResponse[AnyResource], Error, Dict]:
195
287
  """Perform a GET request to read all available resources, as defined in
196
288
  :rfc:`RFC7644 §3.4.2.1 <7644#section-3.4.2.1>`.
197
289
 
198
290
  :param search_request: An object detailing the search query parameters.
291
+ :param check_request_payload: If :data:`False`,
292
+ :code:`search_request` is expected to be a dict that will be passed as-is in the request.
293
+ :param check_response_payload: Whether to validate that the response payload is valid.
294
+ If set, the raw payload will be returned.
295
+ :param check_status_code: Whether to validate that the response status code is valid.
199
296
  :param kwargs: Additional parameters passed to the underlying
200
297
  HTTP request library.
201
298
 
@@ -208,49 +305,48 @@ class SCIMClient:
208
305
  # server SHALL be included, subject to filtering.
209
306
  # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.4.2.1
210
307
 
211
- payload = (
212
- search_request.model_dump(
213
- exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_REQUEST
308
+ if not check_request_payload:
309
+ payload = search_request
310
+
311
+ else:
312
+ payload = (
313
+ search_request.model_dump(
314
+ exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_REQUEST
315
+ )
316
+ if search_request
317
+ else None
214
318
  )
215
- if search_request
216
- else None
217
- )
218
- response = self.client.get("/", params=payload)
219
319
 
220
- expected_status_codes = [
221
- # Resource querying HTTP codes defined at:
222
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2
223
- 200,
224
- 400,
225
- # Default HTTP codes defined at:
226
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
227
- 307,
228
- 308,
229
- 401,
230
- 403,
231
- 404,
232
- 500,
233
- 501,
234
- ]
320
+ response = self.client.get("/", params=payload)
235
321
 
236
322
  return self.check_response(
237
323
  response,
238
- expected_status_codes,
239
- ListResponse[Union[self.resource_types]],
324
+ self.QUERY_RESPONSE_STATUS_CODES if check_status_code else None,
325
+ ListResponse[Union[self.resource_types]]
326
+ if check_response_payload
327
+ else None,
240
328
  scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
241
329
  )
242
330
 
243
331
  def search(
244
332
  self,
245
333
  search_request: Optional[SearchRequest] = None,
334
+ check_request_payload: bool = True,
335
+ check_response_payload: bool = True,
336
+ check_status_code: bool = True,
246
337
  **kwargs,
247
- ) -> Union[AnyResource, ListResponse[AnyResource], Error]:
338
+ ) -> Union[AnyResource, ListResponse[AnyResource], Error, Dict]:
248
339
  """Perform a POST search request to read all available resources, as
249
340
  defined in :rfc:`RFC7644 §3.4.3 <7644#section-3.4.3>`.
250
341
 
251
342
  :param resource_types: Resource type or union of types expected
252
343
  to be read from the response.
253
344
  :param search_request: An object detailing the search query parameters.
345
+ :param check_request_payload: If :data:`False`,
346
+ :code:`search_request` is expected to be a dict that will be passed as-is in the request.
347
+ :param check_response_payload: Whether to validate that the response payload is valid.
348
+ If set, the raw payload will be returned.
349
+ :param check_status_code: Whether to validate that the response status code is valid.
254
350
  :param kwargs: Additional parameters passed to the underlying
255
351
  HTTP request library.
256
352
 
@@ -259,43 +355,36 @@ class SCIMClient:
259
355
  - A :class:`~scim2_models.ListResponse[resource_type]` object in case of success.
260
356
  """
261
357
 
262
- payload = (
263
- search_request.model_dump(
264
- exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_RESPONSE
358
+ if not check_request_payload:
359
+ payload = search_request
360
+
361
+ else:
362
+ payload = (
363
+ search_request.model_dump(
364
+ exclude_unset=True, scim_ctx=Context.RESOURCE_QUERY_RESPONSE
365
+ )
366
+ if search_request
367
+ else None
265
368
  )
266
- if search_request
267
- else None
268
- )
269
- response = self.client.post("/.search", params=payload)
270
-
271
- expected_status_codes = [
272
- # Resource querying HTTP codes defined at:
273
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.3
274
- 200,
275
- # Default HTTP codes defined at:
276
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
277
- 307,
278
- 308,
279
- 400,
280
- 401,
281
- 403,
282
- 404,
283
- 409,
284
- 413,
285
- 500,
286
- 501,
287
- ]
369
+
370
+ response = self.client.post("/.search", json=payload)
371
+
288
372
  return self.check_response(
289
373
  response,
290
- expected_status_codes,
291
- ListResponse[Union[self.resource_types]],
374
+ self.SEARCH_RESPONSE_STATUS_CODES if check_status_code else None,
375
+ ListResponse[Union[self.resource_types]]
376
+ if check_response_payload
377
+ else None,
292
378
  scim_ctx=Context.RESOURCE_QUERY_RESPONSE,
293
379
  )
294
380
 
295
- def delete(self, resource_type: Type, id: str, **kwargs) -> Optional[Error]:
381
+ def delete(
382
+ self, resource_type: Type, id: str, check_status_code: bool = True, **kwargs
383
+ ) -> Optional[Union[Error, Dict]]:
296
384
  """Perform a DELETE request to create, as defined in :rfc:`RFC7644 §3.6
297
385
  <7644#section-3.6>`.
298
386
 
387
+ :param check_status_code: Whether to validate that the response status code is valid.
299
388
  :param kwargs: Additional parameters passed to the underlying
300
389
  HTTP request library.
301
390
 
@@ -308,29 +397,28 @@ class SCIMClient:
308
397
  url = self.resource_endpoint(resource_type) + f"/{id}"
309
398
  response = self.client.delete(url, **kwargs)
310
399
 
311
- expected_status_codes = [
312
- # Resource deletion HTTP codes defined at:
313
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.6
314
- 204,
315
- # Default HTTP codes defined at:
316
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
317
- 307,
318
- 308,
319
- 400,
320
- 401,
321
- 403,
322
- 404,
323
- 412,
324
- 500,
325
- 501,
326
- ]
327
- return self.check_response(response, expected_status_codes)
328
-
329
- def replace(self, resource: AnyResource, **kwargs) -> Union[AnyResource, Error]:
400
+ return self.check_response(
401
+ response, self.DELETION_RESPONSE_STATUS_CODES if check_status_code else None
402
+ )
403
+
404
+ def replace(
405
+ self,
406
+ resource: Union[AnyResource, Dict],
407
+ check_request_payload: bool = True,
408
+ check_response_payload: bool = True,
409
+ check_status_code: bool = True,
410
+ **kwargs,
411
+ ) -> Union[AnyResource, Error, Dict]:
330
412
  """Perform a PUT request to replace a resource, as defined in
331
413
  :rfc:`RFC7644 §3.5.1 <7644#section-3.5.1>`.
332
414
 
333
- :param resource: The new state of the resource to replace.
415
+ :param resource: The new resource to replace.
416
+ If is a :data:`dict`, the resource type will be guessed from the schema.
417
+ :param check_request_payload: If :data:`False`,
418
+ :code:`resource` is expected to be a dict that will be passed as-is in the request.
419
+ :param check_response_payload: Whether to validate that the response payload is valid.
420
+ If set, the raw payload will be returned.
421
+ :param check_status_code: Whether to validate that the response status code is valid.
334
422
  :param kwargs: Additional parameters passed to the underlying
335
423
  HTTP request library.
336
424
 
@@ -339,39 +427,45 @@ class SCIMClient:
339
427
  - The updated object as returned by the server in case of success.
340
428
  """
341
429
 
342
- self.check_resource_type(resource.__class__)
343
- if not resource.id:
344
- raise Exception("Resource must have an id")
345
-
346
- dump = resource.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_REQUEST)
347
- url = self.resource_endpoint(resource.__class__) + f"/{resource.id}"
348
- response = self.client.put(url, json=dump, **kwargs)
349
-
350
- expected_status_codes = [
351
- # Resource querying HTTP codes defined at:
352
- # https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2
353
- 200,
354
- # Default HTTP codes defined at:
355
- # https://datatracker.ietf.org/doc/html/rfc7644.html#section-3.12
356
- 307,
357
- 308,
358
- 400,
359
- 401,
360
- 403,
361
- 404,
362
- 409,
363
- 412,
364
- 500,
365
- 501,
366
- ]
430
+ if not check_request_payload:
431
+ payload = resource
432
+ url = kwargs.pop("url", None)
433
+
434
+ else:
435
+ if isinstance(resource, Resource):
436
+ resource_type = resource.__class__
437
+
438
+ else:
439
+ resource_type = Resource.get_by_payload(self.resource_types, resource)
440
+ if not resource_type:
441
+ raise SCIMClientError(
442
+ None, "Cannot guess resource type from the payload"
443
+ )
444
+
445
+ resource = resource_type.model_validate(resource)
446
+
447
+ self.check_resource_type(resource_type)
448
+
449
+ if not resource.id:
450
+ raise SCIMClientError(None, "Resource must have an id")
451
+
452
+ payload = resource.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_REQUEST)
453
+ url = kwargs.pop(
454
+ "url", self.resource_endpoint(resource.__class__) + f"/{resource.id}"
455
+ )
456
+
457
+ response = self.client.put(url, json=payload, **kwargs)
458
+
367
459
  return self.check_response(
368
460
  response,
369
- expected_status_codes,
370
- resource.__class__,
461
+ self.REPLACEMENT_RESPONSE_STATUS_CODES if check_status_code else None,
462
+ resource.__class__
463
+ if check_request_payload and check_response_payload
464
+ else None,
371
465
  scim_ctx=Context.RESOURCE_REPLACEMENT_RESPONSE,
372
466
  )
373
467
 
374
468
  def modify(
375
- self, resource: AnyResource, op: PatchOp, **kwargs
376
- ) -> Optional[AnyResource]:
469
+ self, resource: Union[AnyResource, Dict], op: PatchOp, **kwargs
470
+ ) -> Optional[Union[AnyResource, Dict]]:
377
471
  raise NotImplementedError()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scim2-client
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: Pythonically build SCIM requests and parse SCIM responses
5
5
  License: MIT
6
6
  Keywords: scim,scim2,provisioning,httpx,api
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: Implementation :: CPython
22
22
  Requires-Dist: httpx (>=0.27.0,<0.28.0)
23
- Requires-Dist: scim2-models (>=0.1.1,<0.2.0)
23
+ Requires-Dist: scim2-models (>=0.1.2,<0.2.0)
24
24
  Description-Content-Type: text/markdown
25
25
 
26
26
  # scim2-client
@@ -42,7 +42,7 @@ Here is an example of usage:
42
42
 
43
43
  ```python
44
44
  import datetime
45
- from httpx impont Client
45
+ from httpx import Client
46
46
  from scim2_models import User, EnterpriseUserUser, Group, Error
47
47
  from scim2_client import SCIMClient
48
48
 
@@ -0,0 +1,6 @@
1
+ scim2_client/__init__.py,sha256=2UNsl6HNtVUv5LVcnmLaCHyT4SqAUUFOIWW2r5XGv6A,338
2
+ scim2_client/client.py,sha256=1l7vb_OUPNzs-LP_yCmPEBafx3iwo1kgUNmWiucUDMc,17669
3
+ scim2_client/errors.py,sha256=uOOAwsD8rDrC8BQbwPid051YyWtexTcS8b7i6QC6-CM,1175
4
+ scim2_client-0.1.3.dist-info/METADATA,sha256=JxLH05nejwpIVxPOWwdsnujJed-D3ZwFPHwP9an-qc4,2654
5
+ scim2_client-0.1.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
6
+ scim2_client-0.1.3.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- scim2_client/__init__.py,sha256=2UNsl6HNtVUv5LVcnmLaCHyT4SqAUUFOIWW2r5XGv6A,338
2
- scim2_client/client.py,sha256=LsG_omH6Mz4mxcqLLA6ApnVJqInAWo8GjaVRXuyf08c,13199
3
- scim2_client/errors.py,sha256=uOOAwsD8rDrC8BQbwPid051YyWtexTcS8b7i6QC6-CM,1175
4
- scim2_client-0.1.1.dist-info/METADATA,sha256=s1A7Uk7fz_9n0PgU7V2EqxGZMEonmfCzVod5a7l_sJ4,2654
5
- scim2_client-0.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
6
- scim2_client-0.1.1.dist-info/RECORD,,