django-pfx 1.4.dev68__tar.gz → 1.4.dev72__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 (178) hide show
  1. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/.gitlab-ci.yml +6 -3
  2. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/.pre-commit-config.yaml +7 -0
  3. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/PKG-INFO +1 -1
  4. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/django_pfx.egg-info/PKG-INFO +1 -1
  5. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/django_pfx.egg-info/SOURCES.txt +31 -1
  6. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/manage.py +15 -6
  7. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/decorator/rest.py +3 -3
  8. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +19 -11
  9. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/abstract_pfx_base_user.py +10 -0
  10. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/pfx_user.py +2 -2
  11. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/authentication_views.py +4 -9
  12. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/rest_views.py +7 -1
  13. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/migrations/0001_initial.py +1 -14
  14. django_pfx-1.4.dev72/tests/migrations/0002_alter_author_options.py +18 -0
  15. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/models.py +1 -13
  16. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_client.py +22 -1
  17. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_permissions.py +46 -0
  18. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/views.py +9 -1
  19. django_pfx-1.4.dev72/tests_base_user/__init__.py +0 -0
  20. django_pfx-1.4.dev72/tests_base_user/migrations/0001_initial.py +13 -0
  21. django_pfx-1.4.dev72/tests_base_user/migrations/__init__.py +0 -0
  22. django_pfx-1.4.dev72/tests_base_user/settings/__init__.py +0 -0
  23. django_pfx-1.4.dev72/tests_base_user/settings/ci.py +18 -0
  24. django_pfx-1.4.dev72/tests_base_user/settings/common.py +80 -0
  25. django_pfx-1.4.dev72/tests_base_user/settings/dev.py +13 -0
  26. django_pfx-1.4.dev72/tests_base_user/settings/dev_custom_example.py +28 -0
  27. django_pfx-1.4.dev72/tests_base_user/settings/dev_default.py +12 -0
  28. django_pfx-1.4.dev72/tests_base_user/tests/__init__.py +2 -0
  29. django_pfx-1.4.dev72/tests_base_user/tests/test_api.py +32 -0
  30. django_pfx-1.4.dev72/tests_base_user/tests/test_auth_api.py +59 -0
  31. django_pfx-1.4.dev72/tests_base_user/urls.py +13 -0
  32. django_pfx-1.4.dev72/tests_base_user/views.py +13 -0
  33. django_pfx-1.4.dev72/tests_custom_user/__init__.py +0 -0
  34. django_pfx-1.4.dev72/tests_custom_user/migrations/0001_initial.py +31 -0
  35. django_pfx-1.4.dev72/tests_custom_user/migrations/__init__.py +0 -0
  36. django_pfx-1.4.dev72/tests_custom_user/models.py +18 -0
  37. django_pfx-1.4.dev72/tests_custom_user/settings/__init__.py +0 -0
  38. django_pfx-1.4.dev72/tests_custom_user/settings/ci.py +18 -0
  39. django_pfx-1.4.dev72/tests_custom_user/settings/common.py +80 -0
  40. django_pfx-1.4.dev72/tests_custom_user/settings/dev.py +13 -0
  41. django_pfx-1.4.dev72/tests_custom_user/settings/dev_custom_example.py +28 -0
  42. django_pfx-1.4.dev72/tests_custom_user/settings/dev_default.py +12 -0
  43. django_pfx-1.4.dev72/tests_custom_user/tests/__init__.py +2 -0
  44. django_pfx-1.4.dev72/tests_custom_user/tests/test_api.py +24 -0
  45. django_pfx-1.4.dev72/tests_custom_user/tests/test_auth_api.py +57 -0
  46. django_pfx-1.4.dev72/tests_custom_user/urls.py +13 -0
  47. django_pfx-1.4.dev72/tests_custom_user/views.py +13 -0
  48. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/.gitignore +0 -0
  49. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/LICENSE +0 -0
  50. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/MANIFEST.in +0 -0
  51. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/README.md +0 -0
  52. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/django_pfx.egg-info/dependency_links.txt +0 -0
  53. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/django_pfx.egg-info/requires.txt +0 -0
  54. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/django_pfx.egg-info/top_level.txt +0 -0
  55. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/Makefile +0 -0
  56. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/conf.py +0 -0
  57. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/index.rst +0 -0
  58. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/api.views.rst +0 -0
  59. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/authentication.md +0 -0
  60. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/decorator.md +0 -0
  61. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/generate_openapi.md +0 -0
  62. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/getting_started.md +0 -0
  63. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/internationalisation.md +0 -0
  64. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/model.md +0 -0
  65. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/pfx_views.md +0 -0
  66. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/profiling.md +0 -0
  67. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/settings.md +0 -0
  68. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/doc/source/testing.md +0 -0
  69. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/img/pfx.png +0 -0
  70. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/img/pfx.svg +0 -0
  71. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/make_messages +0 -0
  72. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/__init__.py +0 -0
  73. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/__init__.py +0 -0
  74. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/apidoc/__init__.py +0 -0
  75. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/apidoc/parameters.py +0 -0
  76. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/apidoc/schema.py +0 -0
  77. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/apidoc/tags.py +0 -0
  78. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/apps.py +0 -0
  79. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/decorator/__init__.py +0 -0
  80. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/default_settings.py +0 -0
  81. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/exceptions.py +0 -0
  82. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/fields.py +0 -0
  83. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/http/__init__.py +0 -0
  84. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/http/json_response.py +0 -0
  85. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  86. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/management/__init__.py +0 -0
  87. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/management/commands/__init__.py +0 -0
  88. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  89. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/management/commands/profile.py +0 -0
  90. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/middleware/__init__.py +0 -0
  91. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/middleware/authentication.py +0 -0
  92. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/middleware/locale.py +0 -0
  93. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/middleware/profiling.py +0 -0
  94. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  95. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  96. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  97. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/migrations/__init__.py +0 -0
  98. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/__init__.py +0 -0
  99. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/cache_mixins.py +0 -0
  100. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/login_ban.py +0 -0
  101. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/not_null_fields.py +0 -0
  102. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
  103. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/pfx_models.py +0 -0
  104. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  105. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/serializers/__init__.py +0 -0
  106. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/serializers/json.py +0 -0
  107. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/settings.py +0 -0
  108. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/shortcuts.py +0 -0
  109. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/storage/__init__.py +0 -0
  110. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/storage/s3_storage.py +0 -0
  111. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  112. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  113. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  114. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  115. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  116. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  117. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/test.py +0 -0
  118. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/urls.py +0 -0
  119. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/__init__.py +0 -0
  120. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/fields.py +0 -0
  121. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/filters_views.py +0 -0
  122. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/locale_views.py +0 -0
  123. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  124. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  125. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/groups.py +0 -0
  126. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  127. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  128. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  129. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  130. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  131. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  132. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  133. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  134. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  135. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset.py +0 -0
  136. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  137. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  138. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  139. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  140. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  141. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/settings/__init__.py +0 -0
  142. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pfx/settings/dev.py +0 -0
  143. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/pyproject.toml +0 -0
  144. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/requirements.txt +0 -0
  145. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/serve-doc +0 -0
  146. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/setup.cfg +0 -0
  147. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/setup.py +0 -0
  148. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/__init__.py +0 -0
  149. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  150. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/migrations/__init__.py +0 -0
  151. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/__init__.py +0 -0
  152. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/ci.py +0 -0
  153. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/common.py +0 -0
  154. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/dev.py +0 -0
  155. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/dev_custom_example.py +0 -0
  156. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/settings/dev_default.py +0 -0
  157. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/__init__.py +0 -0
  158. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/basic_api_errors.py +0 -0
  159. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/basic_api_test.py +0 -0
  160. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_api_doc.py +0 -0
  161. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_api_doc_search.py +0 -0
  162. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_auth_api.py +0 -0
  163. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_body_mixin.py +0 -0
  164. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_cache.py +0 -0
  165. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_fields.py +0 -0
  166. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_filters.py +0 -0
  167. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_locale_api.py +0 -0
  168. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_perm_tests.py +0 -0
  169. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_perms_api.py +0 -0
  170. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_profiling_middleware.py +0 -0
  171. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_settings.py +0 -0
  172. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_shortcuts.py +0 -0
  173. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_timezone_middleware.py +0 -0
  174. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_tools.py +0 -0
  175. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_user_queryset.py +0 -0
  176. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_view_decorators.py +0 -0
  177. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/tests/test_view_fields.py +0 -0
  178. {django_pfx-1.4.dev68 → django_pfx-1.4.dev72}/tests/urls.py +0 -0
