cardo-python-utils 0.5.dev55__tar.gz → 0.5.1__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 (76) hide show
  1. {cardo_python_utils-0.5.dev55/cardo_python_utils.egg-info → cardo_python_utils-0.5.1}/PKG-INFO +1 -1
  2. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1/cardo_python_utils.egg-info}/PKG-INFO +1 -1
  3. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/pyproject.toml +1 -1
  4. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/api/drf.py +7 -9
  5. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/api/ninja.py +5 -5
  6. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/middleware/tenant_aware_websocket_middleware.py +10 -7
  7. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/LICENSE +0 -0
  8. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/MANIFEST.in +0 -0
  9. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/README.rst +0 -0
  10. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/cardo_python_utils.egg-info/SOURCES.txt +0 -0
  11. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/cardo_python_utils.egg-info/dependency_links.txt +0 -0
  12. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/cardo_python_utils.egg-info/requires.txt +0 -0
  13. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/cardo_python_utils.egg-info/top_level.txt +0 -0
  14. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/__init__.py +0 -0
  15. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/choices.py +0 -0
  16. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/data_structures.py +0 -0
  17. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/db.py +0 -0
  18. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/README.md +0 -0
  19. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/__init__.py +0 -0
  20. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/__init__.py +0 -0
  21. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/auth.py +0 -0
  22. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/templates/__init__.py +0 -0
  23. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/templates/user_groups_changelist.html +0 -0
  24. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/user_group.py +0 -0
  25. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/admin/views.py +0 -0
  26. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/api/__init__.py +0 -0
  27. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/api/utils.py +0 -0
  28. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/apps.py +0 -0
  29. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/auth/service.py +0 -0
  30. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/celery/__init__.py +0 -0
  31. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/celery/tenant_aware_database_scheduler.py +0 -0
  32. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/celery/tenant_aware_task.py +0 -0
  33. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/db/__init__.py +0 -0
  34. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/db/alias.py +0 -0
  35. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/db/routers.py +0 -0
  36. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/db/transaction.py +0 -0
  37. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/db/utils.py +0 -0
  38. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/__init__.py +0 -0
  39. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/commands/__init__.py +0 -0
  40. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/commands/migrateall.py +0 -0
  41. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/commands/shell.py +0 -0
  42. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/commands/showmigrations.py +0 -0
  43. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/management/commands/tenant_aware_command.py +0 -0
  44. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/middleware/__init__.py +0 -0
  45. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/middleware/tenant_aware_http_middleware.py +0 -0
  46. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0001_initial.py +0 -0
  47. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0001_initial_squashed_0005_alter_userrole_id.py +0 -0
  48. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0002_auto_20220120_1617.py +0 -0
  49. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0003_auto_20220513_1025.py +0 -0
  50. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0004_auto_20220817_1526.py +0 -0
  51. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0005_alter_userrole_id.py +0 -0
  52. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0006_userrole_organization_and_more.py +0 -0
  53. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0007_user_demo.py +0 -0
  54. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/0008_delete_userrole.py +0 -0
  55. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/migrations/__init__.py +0 -0
  56. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/models/__init__.py +0 -0
  57. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/models/user.py +0 -0
  58. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/models/user_group.py +0 -0
  59. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/oidc_settings.py +0 -0
  60. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/redis/__init__.py +0 -0
  61. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/redis/key_function.py +0 -0
  62. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/settings.py +0 -0
  63. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/storage/__init__.py +0 -0
  64. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/storage/tenant_aware_storage.py +0 -0
  65. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/tenant_context.py +0 -0
  66. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/tests/__init__.py +0 -0
  67. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django/tests/conftest.py +0 -0
  68. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/django_utils.py +0 -0
  69. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/esma_choices.py +0 -0
  70. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/exceptions.py +0 -0
  71. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/imports.py +0 -0
  72. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/math.py +0 -0
  73. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/text.py +0 -0
  74. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/time.py +0 -0
  75. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/python_utils/types_hinting.py +0 -0
  76. {cardo_python_utils-0.5.dev55 → cardo_python_utils-0.5.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.5.dev55
3
+ Version: 0.5.1
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
5
  Author-email: CardoAI <hello@cardoai.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.5.dev55
3
+ Version: 0.5.1
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
5
  Author-email: CardoAI <hello@cardoai.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cardo-python-utils"
7
- version = "0.5.dev55"
7
+ version = "0.5.1"
8
8
  description = "Python library enhanced with a wide range of functions for different scenarios."
9
9
  readme = "README.rst"
10
10
  requires-python = ">=3.8"
@@ -1,5 +1,5 @@
1
1
  from django.conf import settings
2
- from jwt.exceptions import ExpiredSignatureError, InvalidTokenError, PyJWKClientError
2
+ from jwt.exceptions import ExpiredSignatureError, PyJWTError
3
3
 
4
4
  from rest_framework import authentication
5
5
  from rest_framework.exceptions import AuthenticationFailed, PermissionDenied
@@ -16,19 +16,17 @@ class AuthenticationBackend(authentication.TokenAuthentication):
16
16
  payload = decode_jwt(token, audience=self._get_audience())
17
17
  except ExpiredSignatureError as e:
18
18
  raise AuthenticationFailed("Token has expired.") from e
19
- except (InvalidTokenError, PyJWKClientError) as e:
19
+ except PyJWTError as e:
20
20
  raise PermissionDenied(f"Invalid token: {str(e)}") from e
21
21
 
22
22
  try:
23
23
  username = payload["preferred_username"]
24
24
  except KeyError as e:
25
- raise PermissionDenied(
26
- "Invalid token: preferred_username not present."
27
- ) from e
25
+ raise PermissionDenied("Invalid token: preferred_username not present.") from e
28
26
 
29
27
  user = create_or_update_user(username, payload)
30
28
  return user, payload
31
-
29
+
32
30
  def _get_audience(self):
33
31
  """
34
32
  Allows subclasses to override the audience used for JWT decoding.
@@ -50,9 +48,9 @@ class HasScope(BasePermission):
50
48
  allowed_scopes = ["jobs"]
51
49
  ...
52
50
 
53
- It is possible to define different scopes per HTTP method
51
+ It is possible to define different scopes per HTTP method
54
52
  by setting `allowed_scopes` as a dict:
55
-
53
+
56
54
  class MyApiView(APIView):
57
55
  permission_classes = [IsAuthenticated, HasScope]
58
56
  allowed_scopes = {
@@ -73,7 +71,7 @@ class HasScope(BasePermission):
73
71
  f"No allowed_scopes defined on the view '{view.__class__.__name__}'. "
74
72
  "Define allowed_scopes or set it to '*' to allow any scope."
75
73
  )
76
-
74
+
77
75
  if isinstance(allowed_scopes, dict):
78
76
  allowed_scopes = allowed_scopes.get(request.method.lower(), [])
79
77
 
@@ -1,12 +1,12 @@
1
1
  import logging
2
2
  from typing import Literal, Optional, Union
3
3
 
4
- from jwt.exceptions import ExpiredSignatureError, InvalidTokenError, PyJWKClientError
4
+ from jwt.exceptions import ExpiredSignatureError, PyJWTError
5
5
 
6
6
  from django.conf import settings
7
7
  from django.http import HttpRequest
8
8
  from ninja.security import HttpBearer
9
- from ninja.errors import AuthenticationError, AuthorizationError, HttpError
9
+ from ninja.errors import AuthenticationError, HttpError
10
10
 
11
11
  from .utils import (
12
12
  acreate_or_update_user,
@@ -63,14 +63,14 @@ class AuthBearer(HttpBearer):
63
63
  return decode_jwt(token)
64
64
  except ExpiredSignatureError as e:
65
65
  raise AuthenticationError("Token has expired.") from e
66
- except (InvalidTokenError, PyJWKClientError) as e:
67
- raise AuthorizationError(f"Invalid token: {str(e)}") from e
66
+ except PyJWTError as e:
67
+ raise AuthenticationError(f"Invalid token: {str(e)}") from e
68
68
 
69
69
  def _get_username(self, payload: TokenPayload) -> str:
70
70
  try:
71
71
  return payload["preferred_username"]
72
72
  except KeyError as e:
73
- raise AuthorizationError("Invalid token: 'preferred_username' claim not present.") from e
73
+ raise AuthenticationError("Invalid token: 'preferred_username' claim not present.") from e
74
74
 
75
75
  def _verify_scopes(self, request, token_payload):
76
76
  allowed_scopes = self._get_view_allowed_scopes(request)
@@ -3,6 +3,7 @@ from urllib.parse import parse_qs
3
3
 
4
4
  from django.conf import settings
5
5
  from django.contrib.auth import get_user_model
6
+ from jwt.exceptions import PyJWTError
6
7
 
7
8
  from ..api.utils import decode_jwt, TokenPayload
8
9
  from ..settings import DEVELOPMENT_TENANT
@@ -50,7 +51,13 @@ class TenantAwareWebsocketMiddleware:
50
51
  tenant = self._get_tenant(scope)
51
52
 
52
53
  async with TenantContext(tenant):
53
- token_payload: TokenPayload = decode_jwt(access_token)
54
+ try:
55
+ token_payload: TokenPayload = decode_jwt(access_token)
56
+ except PyJWTError as e:
57
+ logger.info(f"Failed to decode JWT token: {e}")
58
+ await self._reject_connection(send, f"Invalid authorization token: {str(e)}")
59
+ return
60
+
54
61
  username = token_payload.get("preferred_username")
55
62
  if not username:
56
63
  await self._reject_connection(send, "Username cannot be extracted from the token")
@@ -84,9 +91,7 @@ class TenantAwareWebsocketMiddleware:
84
91
  Returns:
85
92
  None
86
93
  """
87
- await send(
88
- {"type": "websocket.close", "code": 4000, "reason": reason}
89
- ) # Custom close code for rejection
94
+ await send({"type": "websocket.close", "code": 4000, "reason": reason}) # Custom close code for rejection
90
95
 
91
96
  def _get_tenant(self, scope) -> str:
92
97
  """
@@ -110,9 +115,7 @@ class TenantAwareWebsocketMiddleware:
110
115
  logger.debug(f"Tenant '{tenant}' extracted from websocket host: {host}")
111
116
  return tenant
112
117
 
113
- raise Exception(
114
- f"Could not determine tenant from websocket subdomain. Host: {host}"
115
- )
118
+ raise Exception(f"Could not determine tenant from websocket subdomain. Host: {host}")
116
119
 
117
120
  @staticmethod
118
121
  def _get_host_from_scope(scope) -> str: