csu 2.6.4__tar.gz → 2.6.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.
Files changed (109) hide show
  1. {csu-2.6.4 → csu-2.6.6}/.bumpversion.cfg +1 -1
  2. {csu-2.6.4 → csu-2.6.6}/.cookiecutterrc +1 -1
  3. {csu-2.6.4 → csu-2.6.6}/PKG-INFO +3 -3
  4. {csu-2.6.4 → csu-2.6.6}/README.rst +2 -2
  5. {csu-2.6.4 → csu-2.6.6}/pyproject.toml +1 -1
  6. {csu-2.6.4 → csu-2.6.6}/src/csu/__init__.py +1 -1
  7. {csu-2.6.4 → csu-2.6.6}/src/csu/exceptions.py +2 -2
  8. {csu-2.6.4 → csu-2.6.6}/src/csu/test_service.py +0 -9
  9. {csu-2.6.4 → csu-2.6.6}/src/csu/views.py +15 -10
  10. {csu-2.6.4 → csu-2.6.6}/src/csu.egg-info/PKG-INFO +3 -3
  11. {csu-2.6.4 → csu-2.6.6}/src/csu.egg-info/SOURCES.txt +1 -1
  12. {csu-2.6.4/src/csu → csu-2.6.6/tests}/test_exceptions.py +32 -19
  13. {csu-2.6.4 → csu-2.6.6}/tests/test_service.py +36 -36
  14. {csu-2.6.4 → csu-2.6.6}/tests/test_service_auth.py +12 -12
  15. csu-2.6.6/tests/test_views.py +107 -0
  16. csu-2.6.4/tests/test_views.py +0 -90
  17. {csu-2.6.4 → csu-2.6.6}/.coveragerc +0 -0
  18. {csu-2.6.4 → csu-2.6.6}/.editorconfig +0 -0
  19. {csu-2.6.4 → csu-2.6.6}/.github/workflows/github-actions.yml +0 -0
  20. {csu-2.6.4 → csu-2.6.6}/.pre-commit-config.yaml +0 -0
  21. {csu-2.6.4 → csu-2.6.6}/.tombi.toml +0 -0
  22. {csu-2.6.4 → csu-2.6.6}/AUTHORS.rst +0 -0
  23. {csu-2.6.4 → csu-2.6.6}/CHANGELOG.rst +0 -0
  24. {csu-2.6.4 → csu-2.6.6}/CONTRIBUTING.rst +0 -0
  25. {csu-2.6.4 → csu-2.6.6}/LICENSE +0 -0
  26. {csu-2.6.4 → csu-2.6.6}/MANIFEST.in +0 -0
  27. {csu-2.6.4 → csu-2.6.6}/ci/bootstrap.py +0 -0
  28. {csu-2.6.4 → csu-2.6.6}/ci/requirements.txt +0 -0
  29. {csu-2.6.4 → csu-2.6.6}/ci/templates/.github/workflows/github-actions.yml +0 -0
  30. {csu-2.6.4 → csu-2.6.6}/pytest.ini +0 -0
  31. {csu-2.6.4 → csu-2.6.6}/setup.cfg +0 -0
  32. {csu-2.6.4 → csu-2.6.6}/src/csu/admin.py +0 -0
  33. {csu-2.6.4 → csu-2.6.6}/src/csu/conf.py +0 -0
  34. {csu-2.6.4 → csu-2.6.6}/src/csu/consts.py +0 -0
  35. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/__init__.py +0 -0
  36. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/auth.py +0 -0
  37. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/fields.py +0 -0
  38. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/forms.py +0 -0
  39. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/perms.py +0 -0
  40. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/phonenumber.py +0 -0
  41. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/serializers.py +0 -0
  42. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/test_auth.py +0 -0
  43. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/test_fields.py +0 -0
  44. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/test_forms.py +0 -0
  45. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/test_phonenumber.py +0 -0
  46. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/test_serializers.py +0 -0
  47. {csu-2.6.4 → csu-2.6.6}/src/csu/drf/views.py +0 -0
  48. {csu-2.6.4 → csu-2.6.6}/src/csu/enums.py +0 -0
  49. {csu-2.6.4 → csu-2.6.6}/src/csu/env.py +0 -0
  50. {csu-2.6.4 → csu-2.6.6}/src/csu/export.py +0 -0
  51. {csu-2.6.4 → csu-2.6.6}/src/csu/fixups.py +0 -0
  52. {csu-2.6.4 → csu-2.6.6}/src/csu/forms/__init__.py +0 -0
  53. {csu-2.6.4 → csu-2.6.6}/src/csu/forms/crispy.py +0 -0
  54. {csu-2.6.4 → csu-2.6.6}/src/csu/forms/fields.py +0 -0
  55. {csu-2.6.4 → csu-2.6.6}/src/csu/gettext.py +0 -0
  56. {csu-2.6.4 → csu-2.6.6}/src/csu/gettext_lazy.py +0 -0
  57. {csu-2.6.4 → csu-2.6.6}/src/csu/locale/ro/LC_MESSAGES/django.mo +0 -0
  58. {csu-2.6.4 → csu-2.6.6}/src/csu/locale/ro/LC_MESSAGES/django.po +0 -0
  59. {csu-2.6.4 → csu-2.6.6}/src/csu/logging.py +0 -0
  60. {csu-2.6.4 → csu-2.6.6}/src/csu/management.py +0 -0
  61. {csu-2.6.4 → csu-2.6.6}/src/csu/models.py +0 -0
  62. {csu-2.6.4 → csu-2.6.6}/src/csu/query.py +0 -0
  63. {csu-2.6.4 → csu-2.6.6}/src/csu/routers.py +0 -0
  64. {csu-2.6.4 → csu-2.6.6}/src/csu/service.py +0 -0
  65. {csu-2.6.4 → csu-2.6.6}/src/csu/templates/api_exception.html +0 -0
  66. {csu-2.6.4 → csu-2.6.6}/src/csu/templates/forms/widgets/opaquewidget.html +0 -0
  67. {csu-2.6.4 → csu-2.6.6}/src/csu/test_consts.py +0 -0
  68. {csu-2.6.4 → csu-2.6.6}/src/csu/test_env.py +0 -0
  69. {csu-2.6.4 → csu-2.6.6}/src/csu/test_management.py +0 -0
  70. {csu-2.6.4 → csu-2.6.6}/src/csu/test_timezones.py +0 -0
  71. {csu-2.6.4 → csu-2.6.6}/src/csu/test_utils.py +0 -0
  72. {csu-2.6.4 → csu-2.6.6}/src/csu/test_xml.py +0 -0
  73. {csu-2.6.4 → csu-2.6.6}/src/csu/timezones.py +0 -0
  74. {csu-2.6.4 → csu-2.6.6}/src/csu/utils.py +0 -0
  75. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/__init__.py +0 -0
  76. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/admin.py +0 -0
  77. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/asgi.py +0 -0
  78. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/engine.py +0 -0
  79. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/enums.py +0 -0
  80. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/job.py +0 -0
  81. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/models.py +0 -0
  82. {csu-2.6.4 → csu-2.6.6}/src/csu/worker/registry.py +0 -0
  83. {csu-2.6.4 → csu-2.6.6}/src/csu/wsgi.py +0 -0
  84. {csu-2.6.4 → csu-2.6.6}/src/csu/xml.py +0 -0
  85. {csu-2.6.4 → csu-2.6.6}/src/csu.egg-info/dependency_links.txt +0 -0
  86. {csu-2.6.4 → csu-2.6.6}/src/csu.egg-info/requires.txt +0 -0
  87. {csu-2.6.4 → csu-2.6.6}/src/csu.egg-info/top_level.txt +0 -0
  88. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_custom_context.yaml +0 -0
  89. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_custom_context_0_retries.yaml +0 -0
  90. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_decoding.yaml +0 -0
  91. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_error.yaml +0 -0
  92. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_logging.yaml +0 -0
  93. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service/test_redirects.yaml +0 -0
  94. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service_auth/test_async.yaml +0 -0
  95. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service_auth/test_async_auth.yaml +0 -0
  96. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service_auth/test_sync.yaml +0 -0
  97. {csu-2.6.4 → csu-2.6.6}/tests/cassettes/test_service_auth/test_sync_auth.yaml +0 -0
  98. {csu-2.6.4 → csu-2.6.6}/tests/conftest.py +0 -0
  99. {csu-2.6.4 → csu-2.6.6}/tests/exampleworker.py +0 -0
  100. {csu-2.6.4 → csu-2.6.6}/tests/test_exampleworker.py +0 -0
  101. {csu-2.6.4 → csu-2.6.6}/tests/test_logging.py +0 -0
  102. {csu-2.6.4 → csu-2.6.6}/tests/test_models.py +0 -0
  103. {csu-2.6.4 → csu-2.6.6}/tests/test_worker.py +0 -0
  104. {csu-2.6.4 → csu-2.6.6}/tests/testproject/__init__.py +0 -0
  105. {csu-2.6.4 → csu-2.6.6}/tests/testproject/fixtures/testuser.json +0 -0
  106. {csu-2.6.4 → csu-2.6.6}/tests/testproject/models.py +0 -0
  107. {csu-2.6.4 → csu-2.6.6}/tests/testproject/settings.py +0 -0
  108. {csu-2.6.4 → csu-2.6.6}/tests/testproject/urls.py +0 -0
  109. {csu-2.6.4 → csu-2.6.6}/tox.ini +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 2.6.4
2
+ current_version = 2.6.6
3
3
  commit = True
4
4
  tag = True
5
5
 
@@ -41,7 +41,7 @@ default_context:
41
41
  sphinx_theme: furo
42
42
  test_matrix_separate_coverage: false
43
43
  tests_inside_package: true
44
- version: 2.6.4
44
+ version: 2.6.6
45
45
  version_manager: bump2version
46
46
  website: https://blog.ionelmc.ro
47
47
  year_from: '2024'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csu
3
- Version: 2.6.4
3
+ Version: 2.6.6
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.6.4.svg
72
+ .. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.6.6.svg
73
73
  :alt: Commits since latest release
74
- :target: https://github.com/ionelmc/python-csu/compare/v2.6.4...main
74
+ :target: https://github.com/ionelmc/python-csu/compare/v2.6.6...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.6.4.svg
37
+ .. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.6.6.svg
38
38
  :alt: Commits since latest release
39
- :target: https://github.com/ionelmc/python-csu/compare/v2.6.4...main
39
+ :target: https://github.com/ionelmc/python-csu/compare/v2.6.6...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/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csu"
3
- version = "2.6.4"
3
+ version = "2.6.6"
4
4
  description = "Clean Slate Utils - bunch of utility code, mostly Django/DRF specific."
5
5
  requires-python = ">=3.14"