@@ -33,19 +33,22 @@ quality check:
33
33
  - isort . -c
34
34
  - ./make_messages
35
35
  - git diff --exit-code # exit if messages changed
36
- - python manage.py makemigrations --check --dry-run --setting='pfx.settings.dev'
36
+ - python manage.py makemigrations --check --dry-run
37
+ - python manage.py makemigrations tests_base_user --check --dry-run
38
+ - python manage.py makemigrations tests_custom_user --check --dry-run
37
39
 
38
40
  test:
39
41
  variables:
40
42
  POSTGRES_DB: ci
41
43
  POSTGRES_USER: postgres
42
44
  POSTGRES_PASSWORD: postgres
43
- DJANGO_SETTINGS_MODULE: 'tests.settings.ci'
44
45
  script:
45
46
  - apt-get update
46
47
  - apt-get install -y gettext
47
48
  - python manage.py compilemessages -i venv
48
- - coverage run --source='.' manage.py test
49
+ - coverage run -a --source='.' manage.py test
50
+ - coverage run -a --source='.' manage.py test tests_base_user
51
+ - coverage run -a --source='.' manage.py test tests_custom_user
49
52
  - coverage report
50
53
  - coverage xml
51
54
  - coverage html
@@ -20,3 +20,10 @@ repos:
20
20
  entry: isort
