cardo-python-utils 0.4.2__tar.gz → 0.5.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.
Files changed (83) hide show
  1. cardo_python_utils-0.5.0/MANIFEST.in +5 -0
  2. {cardo_python_utils-0.4.2/cardo_python_utils.egg-info → cardo_python_utils-0.5.0}/PKG-INFO +27 -24
  3. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/README.rst +2 -4
  4. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0/cardo_python_utils.egg-info}/PKG-INFO +27 -24
  5. cardo_python_utils-0.5.0/cardo_python_utils.egg-info/SOURCES.txt +74 -0
  6. cardo_python_utils-0.5.0/cardo_python_utils.egg-info/requires.txt +20 -0
  7. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/cardo_python_utils.egg-info/top_level.txt +1 -0
  8. cardo_python_utils-0.5.0/pyproject.toml +74 -0
  9. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/choices.py +5 -4
  10. cardo_python_utils-0.5.0/python_utils/django/README.md +227 -0
  11. cardo_python_utils-0.5.0/python_utils/django/__init__.py +1 -0
  12. cardo_python_utils-0.5.0/python_utils/django/admin/__init__.py +0 -0
  13. cardo_python_utils-0.5.0/python_utils/django/admin/auth.py +82 -0
  14. cardo_python_utils-0.5.0/python_utils/django/admin/templates/__init__.py +3 -0
  15. cardo_python_utils-0.5.0/python_utils/django/admin/templates/user_groups_changelist.html +7 -0
  16. cardo_python_utils-0.5.0/python_utils/django/admin/user_group.py +159 -0
  17. cardo_python_utils-0.5.0/python_utils/django/admin/views.py +24 -0
  18. cardo_python_utils-0.5.0/python_utils/django/api/__init__.py +0 -0
  19. cardo_python_utils-0.5.0/python_utils/django/api/drf.py +93 -0
  20. cardo_python_utils-0.5.0/python_utils/django/api/ninja.py +153 -0
  21. cardo_python_utils-0.5.0/python_utils/django/api/utils.py +130 -0
  22. cardo_python_utils-0.5.0/python_utils/django/apps.py +6 -0
  23. cardo_python_utils-0.5.0/python_utils/django/auth/service.py +202 -0
  24. cardo_python_utils-0.5.0/python_utils/django/celery/__init__.py +4 -0
  25. cardo_python_utils-0.5.0/python_utils/django/celery/tenant_aware_database_scheduler.py +207 -0
  26. cardo_python_utils-0.5.0/python_utils/django/celery/tenant_aware_task.py +115 -0
  27. cardo_python_utils-0.5.0/python_utils/django/db/__init__.py +0 -0
  28. cardo_python_utils-0.5.0/python_utils/django/db/alias.py +22 -0
  29. cardo_python_utils-0.5.0/python_utils/django/db/routers.py +11 -0
  30. cardo_python_utils-0.5.0/python_utils/django/db/transaction.py +26 -0
  31. cardo_python_utils-0.5.0/python_utils/django/db/utils.py +66 -0
  32. cardo_python_utils-0.5.0/python_utils/django/management/__init__.py +0 -0
  33. cardo_python_utils-0.5.0/python_utils/django/management/commands/__init__.py +0 -0
  34. cardo_python_utils-0.5.0/python_utils/django/management/commands/migrateall.py +25 -0
  35. cardo_python_utils-0.5.0/python_utils/django/management/commands/shell.py +32 -0
  36. cardo_python_utils-0.5.0/python_utils/django/management/commands/showmigrations.py +37 -0
  37. cardo_python_utils-0.5.0/python_utils/django/management/commands/tenant_aware_command.py +74 -0
  38. cardo_python_utils-0.5.0/python_utils/django/middleware/__init__.py +6 -0
  39. cardo_python_utils-0.5.0/python_utils/django/middleware/tenant_aware_http_middleware.py +108 -0
  40. cardo_python_utils-0.5.0/python_utils/django/middleware/tenant_aware_websocket_middleware.py +129 -0
  41. cardo_python_utils-0.5.0/python_utils/django/migrations/0001_initial.py +115 -0
  42. cardo_python_utils-0.5.0/python_utils/django/migrations/0001_initial_squashed_0005_alter_userrole_id.py +153 -0
  43. cardo_python_utils-0.5.0/python_utils/django/migrations/0002_auto_20220120_1617.py +18 -0
  44. cardo_python_utils-0.5.0/python_utils/django/migrations/0003_auto_20220513_1025.py +18 -0
  45. cardo_python_utils-0.5.0/python_utils/django/migrations/0004_auto_20220817_1526.py +23 -0
  46. cardo_python_utils-0.5.0/python_utils/django/migrations/0005_alter_userrole_id.py +18 -0
  47. cardo_python_utils-0.5.0/python_utils/django/migrations/0006_userrole_organization_and_more.py +31 -0
  48. cardo_python_utils-0.5.0/python_utils/django/migrations/0007_user_demo.py +15 -0
  49. cardo_python_utils-0.5.0/python_utils/django/migrations/0008_delete_userrole.py +25 -0
  50. cardo_python_utils-0.5.0/python_utils/django/migrations/__init__.py +0 -0
  51. cardo_python_utils-0.5.0/python_utils/django/models/__init__.py +3 -0
  52. cardo_python_utils-0.5.0/python_utils/django/models/user.py +22 -0
  53. cardo_python_utils-0.5.0/python_utils/django/models/user_group.py +22 -0
  54. cardo_python_utils-0.5.0/python_utils/django/oidc_settings.py +134 -0
  55. cardo_python_utils-0.5.0/python_utils/django/redis/__init__.py +4 -0
  56. cardo_python_utils-0.5.0/python_utils/django/redis/key_function.py +5 -0
  57. cardo_python_utils-0.5.0/python_utils/django/settings.py +22 -0
  58. cardo_python_utils-0.5.0/python_utils/django/storage/__init__.py +6 -0
  59. cardo_python_utils-0.5.0/python_utils/django/storage/tenant_aware_storage.py +86 -0
  60. cardo_python_utils-0.5.0/python_utils/django/tenant_context.py +101 -0
  61. cardo_python_utils-0.5.0/python_utils/django/tests/__init__.py +9 -0
  62. cardo_python_utils-0.5.0/python_utils/django/tests/conftest.py +101 -0
  63. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/django_utils.py +0 -40
  64. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/esma_choices.py +21 -0
  65. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/text.py +5 -4
  66. cardo_python_utils-0.5.0/setup.cfg +4 -0
  67. cardo_python_utils-0.4.2/MANIFEST.in +0 -3
  68. cardo_python_utils-0.4.2/cardo_python_utils.egg-info/SOURCES.txt +0 -24
  69. cardo_python_utils-0.4.2/cardo_python_utils.egg-info/requires.txt +0 -18
  70. cardo_python_utils-0.4.2/python_utils/pandas_utils.py +0 -143
  71. cardo_python_utils-0.4.2/python_utils/rest.py +0 -37
  72. cardo_python_utils-0.4.2/setup.cfg +0 -44
  73. cardo_python_utils-0.4.2/setup.py +0 -7
  74. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/LICENSE +0 -0
  75. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/cardo_python_utils.egg-info/dependency_links.txt +0 -0
  76. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/__init__.py +0 -0
  77. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/data_structures.py +0 -0
  78. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/db.py +0 -0
  79. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/exceptions.py +0 -0
  80. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/imports.py +0 -0
  81. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/math.py +0 -0
  82. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/time.py +0 -0
  83. {cardo_python_utils-0.4.2 → cardo_python_utils-0.5.0}/python_utils/types_hinting.py +0 -0
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.rst
3
+ include python_utils/django/admin/templates/user_groups_changelist.html
4
+ include python_utils/django/README.md
5
+ recursive-exclude tests *
@@ -1,40 +1,45 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
- Home-page: https://github.com/CardoAI/cardo-python-utils
6
- Author: Kristi Kotini
7
- Author-email: hello@cardoai.com
8
- License: MIT (X11)
5
+ Author-email: CardoAI <hello@cardoai.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/CardoAI/cardo-python-utils
8
+ Project-URL: Repository, https://github.com/CardoAI/cardo-python-utils.git
9
+ Project-URL: Issues, https://github.com/CardoAI/cardo-python-utils/issues
10
+ Keywords: utilities,helpers,django
9
11
  Classifier: Environment :: Web Environment