6
6
  license = "BSD-2-Clause"
@@ -2,4 +2,4 @@
2
2
  a.k.a Clean Slate Utils
3
3
  """
4
4
 
5
- __version__ = "2.6.4"
5
+ __version__ = "2.6.6"
@@ -1,3 +1,4 @@
1
+ from base64 import b64encode
1
2
  from collections import Counter
2
3
  from collections.abc import Iterable
3
4
  from importlib.util import find_spec
@@ -23,8 +24,7 @@ else:
23
24
 
24
25
  def get_event_id():
25
26
  dt = now()
26
- seconds = dt - dt.replace(second=0, microsecond=0)
27
- return dt.strftime(f"%y%m%d:{urandom(4).hex()}:%H%M{seconds.total_seconds():05.2f}")
27
+ return dt.strftime(f"%y%m%d:{b64encode(urandom(3)).strip(b'=').decode()}:%H%M%S")
28
28
 
29
29
 
30
30
  class TaggedError(Exception):
@@ -1,23 +1,14 @@
1
1
  from typing import reveal_type
2
2
 
3
- import time_machine
4
3
  from niquests import PreparedRequest
5
4
  from niquests import Response
6
5
 
7
- from . import exceptions
8
- from .exceptions import get_event_id
9
6
  from .service import AsyncHTTPService
10
7
  from .service import AsyncHTTPServiceContext
11
8
  from .service import HTTPService
12
9
  from .service import HTTPServiceContext
13
10
 
14
11
 
15
- def test_get_accident_id(monkeypatch):
16
- monkeypatch.setattr(exceptions, "urandom", lambda len: bytes(range(len)))
17
- with time_machine.travel(1674777700.5816755):
18
- assert get_event_id() == "230127:00010203:020140.58"
19
-
20
-
21
12
  class CustomResponse:
22
13
  def bar(self, x: float) -> float: ...
23
14
 
@@ -79,7 +79,9 @@ def exception_handler(
79
79
  event_id_field="accident_id",
80
80
  message_field="detail",
81
81
  error_error_code_field="code",
82
- ):
82
+ rollback_transaction=True,
83
+ build_response=True,
84
+ ) -> Response | None:
83
85
  """
84
86
  Returns the response that should be used for any given exception.
85
87
 
@@ -106,6 +108,7 @@ def exception_handler(
106
108
  if auth_header := getattr(exc, "auth_header", None):
107
109
  headers["WWW-Authenticate"] = auth_header
108
110
  if wait := getattr(exc, "wait", None):
111
+ assert isinstance(wait, int), f"Expected exc.wait={wait=!r} to be int!"
109
112
  headers["Retry-After"] = f"{wait:d}"
110
113
  status_code = exc.status_code
111
114
  else:
@@ -154,15 +157,17 @@ def exception_handler(
154
157
  exc_info=True,
155
158
  extra={"csu_exc": True},
156
159
  )
157
- set_rollback()
158
- response = Response(data, status=status_code, headers=headers)
159
- accepted_renderer = getattr(request, "accepted_renderer", None)
160
- if not accepted_renderer:
161
- accepted_renderer = JSONRenderer()
162
- response.accepted_renderer = accepted_renderer
163
- response.accepted_media_type = accepted_renderer.media_type
164
- response.renderer_context = context
165
- return response
160
+ if rollback_transaction:
161
+ set_rollback()
162
+ if build_response:
163
+ response = Response(data, status=status_code, headers=headers)
164
+ accepted_renderer = getattr(request, "accepted_renderer", None)
165
+ if not accepted_renderer:
166
+ accepted_renderer = JSONRenderer()
167
+ response.accepted_renderer = accepted_renderer
168
+ response.accepted_media_type = accepted_renderer.media_type
169
+ response.renderer_context = context
170
+ return response
166
171
 
167
172
 
168
173
  def server_error(request, *args, **kwargs):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csu
3
- Version: 2.6.4
3
+ Version: 2.6.6
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.6.4.svg
72
+ .. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-csu/v2.6.6.svg
73
73
  :alt: Commits since latest release
74
- :target: https://github.com/ionelmc/python-csu/compare/v2.6.4...main
74
+ :target: https://github.com/ionelmc/python-csu/compare/v2.6.6...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/
@@ -36,7 +36,6 @@ src/csu/routers.py
36
36
  src/csu/service.py
37
37
  src/csu/test_consts.py
38
38
  src/csu/test_env.py
39
- src/csu/test_exceptions.py
40
39
  src/csu/test_management.py
41
40
  src/csu/test_service.py
42
41
  src/csu/test_timezones.py
@@ -83,6 +82,7 @@ src/csu/worker/registry.py
83
82
  tests/conftest.py
84
83
  tests/exampleworker.py
85
84
  tests/test_exampleworker.py
85
+ tests/test_exceptions.py
86
86
  tests/test_logging.py
87
87
  tests/test_models.py
88
88
  tests/test_service.py
@@ -3,12 +3,13 @@ from datetime import datetime
3
3
  from zoneinfo import ZoneInfo
4
4
 
5
5
  import time_machine
6
+ from inline_snapshot import snapshot
6
7
 
7
- from . import exceptions
8
- from .exceptions import APIServiceError
9
- from .exceptions import ExhaustedRetriesError
10
- from .exceptions import OpenServiceError
11
- from .exceptions import get_event_id
8
+ from csu import exceptions
9
+ from csu.exceptions import APIServiceError
10
+ from csu.exceptions import ExhaustedRetriesError
11
+ from csu.exceptions import OpenServiceError
12
+ from csu.exceptions import get_event_id
12
13
 
13
14
 
14
15
  class OpenFooError(OpenServiceError):
@@ -25,11 +26,13 @@ def test_open_service_error(monkeypatch):
25
26
  monkeypatch.setattr(exceptions, "get_event_id", lambda: 234)
26
27
  api_exc = exc.as_api_service_error()
27
28
  assert isinstance(api_exc, APIServiceError)
28
- assert api_exc.detail == {
29
- "accident_id": 234,
30
- "code": "unknown",
31
- "detail": "Unknown error",
32
- }
29
+ assert api_exc.detail == snapshot(
30
+ {
31
+ "accident_id": 234,
32
+ "code": "unknown",
33
+ "detail": "Unknown error",
34
+ }
35
+ )
33
36
 
34
37
 
35
38
  def test_open_service_error_subclass(monkeypatch):
@@ -38,18 +41,22 @@ def test_open_service_error_subclass(monkeypatch):
38
41
  monkeypatch.setattr(exceptions, "get_event_id", lambda: 123)
39
42
  api_exc = exc.as_api_service_error()
40
43
  assert isinstance(api_exc, APIServiceError)
41
- assert api_exc.detail == {
42
- "accident_id": 123,
43
- "code": "unknown",
44
- "detail": "proper foo",
45
- }
44
+ assert api_exc.detail == snapshot(
45
+ {
46
+ "accident_id": 123,
47
+ "code": "unknown",
48
+ "detail": "proper foo",
49
+ }
50
+ )
46
51
 
47
52
 
48
53
  def test_add_note():
49
54
  exc = OpenServiceError("My message!", details=[1, 2, Exception(123)], event_id=None)
50
- assert exc.__notes__ == [
51
- "(1, 2, Exception(123))",
52
- ]
55
+ assert exc.__notes__ == snapshot(
56
+ [
57
+ "(1, 2, Exception(123))",
58
+ ]
59
+ )
53
60
 
54
61
  exc = OpenServiceError("My message!", details=[], event_id=None)
55
62
  assert getattr(exc, "__notes__", []) == []
@@ -84,4 +91,10 @@ def test_exhausted_retries_error():
84
91
  def test_get_event_id(monkeypatch):
85
92
  monkeypatch.setattr(exceptions, "urandom", lambda _: b"ZZZ")
86
93
  with time_machine.travel(datetime(2024, 12, 12, 1, 2, 3, microsecond=456789, tzinfo=ZoneInfo("Europe/Bucharest"))):
87
- assert get_event_id() == "241212:5a5a5a:010203.46"
94
+ assert get_event_id() == snapshot("241212:Wlpa:010203")
95
+
96
+
97
+ def test_get_accident_id(monkeypatch):
98
+ monkeypatch.setattr(exceptions, "urandom", lambda len: bytes(range(len)))
99
+ with time_machine.travel(1674777700.5816755):
100
+ assert get_event_id() == snapshot("230127:AAEC:020140")