21
21
  language: system
22
22
  types: [python]
23
+ - repo: local
24
+ hooks:
25
+ - id: make-messages
26
+ name: make messages
27
+ entry: ./make_messages
28
+ language: system
29
+ types: [python]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev68
3
+ Version: 1.4.dev72
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-pfx
3
- Version: 1.4.dev68
3
+ Version: 1.4.dev72
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -115,6 +115,7 @@ tests/urls.py
115
115
  tests/views.py
116
116
  tests/locale/fr/LC_MESSAGES/django.po
117
117
  tests/migrations/0001_initial.py
118
+ tests/migrations/0002_alter_author_options.py
118
119
  tests/migrations/__init__.py
119
120
  tests/settings/__init__.py
120
121
  tests/settings/ci.py
@@ -144,4 +145,33 @@ tests/tests/test_timezone_middleware.py
144
145
  tests/tests/test_tools.py
145
146
  tests/tests/test_user_queryset.py
146
147
  tests/tests/test_view_decorators.py
147
- tests/tests/test_view_fields.py
148
+ tests/tests/test_view_fields.py
149
+ tests_base_user/__init__.py
150
+ tests_base_user/urls.py
151
+ tests_base_user/views.py
152
+ tests_base_user/migrations/0001_initial.py
153
+ tests_base_user/migrations/__init__.py
154
+ tests_base_user/settings/__init__.py
155
+ tests_base_user/settings/ci.py
156
+ tests_base_user/settings/common.py
157
+ tests_base_user/settings/dev.py
158
+ tests_base_user/settings/dev_custom_example.py
159
+ tests_base_user/settings/dev_default.py
160
+ tests_base_user/tests/__init__.py
161
+ tests_base_user/tests/test_api.py
162
+ tests_base_user/tests/test_auth_api.py
163
+ tests_custom_user/__init__.py
164
+ tests_custom_user/models.py
165
+ tests_custom_user/urls.py
166
+ tests_custom_user/views.py
167
+ tests_custom_user/migrations/0001_initial.py
168
+ tests_custom_user/migrations/__init__.py
169
+ tests_custom_user/settings/__init__.py
170
+ tests_custom_user/settings/ci.py
171
+ tests_custom_user/settings/common.py
172
+ tests_custom_user/settings/dev.py
173
+ tests_custom_user/settings/dev_custom_example.py
174
+ tests_custom_user/settings/dev_default.py
175
+ tests_custom_user/tests/__init__.py
176
+ tests_custom_user/tests/test_api.py
177
+ tests_custom_user/tests/test_auth_api.py
@@ -18,11 +18,20 @@ writer.MIGRATION_HEADER_TEMPLATE = """\
18
18
 
19
19
  def main():
20
20
  """Run administrative tasks."""
21
- cmd = len(sys.argv) > 1 and sys.argv[1]
22
- os.environ.setdefault(
23
- "DJANGO_SETTINGS_MODULE",
24
- cmd in ('test', 'makemigrations') and
25
- "tests.settings.dev" or "pfx.settings.dev")
21
+ mode = os.environ.get('CI', '').lower() == 'true' and 'ci' or 'dev'
22
+ argv = [a for a in sys.argv if not a.startswith('--')]
23
+ options = [a for a in sys.argv if a.startswith('--')]
24
+ settings = f"pfx.settings.dev"
25
+ cmd = len(argv) > 1 and argv[1]
26
+ if cmd == 'test':
27
+ app = len(argv) > 2 and argv[2] or 'tests'
28
+ if len(argv) <= 2:
29
+ argv.append('tests')
30
+ settings = f"{app.split('.')[0]}.settings.{mode}"
31
+ elif cmd == 'makemigrations':
32
+ app = len(argv) > 2 and argv[2] or 'pfx'
33
+ settings = f"{app}.settings.{app == 'pfx' and 'dev' or 'common'}"
34
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings)
26
35
  try:
27
36
  from django.core.management import execute_from_command_line
28
37
  except ImportError as exc:
@@ -31,7 +40,7 @@ def main():
31
40
  "available on your PYTHONPATH environment variable? Did you "
32
41
  "forget to activate a virtual environment?"
33
42
  ) from exc
34
- execute_from_command_line(sys.argv)
43
+ execute_from_command_line([*argv, *options])
35
44
 
36
45
 
37
46
  if __name__ == '__main__':
@@ -14,8 +14,8 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  def rest_api(
17
- path, method='get', public=None, priority=0, priority_doc=0,
18
- parameters=None,
17
+ path, method='get', public=None, perms=None,
18
+ priority=0, priority_doc=0, parameters=None,
19
19
  request_schema=None, response_schema=None, filters=False,
20
20
  search=False, groups=None):
21
21
  def decorator(func):
@@ -31,7 +31,7 @@ def rest_api(
31
31
  'HTTP_X_PRINT_REQUEST' in request.META):
32
32
  print(format_request(request))
33
33
  try:
34
- self.check_perm(public, func.__name__, *args, **kwargs)
34
+ self.check_perm(public, func.__name__, perms, *args, **kwargs)
35
35
  return func(self, *args, **kwargs)
36
36
  except APIError as e:
37
37
  return e.response
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: \n"
9
9
  "Report-Msgid-Bugs-To: \n"
10
- "POT-Creation-Date: 2025-01-21 14:22+0100\n"
10
+ "POT-Creation-Date: 2025-01-21 18:35+0100\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -59,6 +59,14 @@ msgstr ""
59
59
  "Format non valide, il peut s’agir d’un nombre en heures, « 1:05 », « :05 », "
60
60
  "« 1h 5m », « 1.5h » ou « 30m »."
61
61
 
62
+ #: models/abstract_pfx_base_user.py:35
63
+ msgid "user"
64
+ msgstr ""
65
+
66
+ #: models/abstract_pfx_base_user.py:36
67
+ msgid "users"
68
+ msgstr ""
69
+
62
70
  #: models/login_ban.py:45
63
71
  msgid "Username"
64
72
  msgstr "Nom d’utilisateur"
@@ -95,7 +103,7 @@ msgstr "Compte HOTP"
95
103
  msgid "HOTP expiry"
96
104
  msgstr "Expiration HOTP"
97
105
 
98
- #: models/otp_user_mixin.py:29 views/authentication_views.py:496
106
+ #: models/otp_user_mixin.py:29 views/authentication_views.py:491
99
107
  msgid "OTP enabled"
100
108
  msgstr "OTP activé"
101
109
 
@@ -209,7 +217,7 @@ msgstr ""
209
217
  msgid "Successful login"
210
218
  msgstr "Connexion réussie"
211
219
 
212
- #: views/authentication_views.py:243 views/authentication_views.py:413
220
+ #: views/authentication_views.py:243 views/authentication_views.py:408
213
221
  msgid "password updated successfully"
214
222
  msgstr "le mot de passe a été mis à jour avec succès"
215
223
 
@@ -217,31 +225,31 @@ msgstr "le mot de passe a été mis à jour avec succès"
217
225
  msgid "Incorrect password"
218
226
  msgstr "Mot de passe incorrect"
219
227
 
220
- #: views/authentication_views.py:251 views/authentication_views.py:422
228
+ #: views/authentication_views.py:251 views/authentication_views.py:417
221
229
  msgid "Empty password is not allowed"
222
230
  msgstr "Un mot de passe vide n’est pas autorisé"
223
231
 
224
- #: views/authentication_views.py:347
232
+ #: views/authentication_views.py:342
225
233
  msgid "User and token are valid"
226
234
  msgstr "L'utilisateur et le token sont valides"
227
235
 
228
- #: views/authentication_views.py:349
236
+ #: views/authentication_views.py:344
229
237
  msgid "User or token is invalid"
230
238
  msgstr "L'utilisateur ou le token est invalide"
231
239
 
232
- #: views/authentication_views.py:456
240
+ #: views/authentication_views.py:451
233
241
  msgid "OTP is already enabled"
234
242
  msgstr "OTP est déjà activé"
235
243
 
236
- #: views/authentication_views.py:497 views/authentication_views.py:533
244
+ #: views/authentication_views.py:492 views/authentication_views.py:528
237
245
  msgid "Invalid code"
238
246
  msgstr "Code invalide"
239
247
 
240
- #: views/authentication_views.py:532
248
+ #: views/authentication_views.py:527
241
249
  msgid "OTP disabled"
242
250
  msgstr "OTP désactivé"
243
251
 
244
- #: views/authentication_views.py:792
252
+ #: views/authentication_views.py:787
245
253
  msgid ""
246
254
  "If the email address you entered is correct, you will receive an email from "
247
255
  "us with instructions to reset your password."
@@ -250,7 +258,7 @@ msgstr ""
250
258
  "un courrier électronique de notre part contenant des instructions pour "
251
259
  "réinitialiser votre mot de passe."
252
260
 
253
- #: views/authentication_views.py:866
261
+ #: views/authentication_views.py:861
254
262
  msgid "A new authentication code has been sent by email."
255
263
  msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
256
264
 
@@ -1,4 +1,5 @@
1
1
  from django.contrib.auth.models import AbstractBaseUser, AbstractUser
2
+ from django.utils.translation import gettext_lazy as _
2
3
 
3
4
  from .pfx_models import PFXModelMixin
4
5
 
@@ -9,6 +10,13 @@ class AbstractPFXBaseUser(PFXModelMixin, AbstractBaseUser):
9
10
  class Meta:
10
11
  abstract = True
11
12
 
13
+ def auth_json_repr(self):
14
+ return self.json_repr()
15
+
16
+ @classmethod
17
+ def auth_json_repr_schema(cls):
18
+ return cls.json_repr_schema()
19
+
12
20
  def get_user_jwt_signature_key(self):
13
21
  """