10
12
  Classifier: Framework :: Django
11
13
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: BSD License
14
+ Classifier: License :: OSI Approved :: MIT License
13
15
  Classifier: Operating System :: OS Independent
14
16
  Classifier: Programming Language :: Python
15
17
  Classifier: Programming Language :: Python :: 3
16
18
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
19
19
  Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
20
22
  Classifier: Topic :: Internet :: WWW/HTTP
21
23
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
22
24
  Requires-Python: >=3.8
25
+ Description-Content-Type: text/x-rst
23
26
  License-File: LICENSE
24
- Provides-Extra: pandas
25
- Requires-Dist: pandas>=1.4.0; extra == "pandas"
26
- Provides-Extra: django
27
- Requires-Dist: Django; extra == "django"
28
- Requires-Dist: django-model-utils==4.2.0; extra == "django"
29
- Provides-Extra: rest
30
- Requires-Dist: djangorestframework; extra == "rest"
31
- Requires-Dist: requests; extra == "rest"
27
+ Provides-Extra: django-keycloak
28
+ Requires-Dist: PyJWT>=2.10.1; extra == "django-keycloak"
29
+ Requires-Dist: mozilla-django-oidc>=4.0.1; extra == "django-keycloak"
30
+ Requires-Dist: requests; extra == "django-keycloak"
31
+ Provides-Extra: django-keycloak-groups
32
+ Requires-Dist: python-keycloak>=5.8.1; extra == "django-keycloak-groups"
32
33
  Provides-Extra: all
