csu 2.3.5__tar.gz → 2.4.0__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.
- {csu-2.3.5 → csu-2.4.0}/.bumpversion.cfg +1 -1
- {csu-2.3.5 → csu-2.4.0}/.cookiecutterrc +1 -1
- {csu-2.3.5 → csu-2.4.0}/.pre-commit-config.yaml +2 -2
- {csu-2.3.5 → csu-2.4.0}/PKG-INFO +3 -3
- {csu-2.3.5 → csu-2.4.0}/README.rst +2 -2
- {csu-2.3.5 → csu-2.4.0}/pyproject.toml +1 -1
- {csu-2.3.5 → csu-2.4.0}/src/csu/__init__.py +1 -1
- {csu-2.3.5 → csu-2.4.0}/src/csu/service.py +44 -39
- {csu-2.3.5 → csu-2.4.0}/src/csu.egg-info/PKG-INFO +3 -3
- {csu-2.3.5 → csu-2.4.0}/src/csu.egg-info/SOURCES.txt +2 -0
- csu-2.4.0/tests/cassettes/test_service_auth/test_async_auth.yaml +110 -0
- csu-2.4.0/tests/cassettes/test_service_auth/test_sync_auth.yaml +146 -0
- csu-2.4.0/tests/conftest.py +186 -0
- {csu-2.3.5 → csu-2.4.0}/tests/test_service.py +15 -36
- {csu-2.3.5 → csu-2.4.0}/tests/test_service_auth.py +114 -10
- csu-2.3.5/tests/conftest.py +0 -56
- {csu-2.3.5 → csu-2.4.0}/.coveragerc +0 -0
- {csu-2.3.5 → csu-2.4.0}/.editorconfig +0 -0
- {csu-2.3.5 → csu-2.4.0}/.github/workflows/github-actions.yml +0 -0
- {csu-2.3.5 → csu-2.4.0}/.tombi.toml +0 -0
- {csu-2.3.5 → csu-2.4.0}/AUTHORS.rst +0 -0
- {csu-2.3.5 → csu-2.4.0}/CHANGELOG.rst +0 -0
- {csu-2.3.5 → csu-2.4.0}/CONTRIBUTING.rst +0 -0
- {csu-2.3.5 → csu-2.4.0}/LICENSE +0 -0
- {csu-2.3.5 → csu-2.4.0}/MANIFEST.in +0 -0
- {csu-2.3.5 → csu-2.4.0}/ci/bootstrap.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/ci/requirements.txt +0 -0
- {csu-2.3.5 → csu-2.4.0}/ci/templates/.github/workflows/github-actions.yml +0 -0
- {csu-2.3.5 → csu-2.4.0}/pytest.ini +0 -0
- {csu-2.3.5 → csu-2.4.0}/setup.cfg +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/admin.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/conf.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/consts.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/__init__.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/auth.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/fields.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/forms.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/perms.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/phonenumber.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/serializers.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/test_auth.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/test_fields.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/test_forms.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/test_phonenumber.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/test_serializers.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/drf/views.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/enums.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/env.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/exceptions.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/export.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/fixups.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/forms/__init__.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/forms/crispy.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/forms/fields.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/gettext.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/gettext_lazy.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/locale/ro/LC_MESSAGES/django.mo +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/locale/ro/LC_MESSAGES/django.po +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/logging.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/management.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/models.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/query.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/routers.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/templates/api_exception.html +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/templates/forms/widgets/opaquewidget.html +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_consts.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_env.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_exceptions.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_logging.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_management.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_service.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_timezones.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_utils.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/test_xml.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/timezones.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/utils.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/views.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/__init__.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/admin.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/asgi.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/engine.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/enums.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/job.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/models.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/worker/registry.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/wsgi.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu/xml.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu.egg-info/dependency_links.txt +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu.egg-info/requires.txt +0 -0
- {csu-2.3.5 → csu-2.4.0}/src/csu.egg-info/top_level.txt +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_custom_context.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_custom_context_0_retries.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_decoding.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_error.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_logging.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service/test_redirects.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service_auth/test_async.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/cassettes/test_service_auth/test_sync.yaml +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/exampleworker.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/test_exampleworker.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/test_models.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/test_views.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/test_worker.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/testproject/__init__.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/testproject/fixtures/testuser.json +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/testproject/models.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/testproject/settings.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tests/testproject/urls.py +0 -0
- {csu-2.3.5 → csu-2.4.0}/tox.ini +0 -0
|
@@ -11,14 +11,14 @@ repos:
|
|
|
11
11
|
- id: django-upgrade
|
|
12
12
|
args: [ --target-version, "5.2" ]
|
|
13
13
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
14
|
-
rev: v0.15.
|
|
14
|
+
rev: v0.15.17
|
|
15
15
|
hooks:
|
|
16
16
|
- id: ruff
|
|
17
17
|
# Using --unsafe-fixes can change code behavior
|
|
18
18
|
args: [--fix, --exit-non-zero-on-fix, --show-fixes, --unsafe-fixes]
|
|
19
19
|
- id: ruff-format
|
|
20
20
|
- repo: https://github.com/tombi-toml/tombi-pre-commit
|
|
21
|
-
rev:
|
|
21
|
+
rev: v1.1.2
|
|
22
22
|
hooks:
|
|
23
23
|
- id: tombi-format
|
|
24
24
|
# args: [ "--offline" ]
|
{csu-2.3.5 → csu-2.4.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -69,9 +69,9 @@ Overview
|
|
|
69
69
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
70
70
|
:alt: Supported implementations
|
|
71
71
|
:target: https://pypi.org/project/csu
|
|
72
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.
|
|
72
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.4.0.svg
|
|
73
73
|
:alt: Commits since latest release
|
|
74
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.
|
|
74
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.4.0...main
|
|
75
75
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
76
76
|
:alt: Scrutinizer Status
|
|
77
77
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -34,9 +34,9 @@ Overview
|
|
|
34
34
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
35
35
|
:alt: Supported implementations
|
|
36
36
|
:target: https://pypi.org/project/csu
|
|
37
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.
|
|
37
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.4.0.svg
|
|
38
38
|
:alt: Commits since latest release
|
|
39
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.
|
|
39
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.4.0...main
|
|
40
40
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
41
41
|
:alt: Scrutinizer Status
|
|
42
42
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -165,7 +165,7 @@ class HTTPServiceContext[RTYPE = HTTPServiceResponse]:
|
|
|
165
165
|
self.handle_log_response(response, response.content)
|
|
166
166
|
|
|
167
167
|
def handle_log_response(self, response: Response | AsyncResponse, content):
|
|
168
|
-
size = len(content)
|
|
168
|
+
size = len(content) if content else 0
|
|
169
169
|
content_type = response.headers.get("content-type")
|
|
170
170
|
content_type = "no content-type" if content_type is None else repr(content_type)
|
|
171
171
|
response_line = f" response body ({content_type} - {size} bytes) ".center(LINE_LENGTH, "-")
|
|
@@ -215,19 +215,14 @@ class HTTPServiceContext[RTYPE = HTTPServiceResponse]:
|
|
|
215
215
|
else:
|
|
216
216
|
self.logger.warning("[%s] __exit__ !> %r", self.short_id, exc_val)
|
|
217
217
|
|
|
218
|
-
def handle_process_response(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if response.status_code in retry_statuses:
|
|
227
|
-
raise RetryableStatusError(response, accept_statuses, retry_statuses, event_id=self.event_id)
|
|
228
|
-
elif response.status_code not in accept_statuses:
|
|
229
|
-
raise UnexpectedStatusError(response, accept_statuses, event_id=self.event_id)
|
|
230
|
-
|
|
218
|
+
def handle_process_response(self, response: Response, *, expect_json: bool) -> RTYPE:
|
|
219
|
+
if expect_json:
|
|
220
|
+
try:
|
|
221
|
+
json = response.json(parse_float=Decimal)
|
|
222
|
+
except Exception as exc:
|
|
223
|
+
raise DecodeError(response, exc, event_id=self.event_id) from exc
|
|
224
|
+
else:
|
|
225
|
+
json = None
|
|
231
226
|
return HTTPServiceResponse(
|
|
232
227
|
status=response.status_code,
|
|
233
228
|
http_response=response,
|
|
@@ -300,14 +295,11 @@ class HTTPServiceContext[RTYPE = HTTPServiceResponse]:
|
|
|
300
295
|
try:
|
|
301
296
|
self.log_request(prepared_request)
|
|
302
297
|
response = self.client.send(prepared_request, timeout=self.client.timeout, allow_redirects=follow_redirects, **settings)
|
|
303
|
-
if
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
else:
|
|
309
|
-
json = None
|
|
310
|
-
return self.handle_process_response(response, retry_statuses=retry_statuses, accept_statuses=accept_statuses, json=json)
|
|
298
|
+
if response.status_code in retry_statuses:
|
|
299
|
+
raise RetryableStatusError(response, accept_statuses, retry_statuses, event_id=self.event_id)
|
|
300
|
+
elif response.status_code not in accept_statuses:
|
|
301
|
+
raise UnexpectedStatusError(response, accept_statuses, event_id=self.event_id)
|
|
302
|
+
return self.handle_process_response(response, expect_json=expect_json)
|
|
311
303
|
except (RequestError, RetryableError) as exc:
|
|
312
304
|
retry_failures.append(exc)
|
|
313
305
|
self.handle_retriable_failure(method, prepared_request.url, exc, retries_left, retry_budget)
|
|
@@ -321,7 +313,7 @@ class HTTPServiceContext[RTYPE = HTTPServiceResponse]:
|
|
|
321
313
|
raise ExhaustedRetriesError(retry_budget, retry_failures, event_id=self.event_id)
|
|
322
314
|
|
|
323
315
|
|
|
324
|
-
class AsyncHTTPServiceContext[
|
|
316
|
+
class AsyncHTTPServiceContext[RTYPE = HTTPServiceResponse](HTTPServiceContext[RTYPE]):
|
|
325
317
|
auth_class = AsyncHTTPServiceAuth
|
|
326
318
|
client_class = AsyncSession
|
|
327
319
|
client: AsyncSession
|
|
@@ -334,7 +326,7 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
334
326
|
async def log_request(self, request: PreparedRequest):
|
|
335
327
|
self.handle_log_request(request)
|
|
336
328
|
|
|
337
|
-
async def log_response(self, response: AsyncResponse | Response):
|
|
329
|
+
async def log_response(self, response: AsyncResponse | Response, **kwargs):
|
|
338
330
|
if isinstance(response, AsyncResponse):
|
|
339
331
|
content = await response.content
|
|
340
332
|
else:
|
|
@@ -345,6 +337,24 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
345
337
|
await self.client.__aexit__(exc_type, exc_val, exc_tb)
|
|
346
338
|
self.handle_exit(exc_type, exc_val, exc_tb)
|
|
347
339
|
|
|
340
|
+
async def handle_process_response(self, response: Response, *, expect_json: bool) -> RTYPE:
|
|
341
|
+
if expect_json:
|
|
342
|
+
try:
|
|
343
|
+
if isinstance(response, AsyncResponse):
|
|
344
|
+
json = await response.json(parse_float=Decimal)
|
|
345
|
+
else:
|
|
346
|
+
json = response.json(parse_float=Decimal)
|
|
347
|
+
except Exception as exc:
|
|
348
|
+
raise DecodeError(response, exc, event_id=self.event_id) from exc
|
|
349
|
+
else:
|
|
350
|
+
json = None
|
|
351
|
+
return HTTPServiceResponse(
|
|
352
|
+
status=response.status_code,
|
|
353
|
+
http_response=response,
|
|
354
|
+
json=json,
|
|
355
|
+
event_id=self.event_id,
|
|
356
|
+
)
|
|
357
|
+
|
|
348
358
|
async def request(
|
|
349
359
|
self,
|
|
350
360
|
method,
|
|
@@ -360,7 +370,7 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
360
370
|
verify: TLSVerifyType | None = None,
|
|
361
371
|
cert: TLSClientCertType | None = None,
|
|
362
372
|
**kwargs,
|
|
363
|
-
) ->
|
|
373
|
+
) -> RTYPE:
|
|
364
374
|
retry_statuses = set(retry_statuses)
|
|
365
375
|
accept_statuses = set(accept_statuses)
|
|
366
376
|
assert not (common := sorted(retry_statuses & accept_statuses)), f"{common} is in both retry_statuses and accept_statuses!"
|
|
@@ -379,7 +389,7 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
379
389
|
**kwargs,
|
|
380
390
|
)
|
|
381
391
|
if prepared_request._asynchronous_auth:
|
|
382
|
-
# needs a solution
|
|
392
|
+
# needs a solution without internals coupling
|
|
383
393
|
r = await prepared_request._pending_async_auth(prepared_request)
|
|
384
394
|
prepared_request.__dict__.update(r.__dict__)
|
|
385
395
|
prepared_request.prepare_content_length(prepared_request.body)
|
|
@@ -390,17 +400,11 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
390
400
|
try:
|
|
391
401
|
await self.log_request(prepared_request)
|
|
392
402
|
response = await self.client.send(prepared_request, timeout=self.client.timeout, allow_redirects=follow_redirects, **settings)
|
|
393
|
-
if
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
json = response.json(parse_float=Decimal)
|
|
399
|
-
except Exception as exc:
|
|
400
|
-
raise DecodeError(response, exc, event_id=self.event_id) from exc
|
|
401
|
-
else:
|
|
402
|
-
json = None
|
|
403
|
-
return self.handle_process_response(response, retry_statuses=retry_statuses, accept_statuses=accept_statuses, json=json)
|
|
403
|
+
if response.status_code in retry_statuses:
|
|
404
|
+
raise RetryableStatusError(response, accept_statuses, retry_statuses, event_id=self.event_id)
|
|
405
|
+
elif response.status_code not in accept_statuses:
|
|
406
|
+
raise UnexpectedStatusError(response, accept_statuses, event_id=self.event_id)
|
|
407
|
+
return await self.handle_process_response(response, expect_json=expect_json)
|
|
404
408
|
except (RequestError, RetryableError) as exc:
|
|
405
409
|
retry_failures.append(exc)
|
|
406
410
|
self.handle_retriable_failure(method, prepared_request.url, exc, retries_left, retry_budget)
|
|
@@ -416,6 +420,7 @@ class AsyncHTTPServiceContext[RT = HTTPServiceResponse](HTTPServiceContext[RT]):
|
|
|
416
420
|
|
|
417
421
|
class HTTPService[CT = HTTPServiceContext]:
|
|
418
422
|
context_class: type[CT] = HTTPServiceContext
|
|
423
|
+
context_defaults: dict = {}
|
|
419
424
|
logger_name: str = "service"
|
|
420
425
|
logger: Logger
|
|
421
426
|
base_url: str
|
|
@@ -442,7 +447,7 @@ class HTTPService[CT = HTTPServiceContext]:
|
|
|
442
447
|
)
|
|
443
448
|
|
|
444
449
|
def context(self, **kwargs) -> CT:
|
|
445
|
-
return self.context_class(self, **kwargs)
|
|
450
|
+
return self.context_class(self, **self.context_defaults, **kwargs)
|
|
446
451
|
|
|
447
452
|
def auth(self, request: PreparedRequest, context: CT) -> PreparedRequest:
|
|
448
453
|
return request
|
|
@@ -452,7 +457,7 @@ class AsyncHTTPService[ACT = AsyncHTTPServiceContext](HTTPService[ACT]):
|
|
|
452
457
|
context_class: type[AsyncHTTPServiceContext] = AsyncHTTPServiceContext
|
|
453
458
|
|
|
454
459
|
def context(self, **kwargs) -> ACT:
|
|
455
|
-
return self.context_class(self, **kwargs)
|
|
460
|
+
return self.context_class(self, **self.context_defaults, **kwargs)
|
|
456
461
|
|
|
457
462
|
async def auth(self, request: PreparedRequest, context: ACT) -> PreparedRequest:
|
|
458
463
|
return request
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csu
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Clean Slate Utils - bunch of utility code, mostly Django/DRF specific.
|
|
5
5
|
Author-email: Ionel Cristian Mărieș <contact@ionelmc.ro>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -69,9 +69,9 @@ Overview
|
|
|
69
69
|
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/csu.svg
|
|
70
70
|
:alt: Supported implementations
|
|
71
71
|
:target: https://pypi.org/project/csu
|
|
72
|
-
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.
|
|
72
|
+
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.4.0.svg
|
|
73
73
|
:alt: Commits since latest release
|
|
74
|
-
:target: https://github.com/ionelmc/python-csu/compare/v2.
|
|
74
|
+
:target: https://github.com/ionelmc/python-csu/compare/v2.4.0...main
|
|
75
75
|
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/quality/g/ionelmc/python-csu/main.svg
|
|
76
76
|
:alt: Scrutinizer Status
|
|
77
77
|
:target: https://scrutinizer-ci.com/g/ionelmc/python-csu/
|
|
@@ -96,7 +96,9 @@ tests/cassettes/test_service/test_error.yaml
|
|
|
96
96
|
tests/cassettes/test_service/test_logging.yaml
|
|
97
97
|
tests/cassettes/test_service/test_redirects.yaml
|
|
98
98
|
tests/cassettes/test_service_auth/test_async.yaml
|
|
99
|
+
tests/cassettes/test_service_auth/test_async_auth.yaml
|
|
99
100
|
tests/cassettes/test_service_auth/test_sync.yaml
|
|
101
|
+
tests/cassettes/test_service_auth/test_sync_auth.yaml
|
|
100
102
|
tests/testproject/__init__.py
|
|
101
103
|
tests/testproject/models.py
|
|
102
104
|
tests/testproject/settings.py
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
interactions:
|
|
2
|
+
- request:
|
|
3
|
+
body: null
|
|
4
|
+
headers:
|
|
5
|
+
Accept:
|
|
6
|
+
- '*/*'
|
|
7
|
+
Accept-Encoding:
|
|
8
|
+
- gzip, deflate, br
|
|
9
|
+
Authorization:
|
|
10
|
+
- Basic dXNyOnB3ZA==
|
|
11
|
+
Connection:
|
|
12
|
+
- keep-alive
|
|
13
|
+
User-Agent:
|
|
14
|
+
- niquests/3.18.6
|
|
15
|
+
method: GET
|
|
16
|
+
uri: http://127.0.0.1:37027/basic-auth/usr/pwd
|
|
17
|
+
response:
|
|
18
|
+
body:
|
|
19
|
+
string: "{\n \"authenticated\": true,\n \"user\": \"usr\"\n}\n"
|
|
20
|
+
headers:
|
|
21
|
+
Access-Control-Allow-Credentials:
|
|
22
|
+
- 'true'
|
|
23
|
+
Access-Control-Allow-Origin:
|
|
24
|
+
- '*'
|
|
25
|
+
Connection:
|
|
26
|
+
- Close
|
|
27
|
+
Content-Length:
|
|
28
|
+
- '45'
|
|
29
|
+
Content-Type:
|
|
30
|
+
- application/json
|
|
31
|
+
Date:
|
|
32
|
+
- Wed, 17 Jun 2026 16:14:27 GMT
|
|
33
|
+
Server:
|
|
34
|
+
- Pytest-HTTPBIN/0.1.0
|
|
35
|
+
status:
|
|
36
|
+
code: 200
|
|
37
|
+
message: OK
|
|
38
|
+
- request:
|
|
39
|
+
body: null
|
|
40
|
+
headers:
|
|
41
|
+
Accept:
|
|
42
|
+
- '*/*'
|
|
43
|
+
Accept-Encoding:
|
|
44
|
+
- gzip, deflate, br
|
|
45
|
+
Authorization:
|
|
46
|
+
- Basic dXNyOnB3ZA==
|
|
47
|
+
Connection:
|
|
48
|
+
- keep-alive
|
|
49
|
+
User-Agent:
|
|
50
|
+
- niquests/3.18.6
|
|
51
|
+
method: GET
|
|
52
|
+
uri: http://127.0.0.1:40371/basic-auth/usr/pwd
|
|
53
|
+
response:
|
|
54
|
+
body:
|
|
55
|
+
string: "{\n \"authenticated\": true,\n \"user\": \"usr\"\n}\n"
|
|
56
|
+
headers:
|
|
57
|
+
Access-Control-Allow-Credentials:
|
|
58
|
+
- 'true'
|
|
59
|
+
Access-Control-Allow-Origin:
|
|
60
|
+
- '*'
|
|
61
|
+
Connection:
|
|
62
|
+
- Close
|
|
63
|
+
Content-Length:
|
|
64
|
+
- '45'
|
|
65
|
+
Content-Type:
|
|
66
|
+
- application/json
|
|
67
|
+
Date:
|
|
68
|
+
- Wed, 17 Jun 2026 16:25:16 GMT
|
|
69
|
+
Server:
|
|
70
|
+
- Pytest-HTTPBIN/0.1.0
|
|
71
|
+
status:
|
|
72
|
+
code: 200
|
|
73
|
+
message: OK
|
|
74
|
+
- request:
|
|
75
|
+
body: null
|
|
76
|
+
headers:
|
|
77
|
+
Accept:
|
|
78
|
+
- '*/*'
|
|
79
|
+
Accept-Encoding:
|
|
80
|
+
- gzip, deflate, br
|
|
81
|
+
Authorization:
|
|
82
|
+
- Basic dXNyOnB3ZA==
|
|
83
|
+
Connection:
|
|
84
|
+
- keep-alive
|
|
85
|
+
User-Agent:
|
|
86
|
+
- niquests/3.18.6
|
|
87
|
+
method: GET
|
|
88
|
+
uri: http://127.0.0.1:38445/basic-auth/quite/bad
|
|
89
|
+
response:
|
|
90
|
+
body:
|
|
91
|
+
string: ''
|
|
92
|
+
headers:
|
|
93
|
+
Access-Control-Allow-Credentials:
|
|
94
|
+
- 'true'
|
|
95
|
+
Access-Control-Allow-Origin:
|
|
96
|
+
- '*'
|
|
97
|
+
Connection:
|
|
98
|
+
- Close
|
|
99
|
+
Content-Length:
|
|
100
|
+
- '0'
|
|
101
|
+
Date:
|
|
102
|
+
- Wed, 17 Jun 2026 16:25:39 GMT
|
|
103
|
+
Server:
|
|
104
|
+
- Pytest-HTTPBIN/0.1.0
|
|
105
|
+
WWW-Authenticate:
|
|
106
|
+
- Basic realm="Fake Realm"
|
|
107
|
+
status:
|
|
108
|
+
code: 401
|
|
109
|
+
message: Unauthorized
|
|
110
|
+
version: 1
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
interactions:
|
|
2
|
+
- request:
|
|
3
|
+
body: null
|
|
4
|
+
headers:
|
|
5
|
+
Accept:
|
|
6
|
+
- '*/*'
|
|
7
|
+
Accept-Encoding:
|
|
8
|
+
- gzip, deflate, br
|
|
9
|
+
Authorization:
|
|
10
|
+
- Basic dXNyOnB3ZA==
|
|
11
|
+
Connection:
|
|
12
|
+
- keep-alive
|
|
13
|
+
User-Agent:
|
|
14
|
+
- niquests/3.18.6
|
|
15
|
+
method: GET
|
|
16
|
+
uri: http://127.0.0.1:37027/basic-auth/usr/pwd
|
|
17
|
+
response:
|
|
18
|
+
body:
|
|
19
|
+
string: "{\n \"authenticated\": true,\n \"user\": \"usr\"\n}\n"
|
|
20
|
+
headers:
|
|
21
|
+
Access-Control-Allow-Credentials:
|
|
22
|
+
- 'true'
|
|
23
|
+
Access-Control-Allow-Origin:
|
|
24
|
+
- '*'
|
|
25
|
+
Connection:
|
|
26
|
+
- Close
|
|
27
|
+
Content-Length:
|
|
28
|
+
- '45'
|
|
29
|
+
Content-Type:
|
|
30
|
+
- application/json
|
|
31
|
+
Date:
|
|
32
|
+
- Wed, 17 Jun 2026 16:14:27 GMT
|
|
33
|
+
Server:
|
|
34
|
+
- Pytest-HTTPBIN/0.1.0
|
|
35
|
+
status:
|
|
36
|
+
code: 200
|
|
37
|
+
message: OK
|
|
38
|
+
- request:
|
|
39
|
+
body: null
|
|
40
|
+
headers:
|
|
41
|
+
Accept:
|
|
42
|
+
- '*/*'
|
|
43
|
+
Accept-Encoding:
|
|
44
|
+
- gzip, deflate, br
|
|
45
|
+
Authorization:
|
|
46
|
+
- Basic dXNyOnB3ZA==
|
|
47
|
+
Connection:
|
|
48
|
+
- keep-alive
|
|
49
|
+
User-Agent:
|
|
50
|
+
- niquests/3.18.6
|
|
51
|
+
method: GET
|
|
52
|
+
uri: http://127.0.0.1:37027/basic-auth/quite/bad
|
|
53
|
+
response:
|
|
54
|
+
body:
|
|
55
|
+
string: ''
|
|
56
|
+
headers:
|
|
57
|
+
Access-Control-Allow-Credentials:
|
|
58
|
+
- 'true'
|
|
59
|
+
Access-Control-Allow-Origin:
|
|
60
|
+
- '*'
|
|
61
|
+
Connection:
|
|
62
|
+
- Close
|
|
63
|
+
Content-Length:
|
|
64
|
+
- '0'
|
|
65
|
+
Date:
|
|
66
|
+
- Wed, 17 Jun 2026 16:14:27 GMT
|
|
67
|
+
Server:
|
|
68
|
+
- Pytest-HTTPBIN/0.1.0
|
|
69
|
+
WWW-Authenticate:
|
|
70
|
+
- Basic realm="Fake Realm"
|
|
71
|
+
status:
|
|
72
|
+
code: 401
|
|
73
|
+
message: Unauthorized
|
|
74
|
+
- request:
|
|
75
|
+
body: null
|
|
76
|
+
headers:
|
|
77
|
+
Accept:
|
|
78
|
+
- '*/*'
|
|
79
|
+
Accept-Encoding:
|
|
80
|
+
- gzip, deflate, br
|
|
81
|
+
Authorization:
|
|
82
|
+
- Basic dXNyOnB3ZA==
|
|
83
|
+
Connection:
|
|
84
|
+
- keep-alive
|
|
85
|
+
User-Agent:
|
|
86
|
+
- niquests/3.18.6
|
|
87
|
+
method: GET
|
|
88
|
+
uri: http://127.0.0.1:40371/basic-auth/usr/pwd
|
|
89
|
+
response:
|
|
90
|
+
body:
|
|
91
|
+
string: "{\n \"authenticated\": true,\n \"user\": \"usr\"\n}\n"
|
|
92
|
+
headers:
|
|
93
|
+
Access-Control-Allow-Credentials:
|
|
94
|
+
- 'true'
|
|
95
|
+
Access-Control-Allow-Origin:
|
|
96
|
+
- '*'
|
|
97
|
+
Connection:
|
|
98
|
+
- Close
|
|
99
|
+
Content-Length:
|
|
100
|
+
- '45'
|
|
101
|
+
Content-Type:
|
|
102
|
+
- application/json
|
|
103
|
+
Date:
|
|
104
|
+
- Wed, 17 Jun 2026 16:25:16 GMT
|
|
105
|
+
Server:
|
|
106
|
+
- Pytest-HTTPBIN/0.1.0
|
|
107
|
+
status:
|
|
108
|
+
code: 200
|
|
109
|
+
message: OK
|
|
110
|
+
- request:
|
|
111
|
+
body: null
|
|
112
|
+
headers:
|
|
113
|
+
Accept:
|
|
114
|
+
- '*/*'
|
|
115
|
+
Accept-Encoding:
|
|
116
|
+
- gzip, deflate, br
|
|
117
|
+
Authorization:
|
|
118
|
+
- Basic dXNyOnB3ZA==
|
|
119
|
+
Connection:
|
|
120
|
+
- keep-alive
|
|
121
|
+
User-Agent:
|
|
122
|
+
- niquests/3.18.6
|
|
123
|
+
method: GET
|
|
124
|
+
uri: http://127.0.0.1:40371/basic-auth/quite/bad
|
|
125
|
+
response:
|
|
126
|
+
body:
|
|
127
|
+
string: ''
|
|
128
|
+
headers:
|
|
129
|
+
Access-Control-Allow-Credentials:
|
|
130
|
+
- 'true'
|
|
131
|
+
Access-Control-Allow-Origin:
|
|
132
|
+
- '*'
|
|
133
|
+
Connection:
|
|
134
|
+
- Close
|
|
135
|
+
Content-Length:
|
|
136
|
+
- '0'
|
|
137
|
+
Date:
|
|
138
|
+
- Wed, 17 Jun 2026 16:25:16 GMT
|
|
139
|
+
Server:
|
|
140
|
+
- Pytest-HTTPBIN/0.1.0
|
|
141
|
+
WWW-Authenticate:
|
|
142
|
+
- Basic realm="Fake Realm"
|
|
143
|
+
status:
|
|
144
|
+
code: 401
|
|
145
|
+
message: Unauthorized
|
|
146
|
+
version: 1
|