14
22
  Return a user secret to sign JWT token.
@@ -24,4 +32,6 @@ class AbstractPFXUser(AbstractUser, AbstractPFXBaseUser):
24
32
  """The base abstract user for PFX with permissions mixin."""
25
33
 
26
34
  class Meta:
35
+ verbose_name = _("user")
36
+ verbose_name_plural = _("users")
27
37
  abstract = True
@@ -1,4 +1,4 @@
1
- from django.contrib.auth.models import AbstractUser
1
+ # from django.contrib.auth.models import AbstractUser
2
2
 
3
3
  from .abstract_pfx_base_user import AbstractPFXUser
4
4
 
@@ -7,5 +7,5 @@ class PFXUser(AbstractPFXUser):
7
7
  """The Django User with PFX mixins.
8
8
  """
9
9
 
10
- class Meta(AbstractUser.Meta):
10
+ class Meta(AbstractPFXUser.Meta):
11
11
  swappable = "AUTH_USER_MODEL"
@@ -20,7 +20,7 @@ from django.views.decorators.debug import sensitive_post_parameters
20
20
 
21
21
  import jwt
22
22
 
23
- from pfx.pfxcore.apidoc import ModelSchema, Schema, Tag
23
+ from pfx.pfxcore.apidoc import Schema, Tag
24
24
  from pfx.pfxcore.decorator import rest_api, rest_doc, rest_view
25
25
  from pfx.pfxcore.exceptions import (
26
26
  AuthenticationError,
@@ -286,12 +286,7 @@ class AuthenticationView(
286
286
  Can be overridden to customize result.
287
287
 
288
288
  :param user: The user"""
289
- info = {
290
- 'username': user.get_username(),
291
- 'first_name': user.first_name,
292
- 'last_name': user.last_name,
293
- 'email': user.email
294
- }
289
+ info = user.auth_json_repr()
295
290
  if isinstance(user, OtpUserMixin):
296
291
  info.update(is_otp=user.is_otp)
297
292
  return info
@@ -301,8 +296,8 @@ class AuthenticationView(
301
296
  """Get user representation schema.
302
297
 
303
298
  Can be overridden to customize result."""
304
- return ModelSchema(UserModel, cls._process_fields([
305
- 'username', 'first_name', 'last_name', 'email']))
299
+ return Schema(
300
+ 'auth_user', "User", **UserModel.auth_json_repr_schema())
306
301
 
307
302
  @method_decorator(sensitive_post_parameters())
308
303
  @method_decorator(never_cache)
@@ -1325,7 +1325,7 @@ class SecuredRestViewMixin(View):
1325
1325
  return getattr(self, param)
1326
1326
  return self.default_public if public is None else public
1327
1327
 
1328
- def check_perm(self, public, func_name, *args, **kwargs):
1328
+ def check_perm(self, public, func_name, perms, *args, **kwargs):
1329
1329
  """Check permissions for a specific service.
1330
1330
 
1331
1331
  Do all checks for a specific service and raise
@@ -1338,6 +1338,12 @@ class SecuredRestViewMixin(View):
1338
1338
  return
1339
1339
  if not self.request.user.is_authenticated:
1340
1340
  raise UnauthorizedError()
1341
+ if isinstance(perms, str):
1342
+ if not self.request.user.has_perm(perms):
1343
+ raise ForbiddenError()
1344
+ elif perms:
1345
+ if not self.request.user.has_perms(perms):
1346
+ raise ForbiddenError()
1341
1347
  if not self.perm():
1342
1348
  raise ForbiddenError()
1343
1349
  fperm = f'{func_name}_perm'
@@ -1,4 +1,4 @@
1
- # Generated by Django 4.2.17 on 2025-01-21 04:24
1
+ # Generated by Django 4.2.17 on 2025-01-21 08:32
2
2
  # flake8: noqa
3
3
 
4
4
  import django.contrib.auth.models
@@ -56,19 +56,6 @@ class Migration(migrations.Migration):
56
56
  },
57
57
  bases=(pfx.pfxcore.models.cache_mixins.CacheDependsMixin, pfx.pfxcore.models.pfx_models.PFXModelMixin, models.Model),
58
58
  ),
59
- migrations.CreateModel(
60
- name='TestModel',
61
- fields=[
62
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
63
- ('name', models.CharField(max_length=30, verbose_name='Name')),
64
- ],
65
- options={
66
- 'verbose_name': 'TestModel',
67
- 'verbose_name_plural': 'TestModels',
68
- 'ordering': ['name', 'pk'],
69
- },
70
- bases=(pfx.pfxcore.models.pfx_models.JSONReprMixin, models.Model),
71
- ),
72
59
  migrations.CreateModel(
73
60
  name='Book',
74
61
  fields=[
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.17 on 2025-01-22 03:31
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('tests', '0001_initial'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterModelOptions(
15
+ name='author',
16
+ options={'ordering': ['last_name', 'first_name', 'pk'], 'permissions': [('can_customize_author', 'Can customize author')], 'verbose_name': 'Author', 'verbose_name_plural': 'Authors'},
17
+ ),
18
+ ]
@@ -89,6 +89,7 @@ class Author(CacheableMixin, JSONReprMixin, models.Model):
89
89
  verbose_name = "Author"
90
90
  verbose_name_plural = "Authors"
91
91
  ordering = ['last_name', 'first_name', 'pk']
92
+ permissions = [("can_customize_author", "Can customize author")]
92
93
 
93
94
  def __str__(self):
94
95
  return f"{self.first_name} {self.last_name}"
@@ -166,16 +167,3 @@ class Book(CacheDependsMixin, PFXModelMixin, models.Model):
166
167
  type: string
167
168
  """
168
169
  return super().json_repr(author_name=str(self.author), **values)
169
-
170
-
171
- class TestModel(JSONReprMixin, models.Model):
172
-
173
- name = models.CharField("Name", max_length=30)
174
-
175
- class Meta:
176
- verbose_name = "TestModel"
177
- verbose_name_plural = "TestModels"
178
- ordering = ['name', 'pk']
179
-
180
- def __str__(self):
181
- return self.name
@@ -1,3 +1,4 @@
1
+ from django.db import connection, models
1
2
  from django.http import HttpResponse
2
3
  from django.test import TestCase
3
4
  from django.test.utils import override_settings
@@ -6,9 +7,22 @@ from django.urls import include, path
6
7
  from pfx.pfxcore import register_views
7
8
  from pfx.pfxcore.decorator import rest_api, rest_view
8
9
  from pfx.pfxcore.http import JsonResponse
10
+ from pfx.pfxcore.models import JSONReprMixin
9
11
  from pfx.pfxcore.test import APIClient, TestAssertMixin
10
12
  from pfx.pfxcore.views import RestView
11
- from tests.models import TestModel, User
13
+ from tests.models import User
14
+
15
+
16
+ class TestModel(JSONReprMixin, models.Model):
17
+ name = models.CharField("Name", max_length=30)
18
+
19
+ class Meta:
20
+ verbose_name = "TestModel"
21
+ verbose_name_plural = "TestModels"
22
+ ordering = ['name', 'pk']
23
+
24
+ def __str__(self):
25
+ return self.name
12
26
 
13
27
 
14
28
  @rest_view("/test")
@@ -56,8 +70,15 @@ class TestApiClient(TestAssertMixin, TestCase):
56
70
  def setUp(self):
57
71
  self.client = APIClient(default_locale='en')
58
72
 
73
+ # @classmethod
74
+ # def setUpClass(cls):
75
+
76
+ # super(TestApiClient, cls).setUpClass()
77
+
59
78
  @classmethod
60
79
  def setUpTestData(cls):
80
+ with connection.schema_editor() as schema_editor:
81
+ schema_editor.create_model(TestModel)
61
82
  cls.user = User.objects.create_user(
62
83
  username='jrr.tolkien',
63
84
  email="jrr.tolkien@oxford.com",
@@ -237,3 +237,49 @@ class TestPermissions(TestAssertMixin, TestCase):
237
237
  response = self.client.get(
238
238
  f'/api/perms/books/{self.author1_book1.pk}/cover')
239
239
  self.assertRC(response, 200)
240
+
241
+ def test_custom_get_admin(self):
242
+ self.client.login(username='admin')
243
+
244
+ response = self.client.get('/api/perms/authors/custom')
245
+ self.assertRC(response, 200)
246
+
247
+ def test_custom_get_user(self):
248
+ self.client.login(username='user')
249
+
250
+ response = self.client.get('/api/perms/authors/custom')
251
+ self.assertRC(response, 403)
252
+
253
+ self.user.user_permissions.add(*permissions('tests.view_author'))
254
+
255
+ response = self.client.get('/api/perms/authors/custom')
256
+ self.assertRC(response, 200)
257
+
258
+ def test_custom_put_admin(self):
259
+ self.client.login(username='admin')
260
+
261
+ response = self.client.put('/api/perms/authors/custom')
262
+ self.assertRC(response, 200)
263
+
264
+ def test_custom_put_user(self):
265
+ self.client.login(username='user')
266
+
267
+ response = self.client.put('/api/perms/authors/custom')
268
+ self.assertRC(response, 403)
269
+
270
+ self.user.user_permissions.set(permissions('tests.change_author'))
271
+
272
+ response = self.client.put('/api/perms/authors/custom')
273
+ self.assertRC(response, 403)
274
+
275
+ self.user.user_permissions.set(permissions(
276
+ 'tests.can_customize_author'))
277
+
278
+ response = self.client.put('/api/perms/authors/custom')
279
+ self.assertRC(response, 403)
280
+
281
+ self.user.user_permissions.set(permissions(
282
+ 'tests.change_author', 'tests.can_customize_author'))
283
+
284
+ response = self.client.put('/api/perms/authors/custom')
285
+ self.assertRC(response, 200)
@@ -191,7 +191,15 @@ class PrivateAuthorRestView(AuthorRestViewMixin, RestView):
191
191
  @rest_view("/perms/authors")
192
192
  class PermsAuthorRestView(
193
193
  AuthorRestViewMixin, SlugPermsDetailRestViewMixin, PermsRestView):
194
- pass
194
+
195
+ @rest_api("/custom", method="get", perms='tests.view_author')
196
+ def get_custom(self):
197
+ return JsonResponse(dict(message='Custom get'))
198
+
199
+ @rest_api("/custom", method="put", perms=[
200
+ 'tests.change_author', 'tests.can_customize_author'])
201
+ def get_custom_action(self):
202
+ return JsonResponse(dict(message='Custom put'))
195
203
 
196
204
 
197
205
  @rest_view("/admin-edit/authors")
File without changes
@@ -0,0 +1,13 @@
1
+ # Generated by Django 4.2.17 on 2025-01-21 09:43
2
+ # flake8: noqa
3
+
4
+ from django.conf import settings
5
+ from django.db import migrations
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ initial = True
10
+
11
+ dependencies = [
12
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+ ]
@@ -0,0 +1,18 @@
1
+ from .common import * # noqa
2
+
3
+ DATABASES = {
4
+ 'default': {
5
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
6
+ 'NAME': 'ci',
7
+ 'USER': 'postgres',
8
+ 'PASSWORD': 'postgres',
9
+ 'HOST': 'postgres',
10
+ 'PORT': '5432',
11
+ }
12
+ }
13
+
14
+ TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
15
+ TEST_OUTPUT_FILE_NAME = 'testreport.xml'
16
+ TEST_MODE = True
17
+ # TEST_OUTPUT_VERBOSE = 1
18
+ # TEST_OUTPUT_DESCRIPTIONS = False
@@ -0,0 +1,80 @@
1
+ import os
2
+
3
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
4
+
5
+ SECRET_KEY = 'fake-key'
6
+ INSTALLED_APPS = [
7
+ 'django.contrib.auth',
8
+ 'django.contrib.contenttypes',
9
+ 'django.contrib.postgres',
10
+ 'pfx.pfxcore',
11
+ 'tests_base_user',
12
+ ]
13
+
14
+ MIDDLEWARE = [
15
+ 'pfx.pfxcore.middleware.LocaleMiddleware',
16
+ 'django.middleware.security.SecurityMiddleware',
17
+ 'django.middleware.common.CommonMiddleware',
18
+ 'pfx.pfxcore.middleware.AuthenticationMiddleware',
19
+ 'pfx.pfxcore.middleware.CookieAuthenticationMiddleware',
20
+ ]
21
+
22
+ USE_I18N = True
23
+ USE_L10N = True
24
+ LANGUAGE_CODE = 'en'
25
+ LANGUAGES = [
26
+ ('en', 'English'),
27
+ ('fr', 'French')]
28
+ LOCALE_PATHS = [
29
+ os.path.join(BASE_DIR, "tests_base_user/locale")]
30
+
31
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
32
+
33
+ AUTH_USER_MODEL = 'pfxcore.PFXUser'
34
+
35
+ PFX_SECRET_KEY = "fake-secret-key"
36
+ PFX_COOKIE_DOMAIN = None
37
+
38
+ PFX_MAX_LIST_RESULT_SIZE = 0
39
+
40
+ ROOT_URLCONF = 'tests_base_user.urls'
41
+ APPEND_SLASH = False
42
+
43
+ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
44
+ PFX_RESET_PASSWORD_URL = (
45
+ 'http://localhost:8000/test?token={token}&uidb64={uidb64}')
46
+ PFX_SITE_NAME = 'Books Demo'
47
+
48
+ # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
49
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
50
+
51
+ TEMPLATES = [
52
+ {
53
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
54
+ 'DIRS': [],
55
+ 'APP_DIRS': True,
56
+ }
57
+ ]
58
+
59
+ LOGGING = {
60
+ 'version': 1,
61
+ 'disable_existing_logger': False,
62
+ 'formatters': {
63
+ 'console': {
64
+ 'format': "\n%(name)-25s %(levelname)-8s %(message)s",
65
+ },
66
+ },
67
+ 'handlers': {
68
+ 'console': {
69
+ 'class': 'logging.StreamHandler',
70
+ 'formatter': 'console',
71
+ },
72
+ },
73
+ 'loggers': {
74
+ '': {
75
+ 'handlers': ['console'],
76
+ 'level': 'ERROR',
77
+ 'propagate': True,
78
+ },
79
+ },
80
+ }
@@ -0,0 +1,13 @@
1
+ """
2
+ Development settings
3
+
4
+ Load .dev_custom if it exists for personal settings (ignored by git).
5
+ Use .dev_default directly if no.
6
+
7
+ Use: `cp dev_custom_example.py dev_custom.py to create it.`
8
+ """
9
+
10
+ try:
11
+ from .dev_custom import * # noqa
12
+ except ImportError:
13
+ from .dev_default import * # noqa