33
- Requires-Dist: Django; extra == "all"
34
- Requires-Dist: pandas>=1.4.0; extra == "all"
35
- Requires-Dist: django-model-utils>=4.2.0; extra == "all"
36
- Requires-Dist: djangorestframework; extra == "all"
34
+ Requires-Dist: PyJWT>=2.10.1; extra == "all"
35
+ Requires-Dist: mozilla-django-oidc>=4.0.1; extra == "all"
36
+ Requires-Dist: python-keycloak>=5.8.1; extra == "all"
37
37
  Requires-Dist: requests; extra == "all"
38
+ Provides-Extra: dev
39
+ Requires-Dist: pytest>=7.0; extra == "dev"
40
+ Requires-Dist: pytest-django>=4.5; extra == "dev"
41
+ Requires-Dist: coverage>=6.0; extra == "dev"
42
+ Requires-Dist: tox>=3.25; extra == "dev"
38
43
  Dynamic: license-file
39
44
 
40
45
  ============================
@@ -50,9 +55,7 @@ Main utils:
50
55
  * data_structures
51
56
  * db
52
57
  * django
53
- * django_rest
54
58
  * math
55
- * pandas
56
59
  * exception
57
60
  * choices
58
61
 
@@ -64,7 +67,7 @@ Quick start
64
67
  from python_utils.time import date_range
65
68
  date_range(start_date, end_date)
66
69
 
67
- Although the library provides some utility functions related to other libraries like django and pandas, it does not install any dependencies automatically.
70
+ Although the library provides some utility functions related to other libraries like django, it does not install any dependencies automatically.
68
71
  This means, you can install the library even if you do not use these libraries, but keep in mind that in this case you cannot use the
69
72
  functions that depend on them.
70
73
 
@@ -74,7 +77,7 @@ You can also chose to install the dependencies alongside the library, including
74
77
 
75
78
  Tests
76
79
  -----
77
- The library has a 100% coverage by tests. If you want to see tests in action:
80
+ The library has a high coverage by tests. If you want to see tests in action:
78
81
 
79
82
  1. Inside venv, run ``pip install -r tests/requirements.txt``
80
83
 
@@ -11,9 +11,7 @@ Main utils:
11
11
  * data_structures
12
12
  * db
13
13
  * django
14
- * django_rest
15
14
  * math
16
- * pandas
17
15
  * exception
18
16
  * choices
19
17
 
@@ -25,7 +23,7 @@ Quick start
25
23
  from python_utils.time import date_range
26
24
  date_range(start_date, end_date)
27
25
 
28
- Although the library provides some utility functions related to other libraries like django and pandas, it does not install any dependencies automatically.
26
+ Although the library provides some utility functions related to other libraries like django, it does not install any dependencies automatically.
29
27
  This means, you can install the library even if you do not use these libraries, but keep in mind that in this case you cannot use the
30
28
  functions that depend on them.
31
29
 
@@ -35,7 +33,7 @@ You can also chose to install the dependencies alongside the library, including
35
33
 
36
34
  Tests
37
35
  -----
38
- The library has a 100% coverage by tests. If you want to see tests in action:
36
+ The library has a high coverage by tests. If you want to see tests in action:
39
37
 
40
38
  1. Inside venv, run ``pip install -r tests/requirements.txt``
41
39
 
@@ -1,40 +1,45 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
- Home-page: https://github.com/CardoAI/cardo-python-utils
6
- Author: Kristi Kotini
7
- Author-email: hello@cardoai.com
8
- License: MIT (X11)
5
+ Author-email: CardoAI <hello@cardoai.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/CardoAI/cardo-python-utils
8
+ Project-URL: Repository, https://github.com/CardoAI/cardo-python-utils.git
9
+ Project-URL: Issues, https://github.com/CardoAI/cardo-python-utils/issues
10
+ Keywords: utilities,helpers,django
9
11
  Classifier: Environment :: Web Environment
10
12
  Classifier: Framework :: Django
11
13
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: BSD License
14
+ Classifier: License :: OSI Approved :: MIT License
13
15
  Classifier: Operating System :: OS Independent
14
16
  Classifier: Programming Language :: Python
15
17
  Classifier: Programming Language :: Python :: 3
16
18
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
19
19
  Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
20
22
  Classifier: Topic :: Internet :: WWW/HTTP
21
23
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
22
24
  Requires-Python: >=3.8
25
+ Description-Content-Type: text/x-rst
23
26
  License-File: LICENSE
24
- Provides-Extra: pandas
25
- Requires-Dist: pandas>=1.4.0; extra == "pandas"
26
- Provides-Extra: django
27
- Requires-Dist: Django; extra == "django"
28
- Requires-Dist: django-model-utils==4.2.0; extra == "django"
29
- Provides-Extra: rest
30
- Requires-Dist: djangorestframework; extra == "rest"
31
- Requires-Dist: requests; extra == "rest"
27
+ Provides-Extra: django-keycloak
28
+ Requires-Dist: PyJWT>=2.10.1; extra == "django-keycloak"
29
+ Requires-Dist: mozilla-django-oidc>=4.0.1; extra == "django-keycloak"
30
+ Requires-Dist: requests; extra == "django-keycloak"
31
+ Provides-Extra: django-keycloak-groups
32
+ Requires-Dist: python-keycloak>=5.8.1; extra == "django-keycloak-groups"
32
33
  Provides-Extra: all
33
- Requires-Dist: Django; extra == "all"
34
- Requires-Dist: pandas>=1.4.0; extra == "all"
35
- Requires-Dist: django-model-utils>=4.2.0; extra == "all"
36
- Requires-Dist: djangorestframework; extra == "all"
34
+ Requires-Dist: PyJWT>=2.10.1; extra == "all"
35
+ Requires-Dist: mozilla-django-oidc>=4.0.1; extra == "all"
36
+ Requires-Dist: python-keycloak>=5.8.1; extra == "all"
37
37
  Requires-Dist: requests; extra == "all"
38
+ Provides-Extra: dev
39
+ Requires-Dist: pytest>=7.0; extra == "dev"
40
+ Requires-Dist: pytest-django>=4.5; extra == "dev"
41
+ Requires-Dist: coverage>=6.0; extra == "dev"
42
+ Requires-Dist: tox>=3.25; extra == "dev"
38
43
  Dynamic: license-file
39
44
 
40
45
  ============================
@@ -50,9 +55,7 @@ Main utils:
50
55
  * data_structures
51
56
  * db
52
57
  * django
53
- * django_rest
54
58
  * math
55
- * pandas
56
59
  * exception
57
60
  * choices
58
61
 
@@ -64,7 +67,7 @@ Quick start
64
67
  from python_utils.time import date_range
65
68
  date_range(start_date, end_date)
66
69
 
67
- Although the library provides some utility functions related to other libraries like django and pandas, it does not install any dependencies automatically.
70
+ Although the library provides some utility functions related to other libraries like django, it does not install any dependencies automatically.
68
71
  This means, you can install the library even if you do not use these libraries, but keep in mind that in this case you cannot use the
69
72
  functions that depend on them.
70
73
 
@@ -74,7 +77,7 @@ You can also chose to install the dependencies alongside the library, including
74
77
 
75
78
  Tests
76
79
  -----
77
- The library has a 100% coverage by tests. If you want to see tests in action:
80
+ The library has a high coverage by tests. If you want to see tests in action:
78
81
 
79
82
  1. Inside venv, run ``pip install -r tests/requirements.txt``
80
83
 
@@ -0,0 +1,74 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.rst
4
+ pyproject.toml
5
+ cardo_python_utils.egg-info/PKG-INFO
6
+ cardo_python_utils.egg-info/SOURCES.txt
7
+ cardo_python_utils.egg-info/dependency_links.txt
8
+ cardo_python_utils.egg-info/requires.txt
9
+ cardo_python_utils.egg-info/top_level.txt
10
+ python_utils/__init__.py
11
+ python_utils/choices.py
12
+ python_utils/data_structures.py
13
+ python_utils/db.py
14
+ python_utils/django_utils.py
15
+ python_utils/esma_choices.py
16
+ python_utils/exceptions.py
17
+ python_utils/imports.py
18
+ python_utils/math.py
19
+ python_utils/text.py
20
+ python_utils/time.py
21
+ python_utils/types_hinting.py
22
+ python_utils/django/README.md
23
+ python_utils/django/__init__.py
24
+ python_utils/django/apps.py
25
+ python_utils/django/oidc_settings.py
26
+ python_utils/django/settings.py
27
+ python_utils/django/tenant_context.py
28
+ python_utils/django/admin/__init__.py
29
+ python_utils/django/admin/auth.py
30
+ python_utils/django/admin/user_group.py
31
+ python_utils/django/admin/views.py
32
+ python_utils/django/admin/templates/__init__.py
33
+ python_utils/django/admin/templates/user_groups_changelist.html
34
+ python_utils/django/api/__init__.py
35
+ python_utils/django/api/drf.py
36
+ python_utils/django/api/ninja.py
37
+ python_utils/django/api/utils.py
38
+ python_utils/django/auth/service.py
39
+ python_utils/django/celery/__init__.py
40
+ python_utils/django/celery/tenant_aware_database_scheduler.py
41
+ python_utils/django/celery/tenant_aware_task.py
42
+ python_utils/django/db/__init__.py
43
+ python_utils/django/db/alias.py
44
+ python_utils/django/db/routers.py
45
+ python_utils/django/db/transaction.py
46
+ python_utils/django/db/utils.py
47
+ python_utils/django/management/__init__.py
48
+ python_utils/django/management/commands/__init__.py
49
+ python_utils/django/management/commands/migrateall.py
50
+ python_utils/django/management/commands/shell.py
51
+ python_utils/django/management/commands/showmigrations.py
52
+ python_utils/django/management/commands/tenant_aware_command.py
53
+ python_utils/django/middleware/__init__.py
54
+ python_utils/django/middleware/tenant_aware_http_middleware.py
55
+ python_utils/django/middleware/tenant_aware_websocket_middleware.py
56
+ python_utils/django/migrations/0001_initial.py
57
+ python_utils/django/migrations/0001_initial_squashed_0005_alter_userrole_id.py
58
+ python_utils/django/migrations/0002_auto_20220120_1617.py
59
+ python_utils/django/migrations/0003_auto_20220513_1025.py
60
+ python_utils/django/migrations/0004_auto_20220817_1526.py
61
+ python_utils/django/migrations/0005_alter_userrole_id.py
62
+ python_utils/django/migrations/0006_userrole_organization_and_more.py
63
+ python_utils/django/migrations/0007_user_demo.py
64
+ python_utils/django/migrations/0008_delete_userrole.py
65
+ python_utils/django/migrations/__init__.py
66
+ python_utils/django/models/__init__.py
67
+ python_utils/django/models/user.py
68
+ python_utils/django/models/user_group.py
69
+ python_utils/django/redis/__init__.py
70
+ python_utils/django/redis/key_function.py
71
+ python_utils/django/storage/__init__.py
72
+ python_utils/django/storage/tenant_aware_storage.py
73
+ python_utils/django/tests/__init__.py
74
+ python_utils/django/tests/conftest.py
@@ -0,0 +1,20 @@
1
+
2
+ [all]
3
+ PyJWT>=2.10.1
4
+ mozilla-django-oidc>=4.0.1
5
+ python-keycloak>=5.8.1
6
+ requests
7
+
8
+ [dev]
9
+ pytest>=7.0
10
+ pytest-django>=4.5
11
+ coverage>=6.0
12
+ tox>=3.25
13
+
14
+ [django-keycloak]
15
+ PyJWT>=2.10.1
16
+ mozilla-django-oidc>=4.0.1
17
+ requests
18
+
19
+ [django-keycloak-groups]
20
+ python-keycloak>=5.8.1
@@ -0,0 +1,74 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cardo-python-utils"
7
+ version = "0.5.0"
8
+ description = "Python library enhanced with a wide range of functions for different scenarios."
9
+ readme = "README.rst"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "CardoAI", email = "hello@cardoai.com"},
14
+ ]
15
+ keywords = ["utilities", "helpers", "django"]
16
+ classifiers = [
17
+ "Environment :: Web Environment",
18
+ "Framework :: Django",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3 :: Only",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Topic :: Internet :: WWW/HTTP",
29
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
30
+ ]
31
+ dependencies = []
32
+
33
+ [project.optional-dependencies]
34
+ django-keycloak = [
35
+ "PyJWT>=2.10.1",
36
+ "mozilla-django-oidc>=4.0.1",
37
+ "requests",
38
+ ]
39
+ django-keycloak-groups = [
40
+ "python-keycloak>=5.8.1",
41
+ ]
42
+ all = [
43
+ "PyJWT>=2.10.1",
44
+ "mozilla-django-oidc>=4.0.1",
45
+ "python-keycloak>=5.8.1",
46
+ "requests",
47
+ ]
48
+ dev = [
49
+ "pytest>=7.0",
50
+ "pytest-django>=4.5",
51
+ "coverage>=6.0",
52
+ "tox>=3.25",
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/CardoAI/cardo-python-utils"
57
+ Repository = "https://github.com/CardoAI/cardo-python-utils.git"
58
+ Issues = "https://github.com/CardoAI/cardo-python-utils/issues"
59
+
60
+ [tool.setuptools]
61
+ include-package-data = true
62
+
63
+ [tool.setuptools.packages.find]
64
+ where = ["."]
65
+ exclude = ["tests", "tests.*"]
66
+
67
+ [tool.pytest.ini_options]
68
+ DJANGO_SETTINGS_MODULE = "tests.settings"
69
+ django_find_project = false
70
+ python_files = ["tests.py", "test_*.py", "*_tests.py"]
71
+ addopts = "--strict-markers --no-migrations --reuse-db --log-cli-level=INFO --doctest-modules"
72
+
73
+ [tool.tox]
74
+ legacy_tox_ini = "tox.ini"
@@ -9,6 +9,7 @@ It adds some useful methods to the Enum class, such as:
9
9
 
10
10
  from abc import ABC, abstractmethod
11
11
  from enum import EnumMeta, Enum
12
+ from typing import Union
12
13
 
13
14
 
14
15
  class IChoice(ABC):
@@ -41,7 +42,7 @@ class ChoiceEnumMeta(EnumMeta, IChoice, ABC):
41
42
 
42
43
  return new_cls
43
44
 
44
- def __contains__(cls, item: int | str) -> bool:
45
+ def __contains__(cls, item: Union[int, str]) -> bool:
45
46
  if isinstance(item, int):
46
47
  member_values = [v.value[0] for v in cls.__members__.values()]
47
48
  elif isinstance(item, str):
@@ -75,12 +76,12 @@ class ChoiceEnum(Enum, metaclass=ChoiceEnumMeta):
75
76
  return {elm.value[0]: elm.value[1] for elm in cls}
76
77
 
77
78
  @classmethod
78
- def get_by_value(cls, value: str | int):
79
- value_index = 0 if type(value) == int else 1
79
+ def get_by_value(cls, value: Union[str, int]):
80
+ value_index = 0 if isinstance(value, int) else 1
80
81
  return next((v for v in cls.__members__.values() if v.value[value_index] == value), None)
81
82
 
82
83
  @classmethod
83
- def list_as(cls, item_type) -> list[int | str]:
84
+ def list_as(cls, item_type) -> list[Union[int, str]]:
84
85
  if item_type not in [int, str]:
85
86
  raise TypeError('Invalid item type')
86
87
  return list(map(item_type, cls))
@@ -0,0 +1,227 @@
1
+ This package provides utilities for facilitating IDP communication and multi-tenancy support.
2
+
3
+ # Usage
4
+
5
+ ## Environment variables to set
6
+
7
+ - AWS_STORAGE_TENANT_BUCKET_NAMES
8
+ - _This variable should be set if separate tenant buckets are needed._
9
+ - A JSON dictionary where each key is the tenant name and the value is the bucket name.
10
+ - DATABASE_CONFIG
11
+ - A JSON dictionary where each key is the tenant name and the value is a dict with the datase config.
12
+ - If multiple 'DATABASE_CONFIG'-prefixed variables are set, they will be merged into a single dictionary.
13
+ - KEYCLOAK_CONFIDENTIAL_CLIENT_ID
14
+ - The id of the confidential client of the backend service
15
+ - KEYCLOAK_CONFIDENTIAL_CLIENT_SERVICE_ACCOUNT_TOKEN_FILE_PATHS
16
+ - A JSON dictionary where each key is the tenant name and the value is the file path of the service account token for the confidential client of that tenant
17
+
18
+ ## settings.py file
19
+
20
+ ### For multi-tenancy
21
+
22
+ ```python3
23
+ INSTALLED_APPS = [
24
+ ...
25
+ "python_utils.django",
26
+ ...
27
+ ]
28
+
29
+ MIDDLEWARE = [
30
+ "python_utils.django.middleware.TenantAwareHttpMiddleware",
31
+ ...
32
+ ]
33
+
34
+ AUTH_USER_MODEL = "idp_user.User"
35
+
36
+ # Include the database configuration for each tenant in the DATABASES setting.
37
+ # You can use the get_database_configs() function from python_utils.django.db.utils as a helper.
38
+ from python_utils.django.db.utils import get_database_configs
39
+
40
+ for tenant, tenant_db_config in get_database_configs().items():
41
+ DATABASES[tenant] = {
42
+ "ENGINE": "django.db.backends.postgresql",
43
+ "NAME": tenant_db_config["name"],
44
+ "USER": tenant_db_config["user"],
45
+ "PASSWORD": tenant_db_config["password"],
46
+ "HOST": tenant_db_config["host"],
47
+ "PORT": tenant_db_config.get("port", 5432),
48
+ }
49
+
50
+ # If you want to override the database alias to use for local development (when DEBUG is True).
51
+ # By default, the first database defined in DATABASES is used.
52
+ DEVELOPMENT_TENANT = "development"
53
+
54
+ # This is required to use the tenant context when routing database queries
55
+ DATABASE_ROUTERS = ["python_utils.django.db.routers.TenantAwareRouter"]
56
+
57
+ # If using celery, set the task class to TenantAwareTask:
58
+ CELERY_TASK_CLS = "python_utils.django.celery.TenantAwareTask"
59
+
60
+ # If using Redis caching, configure the cache backend as follows:
61
+ CACHES = {
62
+ "default": {
63
+ "BACKEND": "django_redis.cache.RedisCache",
64
+ "LOCATION": REDIS_LOCATION,
65
+ "KEY_FUNCTION": "python_utils.django.redis.make_tenant_aware_key",
66
+ **OPTIONS,
67
+ }
68
+ }
69
+
70
+ # If using Django Storages with S3, and separate tenant buckets are needed,
71
+ # configure the storage backends as follows:
72
+ STORAGES = {
73
+ "default": {
74
+ "BACKEND": "python_utils.django.storage.TenantAwarePrivateS3Storage",
75
+ },
76
+ }
77
+
78
+ # If you want to exclude certain paths from tenant processing, use TENANT_AWARE_EXCLUDED_PATHS:
79
+ # They are considered as prefixes, so all paths starting with the given strings will be excluded.
80
+ TENANT_AWARE_EXCLUDED_PATHS = ("/some/path",)
81
+ ```
82
+
83
+ ### For OIDC auth
84
+
85
+ ```python3
86
+ from python_utils.django.admin.templates import TEMPLATE_PATH
87
+
88
+ INSTALLED_APPS.append("mozilla_django_oidc")
89
+ TEMPLATES[0]["DIRS"].append(TEMPLATE_PATH)
90
+
91
+ JWT_AUDIENCE = "myapp"
92
+ JWT_SCOPE_PREFIX = "myapp"
93
+
94
+ # If using DRF
95
+ REST_FRAMEWORK.update(
96
+ {
97
+ "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
98
+ "DEFAULT_AUTHENTICATION_CLASSES": ("python_utils.django.api.drf.AuthenticationBackend",),
99
+ "DEFAULT_PERMISSION_CLASSES": (
100
+ "rest_framework.permissions.IsAuthenticated",
101
+ "python_utils.django.api.drf.HasScope",
102
+ ),
103
+ }
104
+ )
105
+
106
+ # Admin auth backends
107
+ AUTHENTICATION_BACKENDS = [
108
+ "django.contrib.auth.backends.ModelBackend",
109
+ "python_utils.django.admin.auth.AdminAuthenticationBackend",
110
+ ]
111
+
112
+ # If user groups are used for Row Level Security (RLS)
113
+ KEYCLOAK_USER_GROUP_MODEL = "myapp.UserGroup"
114
+
115
+ KEYCLOAK_CONFIDENTIAL_CLIENT_ID = os.getenv("KEYCLOAK_CONFIDENTIAL_CLIENT_ID", f"{JWT_AUDIENCE}_confidential")
116
+
117
+ OIDC_RP_CLIENT_ID = KEYCLOAK_CONFIDENTIAL_CLIENT_ID
118
+ OIDC_RP_SIGN_ALGO = "RS256"
119
+ OIDC_CREATE_USER = True
120
+ OIDC_AUTHENTICATE_CLASS = "python_utils.django.admin.views.TenantAwareOIDCAuthenticationRequestView"
121
+
122
+ LOGIN_REDIRECT_URL = "/admin"
123
+ SESSION_COOKIE_AGE = 60 * 30 # 30 minutes
124
+ SESSION_SAVE_EVERY_REQUEST = True # Extend session on each request
125
+
126
+ # If using django-easy-audit
127
+
128
+ from python_utils.django.db.alias import DynamicDatabaseAlias
129
+ DJANGO_EASY_AUDIT_DATABASE_ALIAS = DynamicDatabaseAlias()
130
+ ```
131
+
132
+ ## urls.py file
133
+
134
+ The views of the `mozilla-django-oidc` package need to be exposed as well, for the OIDC auth:
135
+
136
+ ```python3
137
+ urlpatterns.append(path("oidc/", include("mozilla_django_oidc.urls")))
138
+ ```
139
+
140
+ ## admin.py file
141
+
142
+ The Django Admin Panel needs to be configured to automatically redirect to the OIDC login page:
143
+
144
+ ```python3
145
+ from python_utils.django.admin.auth import has_admin_site_permission
146
+ from python_utils.django.admin.views import TenantAwareOIDCAuthenticationRequestView
147
+
148
+ admin.site.login = TenantAwareOIDCAuthenticationRequestView.as_view()
149
+ admin.site.has_permission = has_admin_site_permission
150
+ ```
151
+
152
+ ## With django-ninja
153
+
154
+ If using `django-ninja`, apart from the settings configured above, auth utils are provided in the django/api/ninja.py module.
155
+
156
+ ## Atomic Transactions
157
+
158
+ Django's `transaction.atomic` uses the default database. To make it tenant-aware, use `tenant_atomic`.
159
+ If `transaction.on_commit` is used, make sure to pass the tenant as DB alias as well:
160
+
161
+ ```python3
162
+ from python_utils.django.db.transaction import tenant_atomic
163
+
164
+ @tenant_atomic
165
+ def my_function():
166
+ # Some logic
167
+
168
+ transaction.on_commit(do_smth, using=TenantContext.get())
169
+ ```
170
+
171
+ ## Explicit database connection
172
+
173
+ If using django.db.connection anywhere in the code, you need to change that to get a tenant-aware connection:
174
+
175
+ ```python3
176
+ from python_utils.django.db.utils import get_connection
177
+ from python_utils.django.tenant_context import TenantContext
178
+
179
+ connection = get_connection(TenantContext.get())
180
+ ```
181
+
182
+ ## Django Shell
183
+
184
+ This library overrides the shell command of Django, so that it requires the `tenant` arg.
185
+ This way, the shell is automatically initialized with the context set to the tenant.
186
+
187
+ ```bash
188
+ ./manage.py shell --tenant=tenant1
189
+
190
+ Starting shell for tenant: -tenant=tenant
191
+ >>>
192
+ ```
193
+
194
+ ## Testing
195
+
196
+ In order for tests to work, create the following autouse fixtures:
197
+
198
+ ```python3
199
+ import pytest
200
+
201
+ from python_utils.django.tenant_context import TenantContext
202
+
203
+ # Add this, if the test utils of the package are needed
204
+ pytest_plugins = ["python_utils.django.tests"]
205
+
206
+
207
+ @pytest.fixture(scope="session", autouse=True)
208
+ def test_database() -> str:
209
+ return "default"
210
+
211
+
212
+ @pytest.fixture(scope="session", autouse=True)
213
+ def set_tenant_context_session(test_database):
214
+ """Set tenant context for the entire test session."""
215
+ TenantContext.set(test_database)
216
+ yield
217
+ TenantContext.clear()
218
+
219
+
220
+ @pytest.fixture(autouse=True)
221
+ def set_tenant_context(set_tenant_context_session, test_database):
222
+ """Ensure tenant context is set for each test (depends on session fixture)."""
223
+ # Re-set in case it was cleared between tests
224
+ if not TenantContext.is_set():
225
+ TenantContext.set(test_database)
226
+ yield
227
+ ```
@@ -0,0 +1 @@
1
+ default_app_config = "python_utils.django.apps.DjangoAppConfig"