django-pfx 1.7.6.dev23__tar.gz → 1.7.6.dev27__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.
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/PKG-INFO +1 -1
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/SOURCES.txt +7 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/scm_file_list.json +7 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/scm_version.json +2 -2
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/authentication.md +2 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/testing.md +90 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/email_backend/__init__.py +1 -0
- django_pfx-1.7.6.dev27/pfx/emails/email_backend/memory_email_backend.py +14 -0
- django_pfx-1.7.6.dev27/pfx/emails/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/locale/fr/LC_MESSAGES/django.po +5 -1
- django_pfx-1.7.6.dev27/pfx/emails/migrations/0006_alter_email_attachments.py +19 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/models/email.py +1 -1
- django_pfx-1.7.6.dev27/pfx/emails/test.py +40 -0
- django_pfx-1.7.6.dev27/pfx/pfxcore/sms/backends/memory.py +15 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/test.py +99 -0
- django_pfx-1.7.6.dev27/pfx/pfxcore/xml_test_runner.py +8 -0
- django_pfx-1.7.6.dev27/tests/tests/test_emails_test_tools.py +60 -0
- django_pfx-1.7.6.dev27/tests/tests/test_test_runner.py +117 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_verbose_names.py +1 -0
- django_pfx-1.7.6.dev23/pfx/emails/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/.gitignore +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/.gitlab-ci.yml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/LICENSE +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/MANIFEST.in +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/README.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/Makefile +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/conf.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/index.rst +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/api.views.rst +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/decorator.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/getting_started.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/model.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/profiling.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/settings.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/doc/source/user_jobs.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/img/pfx.png +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/img/pfx.svg +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/make_messages +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/manage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/email_backend/q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/mailjet/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/mailjet/mailjet.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/mailjet/message_result.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/0002_alter_email_headers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/0003_alter_email_options.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/0004_alter_email_mail_from.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/0005_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/providers/email_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/templates/emails/base_template.html +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/templates/emails/base_template.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/templates/emails/base_template_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/views/email_rest_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/fields/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/fields/decimal_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/fields/media_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/fields/rich_text_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/authenticator.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/base.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/email.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/legacy.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/mfa/sms.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/request_too_big_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/middleware/ws_cookie_authentication_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0007_alter_pfxuser_options.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/0008_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/attachment_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/mfa_device.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/ordered_model_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/sms/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/sms/backends/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/sms/backends/base.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/sms/backends/console.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/storage/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/storage/local_storage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/version_check.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/mfa_authentication_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0003_clean_scheduled_tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0004_userjob_summary_url.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0005_swappable_user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/0006_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/models/user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/models/user_job_attachment.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/providers/user_job_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/providers/user_job_websocket_channel_provider.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/views/user_job_attachment_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/views/user_job_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/userjobs/views/user_websocket_consumer.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pyproject.toml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/requirements.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/serve-doc +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/setup.cfg +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/setup.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/channel_group_send_calls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/mfa_urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/mfa_test_utils.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_client.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_emails_email_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_emails_email_model.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_emails_q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_emails_send_email_message.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_choices.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_date.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_decimal.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_help_text.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_minutes_duration.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_one2many.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_rich_text.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_fields_time.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_mfa_legacy.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_mfa_login_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_mfa_setup_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_post_migrate_groups_update.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_user_job_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_user_job_messages.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_user_job_model.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_user_websocket.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_version_check.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/tests/test_ws_cookie_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_base_user/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/migrations/0002_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/providers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/scope.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/tests/test_user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_custom_user_job/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/tests_user_email_login/views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.6.
|
|
3
|
+
Version: 1.7.6.dev27
|
|
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.4
|
|
2
2
|
Name: django-pfx
|
|
3
|
-
Version: 1.7.6.
|
|
3
|
+
Version: 1.7.6.dev27
|
|
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
|
|
@@ -41,8 +41,10 @@ pfx/emails/apps.py
|
|
|
41
41
|
pfx/emails/exceptions.py
|
|
42
42
|
pfx/emails/shortcuts.py
|
|
43
43
|
pfx/emails/tasks.py
|
|
44
|
+
pfx/emails/test.py
|
|
44
45
|
pfx/emails/urls.py
|
|
45
46
|
pfx/emails/email_backend/__init__.py
|
|
47
|
+
pfx/emails/email_backend/memory_email_backend.py
|
|
46
48
|
pfx/emails/email_backend/q_mailjet_email_backend.py
|
|
47
49
|
pfx/emails/locale/fr/LC_MESSAGES/django.mo
|
|
48
50
|
pfx/emails/locale/fr/LC_MESSAGES/django.po
|
|
@@ -54,6 +56,7 @@ pfx/emails/migrations/0002_alter_email_headers.py
|
|
|
54
56
|
pfx/emails/migrations/0003_alter_email_options.py
|
|
55
57
|
pfx/emails/migrations/0004_alter_email_mail_from.py
|
|
56
58
|
pfx/emails/migrations/0005_lowercase_verbose_names.py
|
|
59
|
+
pfx/emails/migrations/0006_alter_email_attachments.py
|
|
57
60
|
pfx/emails/migrations/__init__.py
|
|
58
61
|
pfx/emails/models/__init__.py
|
|
59
62
|
pfx/emails/models/email.py
|
|
@@ -73,6 +76,7 @@ pfx/pfxcore/shortcuts.py
|
|
|
73
76
|
pfx/pfxcore/test.py
|
|
74
77
|
pfx/pfxcore/urls.py
|
|
75
78
|
pfx/pfxcore/version_check.py
|
|
79
|
+
pfx/pfxcore/xml_test_runner.py
|
|
76
80
|
pfx/pfxcore/apidoc/__init__.py
|
|
77
81
|
pfx/pfxcore/apidoc/parameters.py
|
|
78
82
|
pfx/pfxcore/apidoc/schema.py
|
|
@@ -133,6 +137,7 @@ pfx/pfxcore/sms/__init__.py
|
|
|
133
137
|
pfx/pfxcore/sms/backends/__init__.py
|
|
134
138
|
pfx/pfxcore/sms/backends/base.py
|
|
135
139
|
pfx/pfxcore/sms/backends/console.py
|
|
140
|
+
pfx/pfxcore/sms/backends/memory.py
|
|
136
141
|
pfx/pfxcore/storage/__init__.py
|
|
137
142
|
pfx/pfxcore/storage/exceptions.py
|
|
138
143
|
pfx/pfxcore/storage/local_storage.py
|
|
@@ -225,6 +230,7 @@ tests/tests/test_emails_email_api.py
|
|
|
225
230
|
tests/tests/test_emails_email_model.py
|
|
226
231
|
tests/tests/test_emails_q_mailjet_email_backend.py
|
|
227
232
|
tests/tests/test_emails_send_email_message.py
|
|
233
|
+
tests/tests/test_emails_test_tools.py
|
|
228
234
|
tests/tests/test_fields_choices.py
|
|
229
235
|
tests/tests/test_fields_date.py
|
|
230
236
|
tests/tests/test_fields_decimal.py
|
|
@@ -246,6 +252,7 @@ tests/tests/test_post_migrate_groups_update.py
|
|
|
246
252
|
tests/tests/test_profiling_middleware.py
|
|
247
253
|
tests/tests/test_settings.py
|
|
248
254
|
tests/tests/test_shortcuts.py
|
|
255
|
+
tests/tests/test_test_runner.py
|
|
249
256
|
tests/tests/test_timezone_middleware.py
|
|
250
257
|
tests/tests/test_tools.py
|
|
251
258
|
tests/tests/test_user_job_api.py
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"pfx/emails/__init__.py",
|
|
30
30
|
"pfx/emails/apps.py",
|
|
31
31
|
"pfx/emails/email_backend/__init__.py",
|
|
32
|
+
"pfx/emails/email_backend/memory_email_backend.py",
|
|
32
33
|
"pfx/emails/email_backend/q_mailjet_email_backend.py",
|
|
33
34
|
"pfx/emails/exceptions.py",
|
|
34
35
|
"pfx/emails/locale/fr/LC_MESSAGES/django.po",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"pfx/emails/migrations/0003_alter_email_options.py",
|
|
41
42
|
"pfx/emails/migrations/0004_alter_email_mail_from.py",
|
|
42
43
|
"pfx/emails/migrations/0005_lowercase_verbose_names.py",
|
|
44
|
+
"pfx/emails/migrations/0006_alter_email_attachments.py",
|
|
43
45
|
"pfx/emails/migrations/__init__.py",
|
|
44
46
|
"pfx/emails/models/__init__.py",
|
|
45
47
|
"pfx/emails/models/email.py",
|
|
@@ -50,6 +52,7 @@
|
|
|
50
52
|
"pfx/emails/templates/emails/base_template.html",
|
|
51
53
|
"pfx/emails/templates/emails/base_template.txt",
|
|
52
54
|
"pfx/emails/templates/emails/base_template_subject.txt",
|
|
55
|
+
"pfx/emails/test.py",
|
|
53
56
|
"pfx/emails/urls.py",
|
|
54
57
|
"pfx/emails/views/__init__.py",
|
|
55
58
|
"pfx/emails/views/email_rest_view.py",
|
|
@@ -118,6 +121,7 @@
|
|
|
118
121
|
"pfx/pfxcore/sms/backends/__init__.py",
|
|
119
122
|
"pfx/pfxcore/sms/backends/base.py",
|
|
120
123
|
"pfx/pfxcore/sms/backends/console.py",
|
|
124
|
+
"pfx/pfxcore/sms/backends/memory.py",
|
|
121
125
|
"pfx/pfxcore/storage/__init__.py",
|
|
122
126
|
"pfx/pfxcore/storage/exceptions.py",
|
|
123
127
|
"pfx/pfxcore/storage/local_storage.py",
|
|
@@ -158,6 +162,7 @@
|
|
|
158
162
|
"pfx/pfxcore/views/parameters/subset_page_size.py",
|
|
159
163
|
"pfx/pfxcore/views/parameters/subset_page_subset.py",
|
|
160
164
|
"pfx/pfxcore/views/rest_views.py",
|
|
165
|
+
"pfx/pfxcore/xml_test_runner.py",
|
|
161
166
|
"pfx/settings/__init__.py",
|
|
162
167
|
"pfx/settings/dev.py",
|
|
163
168
|
"pfx/userjobs/__init__.py",
|
|
@@ -215,6 +220,7 @@
|
|
|
215
220
|
"tests/tests/test_emails_email_model.py",
|
|
216
221
|
"tests/tests/test_emails_q_mailjet_email_backend.py",
|
|
217
222
|
"tests/tests/test_emails_send_email_message.py",
|
|
223
|
+
"tests/tests/test_emails_test_tools.py",
|
|
218
224
|
"tests/tests/test_fields_choices.py",
|
|
219
225
|
"tests/tests/test_fields_date.py",
|
|
220
226
|
"tests/tests/test_fields_decimal.py",
|
|
@@ -236,6 +242,7 @@
|
|
|
236
242
|
"tests/tests/test_profiling_middleware.py",
|
|
237
243
|
"tests/tests/test_settings.py",
|
|
238
244
|
"tests/tests/test_shortcuts.py",
|
|
245
|
+
"tests/tests/test_test_runner.py",
|
|
239
246
|
"tests/tests/test_timezone_middleware.py",
|
|
240
247
|
"tests/tests/test_tools.py",
|
|
241
248
|
"tests/tests/test_user_job_api.py",
|
|
@@ -183,6 +183,8 @@ removed.
|
|
|
183
183
|
* `PFX_SMS_BACKEND`: Dotted path to the SMS backend class (optional, default
|
|
184
184
|
`'pfx.pfxcore.sms.backends.console.ConsoleSMSBackend'`).
|
|
185
185
|
Implement {class}`pfx.pfxcore.sms.backends.base.BaseSMSBackend` to integrate a real SMS provider.
|
|
186
|
+
In the tests, `pfx.pfxcore.test.TestRunner` replaces it with
|
|
187
|
+
{class}`pfx.pfxcore.sms.backends.memory.MemorySMSBackend` (see [Testing](testing.md)).
|
|
186
188
|
* `PFX_TOKEN_OTP_VALIDITY`: Validity for OTP tokens (corresponds to the maximum time to enter
|
|
187
189
|
an OTP code after logging in with a password) (optional, default `{'minutes': 15}`)
|
|
188
190
|
* `PFX_HOTP_CODE_VALIDITY`: Validity of HOTP codes in minutes (used to send code by email or SMS) (optional, default `15`).
|
|
@@ -340,3 +340,93 @@ class BookPermsAPITest(TestPermsAssertMixin):
|
|
|
340
340
|
post=403, put=403, delete=403),
|
|
341
341
|
}
|
|
342
342
|
```
|
|
343
|
+
|
|
344
|
+
## Test runner
|
|
345
|
+
`pfx.pfxcore.test.TestRunner` replaces the SMS and email backends for the
|
|
346
|
+
whole run, parallel workers included: nothing leaves the tests, whatever
|
|
347
|
+
the local settings contain, and what would be sent is kept for the
|
|
348
|
+
assertions.
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
TEST_RUNNER = 'pfx.pfxcore.test.TestRunner'
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
- `PFX_SMS_BACKEND` becomes
|
|
355
|
+
`pfx.pfxcore.sms.backends.memory.MemorySMSBackend`, which collects the
|
|
356
|
+
SMS in memory.
|
|
357
|
+
- If `pfx.emails` is installed, `EMAIL_BACKEND` becomes
|
|
358
|
+
`pfx.emails.email_backend.MemoryEmailBackend` instead of the `locmem`
|
|
359
|
+
backend set by Django. `locmem` puts the emails in
|
|
360
|
+
`django.core.mail.outbox`: the email model is never built nor validated,
|
|
361
|
+
and a sending path that would create an invalid email goes unnoticed.
|
|
362
|
+
`MemoryEmailBackend` builds, validates and saves the email as
|
|
363
|
+
`QMailjetEmailBackend` does, with the `manual` send mode: nothing is
|
|
364
|
+
sent.
|
|
365
|
+
|
|
366
|
+
A project without `pfx.emails` can use the runner as well: only the SMS
|
|
367
|
+
backend is replaced, and the emails stay in Django's `locmem` outbox.
|
|
368
|
+
|
|
369
|
+
To use subclasses of these backends (to fill extra fields of your email
|
|
370
|
+
model, for instance):
|
|
371
|
+
```python
|
|
372
|
+
PFX_TEST_SMS_BACKEND = 'myapp.tests.MyMemorySMSBackend'
|
|
373
|
+
PFX_TEST_EMAIL_BACKEND = 'myapp.tests.MyMemoryEmailBackend'
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
For the XML reports of `unittest-xml-reporting` (to install in the
|
|
377
|
+
project), use the XML variant:
|
|
378
|
+
```python
|
|
379
|
+
TEST_RUNNER = 'pfx.pfxcore.xml_test_runner.XMLTestRunner'
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
With another runner, combine it with `MemoryBackendsRunnerMixin`:
|
|
383
|
+
```python
|
|
384
|
+
from pfx.pfxcore.test import MemoryBackendsRunnerMixin
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class MyTestRunner(MemoryBackendsRunnerMixin, OtherTestRunner):
|
|
388
|
+
pass
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
A test class that needs another backend keeps its
|
|
392
|
+
`override_settings(EMAIL_BACKEND=…)` or `override_settings(PFX_SMS_BACKEND=…)`.
|
|
393
|
+
|
|
394
|
+
## SMSTestMixin
|
|
395
|
+
Helpers to check the SMS of a test. The outbox is emptied before each
|
|
396
|
+
test. They fail if the SMS backend is not a `MemorySMSBackend`, rather
|
|
397
|
+
than reporting an empty outbox.
|
|
398
|
+
|
|
399
|
+
- `sms_outbox()`: the SMS sent so far, as `(to, message)` tuples.
|
|
400
|
+
- `clear_sms_outbox()`: forget the SMS sent so far.
|
|
401
|
+
|
|
402
|
+
## EmailTestMixin
|
|
403
|
+
`pfx.emails.test.EmailTestMixin` gives helpers to check the emails of a
|
|
404
|
+
test. They fail if the emails are not saved in the email model (with
|
|
405
|
+
`locmem`, for instance), rather than reporting an empty outbox.
|
|
406
|
+
|
|
407
|
+
- `outbox()`: the emails created so far, in creation order.
|
|
408
|
+
- `clear_outbox()`: delete the emails created so far.
|
|
409
|
+
- `email_to(email)`: the addresses of the `To`, without the names.
|
|
410
|
+
- `get_email_html(email)`: the HTML part, fails if there is none.
|
|
411
|
+
|
|
412
|
+
Example :
|
|
413
|
+
```python
|
|
414
|
+
from django.test import TestCase
|
|
415
|
+
|
|
416
|
+
from pfx.emails.test import EmailTestMixin
|
|
417
|
+
from pfx.pfxcore.test import SMSTestMixin
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
class ATestClass(EmailTestMixin, SMSTestMixin, TestCase):
|
|
421
|
+
|
|
422
|
+
def a_test(self):
|
|
423
|
+
# … something that sends an email to jrr@example.com
|
|
424
|
+
[email] = self.outbox()
|
|
425
|
+
self.assertEqual(self.email_to(email), ['jrr@example.com'])
|
|
426
|
+
self.assertIn('Welcome', self.get_email_html(email))
|
|
427
|
+
|
|
428
|
+
def another_test(self):
|
|
429
|
+
# … something that sends an SMS
|
|
430
|
+
[(to, message)] = self.sms_outbox()
|
|
431
|
+
self.assertEqual(to, '+41791234567')
|
|
432
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .q_mailjet_email_backend import QMailjetEmailBackend
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MemoryEmailBackend(QMailjetEmailBackend):
|
|
5
|
+
"""Create the emails as :class:`QMailjetEmailBackend` does, but never
|
|
6
|
+
send them.
|
|
7
|
+
|
|
8
|
+
The email model is built, validated and saved, so a sending path that
|
|
9
|
+
would create an invalid email fails. The ``manual`` send mode stops
|
|
10
|
+
there: nothing is queued nor sent to Mailjet."""
|
|
11
|
+
|
|
12
|
+
def create_mail(self, message):
|
|
13
|
+
message.send_mode = 'manual'
|
|
14
|
+
super().create_mail(message)
|
|
Binary file
|
{django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev27}/pfx/emails/locale/fr/LC_MESSAGES/django.po
RENAMED
|
@@ -7,7 +7,7 @@ msgid ""
|
|
|
7
7
|
msgstr ""
|
|
8
8
|
"Project-Id-Version: PACKAGE VERSION\n"
|
|
9
9
|
"Report-Msgid-Bugs-To: \n"
|
|
10
|
-
"POT-Creation-Date: 2026-09-
|
|
10
|
+
"POT-Creation-Date: 2026-09-29 14:49+0200\n"
|
|
11
11
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
12
12
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
13
13
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
@@ -85,6 +85,10 @@ msgstr "partie HTML"
|
|
|
85
85
|
msgid "headers"
|
|
86
86
|
msgstr "en-têtes"
|
|
87
87
|
|
|
88
|
+
#: models/email.py:82
|
|
89
|
+
msgid "attachments"
|
|
90
|
+
msgstr "pièces jointes"
|
|
91
|
+
|
|
88
92
|
#: models/email.py:84
|
|
89
93
|
msgid "status"
|
|
90
94
|
msgstr "statut"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generated by Django 5.2.16 on 2026-09-29 12:49
|
|
2
|
+
# flake8: noqa
|
|
3
|
+
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('emails', '0005_lowercase_verbose_names'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name='email',
|
|
16
|
+
name='attachments',
|
|
17
|
+
field=models.JSONField(blank=True, default=list, verbose_name='attachments'),
|
|
18
|
+
),
|
|
19
|
+
]
|
|
@@ -79,7 +79,7 @@ class AbstractEmail(models.Model):
|
|
|
79
79
|
text_part = NotNullTextField(_("text part"), blank=True)
|
|
80
80
|
html_part = NotNullTextField(_("HTML part"), blank=True)
|
|
81
81
|
headers = models.JSONField(_("headers"), default=dict, blank=True)
|
|
82
|
-
attachments = models.JSONField(
|
|
82
|
+
attachments = models.JSONField(_("attachments"), blank=True, default=list)
|
|
83
83
|
status = models.CharField(
|
|
84
84
|
_("status"), max_length=32, db_index=True, choices=STATUS_LIST,
|
|
85
85
|
default='to_send')
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.utils.module_loading import import_string
|
|
3
|
+
|
|
4
|
+
from pfx.emails.email_backend import QMailjetEmailBackend
|
|
5
|
+
from pfx.emails.models import get_email_model
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EmailTestMixin:
|
|
9
|
+
"""Helpers to check the emails created by a test."""
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def _check_email_backend(cls):
|
|
13
|
+
backend = import_string(settings.EMAIL_BACKEND)
|
|
14
|
+
if not issubclass(backend, QMailjetEmailBackend):
|
|
15
|
+
raise AssertionError(
|
|
16
|
+
f"EMAIL_BACKEND is {settings.EMAIL_BACKEND}, the emails are "
|
|
17
|
+
f"not saved in the email model. Run the tests with a runner "
|
|
18
|
+
f"using pfx.pfxcore.test.MemoryBackendsRunnerMixin.")
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def outbox(cls):
|
|
22
|
+
"""The emails created so far, in creation order."""
|
|
23
|
+
cls._check_email_backend()
|
|
24
|
+
return list(get_email_model().objects.order_by('pk'))
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def clear_outbox(cls):
|
|
28
|
+
cls._check_email_backend()
|
|
29
|
+
get_email_model().objects.all().delete()
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def email_to(cls, email):
|
|
33
|
+
"""The addresses of the ``To`` of ``email``, without the names."""
|
|
34
|
+
return [r['Email'] for r in email.mail_to]
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def get_email_html(cls, email):
|
|
38
|
+
if not email.html_part:
|
|
39
|
+
raise AssertionError("Email does not contain an HTML part.")
|
|
40
|
+
return email.html_part
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .base import BaseSMSBackend
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MemorySMSBackend(BaseSMSBackend):
|
|
5
|
+
"""Collect the SMS in :attr:`outbox` instead of sending them.
|
|
6
|
+
|
|
7
|
+
A new backend instance is built for each send (see
|
|
8
|
+
:func:`pfx.pfxcore.sms.get_sms_backend`), so the outbox is a class
|
|
9
|
+
attribute."""
|
|
10
|
+
|
|
11
|
+
#: The sent SMS, as ``(to, message)`` tuples.
|
|
12
|
+
outbox = []
|
|
13
|
+
|
|
14
|
+
def send_sms(self, to, message):
|
|
15
|
+
self.outbox.append((to, message))
|
|
@@ -5,8 +5,16 @@ from functools import reduce
|
|
|
5
5
|
from http.cookies import SimpleCookie
|
|
6
6
|
from json import JSONDecodeError
|
|
7
7
|
|
|
8
|
+
from django.apps import apps
|
|
8
9
|
from django.db import transaction
|
|
10
|
+
from django.test import override_settings
|
|
9
11
|
from django.test.client import Client as DjangoClient
|
|
12
|
+
from django.test.runner import DiscoverRunner, ParallelTestSuite
|
|
13
|
+
from django.test.runner import _init_worker as django_init_worker
|
|
14
|
+
from django.utils.module_loading import import_string
|
|
15
|
+
|
|
16
|
+
from pfx.pfxcore.settings import settings
|
|
17
|
+
from pfx.pfxcore.sms.backends.memory import MemorySMSBackend
|
|
10
18
|
|
|
11
19
|
logger = logging.getLogger(__name__)
|
|
12
20
|
|
|
@@ -322,3 +330,94 @@ class MockBoto3Client:
|
|
|
322
330
|
|
|
323
331
|
def delete_object(self, *args, **kwargs):
|
|
324
332
|
pass
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def get_test_backends():
|
|
336
|
+
"""The backends that replace the real ones during the tests."""
|
|
337
|
+
backends = dict(PFX_SMS_BACKEND=getattr(
|
|
338
|
+
settings, 'PFX_TEST_SMS_BACKEND',
|
|
339
|
+
'pfx.pfxcore.sms.backends.memory.MemorySMSBackend'))
|
|
340
|
+
if apps.is_installed('pfx.emails'):
|
|
341
|
+
backends['EMAIL_BACKEND'] = getattr(
|
|
342
|
+
settings, 'PFX_TEST_EMAIL_BACKEND',
|
|
343
|
+
'pfx.emails.email_backend.MemoryEmailBackend')
|
|
344
|
+
return backends
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _init_worker(*args, **kwargs):
|
|
348
|
+
# A spawned worker calls setup_test_environment() again, which puts
|
|
349
|
+
# locmem back.
|
|
350
|
+
django_init_worker(*args, **kwargs)
|
|
351
|
+
override_settings(**get_test_backends()).enable()
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class MemoryBackendsParallelTestSuite(ParallelTestSuite):
|
|
355
|
+
init_worker = _init_worker
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class MemoryBackendsRunnerMixin:
|
|
359
|
+
"""Replace the SMS and email backends for the whole run.
|
|
360
|
+
|
|
361
|
+
Nothing leaves the tests, whatever the local settings contain, and
|
|
362
|
+
what would be sent is kept for the assertions (see
|
|
363
|
+
:class:`SMSTestMixin` and :class:`pfx.emails.test.EmailTestMixin`).
|
|
364
|
+
|
|
365
|
+
- ``PFX_SMS_BACKEND`` becomes ``PFX_TEST_SMS_BACKEND`` (default
|
|
366
|
+
:class:`pfx.pfxcore.sms.backends.memory.MemorySMSBackend`).
|
|
367
|
+
- If ``pfx.emails`` is installed, ``EMAIL_BACKEND`` becomes
|
|
368
|
+
``PFX_TEST_EMAIL_BACKEND`` (default
|
|
369
|
+
:class:`pfx.emails.email_backend.MemoryEmailBackend`) instead of
|
|
370
|
+
the ``locmem`` backend set by Django: the email model is built and
|
|
371
|
+
validated, which ``locmem`` never does.
|
|
372
|
+
|
|
373
|
+
A test class decorated with ``override_settings`` keeps its own
|
|
374
|
+
backends."""
|
|
375
|
+
|
|
376
|
+
parallel_test_suite = MemoryBackendsParallelTestSuite
|
|
377
|
+
|
|
378
|
+
def setup_test_environment(self, **kwargs):
|
|
379
|
+
super().setup_test_environment(**kwargs)
|
|
380
|
+
self._test_backends = override_settings(**get_test_backends())
|
|
381
|
+
self._test_backends.enable()
|
|
382
|
+
|
|
383
|
+
def teardown_test_environment(self, **kwargs):
|
|
384
|
+
self._test_backends.disable()
|
|
385
|
+
super().teardown_test_environment(**kwargs)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class TestRunner(MemoryBackendsRunnerMixin, DiscoverRunner):
|
|
389
|
+
pass
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class SMSTestMixin:
|
|
393
|
+
"""Helpers to check the SMS sent by a test.
|
|
394
|
+
|
|
395
|
+
The outbox is emptied before each test, as Django does for
|
|
396
|
+
``mail.outbox``."""
|
|
397
|
+
|
|
398
|
+
@classmethod
|
|
399
|
+
def _sms_backend(cls):
|
|
400
|
+
backend = import_string(settings.PFX_SMS_BACKEND)
|
|
401
|
+
if not issubclass(backend, MemorySMSBackend):
|
|
402
|
+
raise AssertionError(
|
|
403
|
+
f"PFX_SMS_BACKEND is {settings.PFX_SMS_BACKEND}, the SMS "
|
|
404
|
+
f"are not collected. Run the tests with a runner using "
|
|
405
|
+
f"pfx.pfxcore.test.MemoryBackendsRunnerMixin.")
|
|
406
|
+
return backend
|
|
407
|
+
|
|
408
|
+
# __call__ rather than _pre_setup: a classmethod in Django 5.2, an
|
|
409
|
+
# instance method in 4.2.
|
|
410
|
+
def __call__(self, *args, **kwargs):
|
|
411
|
+
backend = import_string(settings.PFX_SMS_BACKEND)
|
|
412
|
+
if issubclass(backend, MemorySMSBackend):
|
|
413
|
+
backend.outbox.clear()
|
|
414
|
+
return super().__call__(*args, **kwargs)
|
|
415
|
+
|
|
416
|
+
@classmethod
|
|
417
|
+
def sms_outbox(cls):
|
|
418
|
+
"""The SMS sent so far, as ``(to, message)`` tuples."""
|
|
419
|
+
return list(cls._sms_backend().outbox)
|
|
420
|
+
|
|
421
|
+
@classmethod
|
|
422
|
+
def clear_sms_outbox(cls):
|
|
423
|
+
cls._sms_backend().outbox.clear()
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from xmlrunner.extra.djangotestrunner import XMLTestRunner as BaseXMLTestRunner
|
|
2
|
+
|
|
3
|
+
from pfx.pfxcore.test import MemoryBackendsRunnerMixin
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class XMLTestRunner(MemoryBackendsRunnerMixin, BaseXMLTestRunner):
|
|
7
|
+
""":class:`pfx.pfxcore.test.TestRunner` with the XML reports of
|
|
8
|
+
``unittest-xml-reporting``, which must be installed."""
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from django.core import mail
|
|
2
|
+
from django.core.exceptions import ValidationError
|
|
3
|
+
from django.core.mail import EmailMultiAlternatives, send_mail
|
|
4
|
+
from django.test import TestCase, override_settings
|
|
5
|
+
|
|
6
|
+
from pfx.emails.models import Email
|
|
7
|
+
from pfx.emails.test import EmailTestMixin
|
|
8
|
+
|
|
9
|
+
MEMORY_BACKEND = 'pfx.emails.email_backend.MemoryEmailBackend'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@override_settings(EMAIL_BACKEND=MEMORY_BACKEND)
|
|
13
|
+
class TestMemoryEmailBackend(EmailTestMixin, TestCase):
|
|
14
|
+
"""The backend goes as far as the saved email, never further."""
|
|
15
|
+
|
|
16
|
+
def test_the_email_is_saved_and_not_sent(self):
|
|
17
|
+
send_mail(
|
|
18
|
+
'Subject', 'Content', 'from@example.com', ['to@example.com'])
|
|
19
|
+
email = Email.objects.get()
|
|
20
|
+
self.assertEqual(email.send_mode, 'manual')
|
|
21
|
+
self.assertEqual(email.status, 'to_send')
|
|
22
|
+
self.assertEqual(mail.outbox, [])
|
|
23
|
+
|
|
24
|
+
def test_an_invalid_email_fails(self):
|
|
25
|
+
"""What locmem cannot see: the email model refuses the message."""
|
|
26
|
+
with self.assertRaises(ValidationError):
|
|
27
|
+
send_mail(
|
|
28
|
+
'Subject', 'Content', 'from@example.com', ['not-an-email'])
|
|
29
|
+
|
|
30
|
+
def test_outbox_helpers(self):
|
|
31
|
+
send_mail(
|
|
32
|
+
'First', 'Content', 'from@example.com',
|
|
33
|
+
['"Jean Dupont" <jean@example.com>', 'paul@example.com'])
|
|
34
|
+
message = EmailMultiAlternatives(
|
|
35
|
+
'Second', 'Text', 'from@example.com', ['marie@example.com'])
|
|
36
|
+
message.attach_alternative('<p>HTML</p>', 'text/html')
|
|
37
|
+
message.send()
|
|
38
|
+
|
|
39
|
+
first, second = self.outbox()
|
|
40
|
+
self.assertEqual(
|
|
41
|
+
[first.subject, second.subject], ['First', 'Second'])
|
|
42
|
+
self.assertEqual(
|
|
43
|
+
self.email_to(first), ['jean@example.com', 'paul@example.com'])
|
|
44
|
+
self.assertEqual(self.get_email_html(second), '<p>HTML</p>')
|
|
45
|
+
with self.assertRaises(AssertionError):
|
|
46
|
+
self.get_email_html(first)
|
|
47
|
+
|
|
48
|
+
self.clear_outbox()
|
|
49
|
+
self.assertEqual(self.outbox(), [])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TestEmailTestMixinWithLocmem(EmailTestMixin, TestCase):
|
|
53
|
+
"""Without the runner, locmem is still there: the helpers refuse to
|
|
54
|
+
answer instead of reporting an empty outbox."""
|
|
55
|
+
|
|
56
|
+
def test_the_helpers_refuse_locmem(self):
|
|
57
|
+
with self.assertRaises(AssertionError):
|
|
58
|
+
self.outbox()
|
|
59
|
+
with self.assertRaises(AssertionError):
|
|
60
|
+
self.clear_outbox()
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.test import SimpleTestCase, override_settings
|
|
6
|
+
from django.test.utils import setup_test_environment, teardown_test_environment
|
|
7
|
+
|
|
8
|
+
from pfx.pfxcore.settings import settings as pfx_settings
|
|
9
|
+
from pfx.pfxcore.sms import get_sms_backend
|
|
10
|
+
from pfx.pfxcore.sms.backends.memory import MemorySMSBackend
|
|
11
|
+
from pfx.pfxcore.test import (
|
|
12
|
+
MemoryBackendsParallelTestSuite,
|
|
13
|
+
MemoryBackendsRunnerMixin,
|
|
14
|
+
SMSTestMixin,
|
|
15
|
+
TestRunner,
|
|
16
|
+
_init_worker,
|
|
17
|
+
get_test_backends,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
MEMORY_EMAIL = 'pfx.emails.email_backend.MemoryEmailBackend'
|
|
21
|
+
MEMORY_SMS = 'pfx.pfxcore.sms.backends.memory.MemorySMSBackend'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestMemoryBackendsRunner(SimpleTestCase):
|
|
25
|
+
|
|
26
|
+
def test_the_runner_replaces_the_backends(self):
|
|
27
|
+
"""The runner swaps the backends for the whole run, and puts the
|
|
28
|
+
original ones back at the end, locmem restored by Django included.
|
|
29
|
+
|
|
30
|
+
The test environment of the current run is torn down first, as
|
|
31
|
+
Django refuses to set it up twice, and restored afterwards."""
|
|
32
|
+
teardown_test_environment()
|
|
33
|
+
try:
|
|
34
|
+
email = settings.EMAIL_BACKEND
|
|
35
|
+
sms = pfx_settings.PFX_SMS_BACKEND
|
|
36
|
+
runner = TestRunner()
|
|
37
|
+
runner.setup_test_environment()
|
|
38
|
+
try:
|
|
39
|
+
self.assertEqual(settings.EMAIL_BACKEND, MEMORY_EMAIL)
|
|
40
|
+
self.assertEqual(pfx_settings.PFX_SMS_BACKEND, MEMORY_SMS)
|
|
41
|
+
finally:
|
|
42
|
+
runner.teardown_test_environment()
|
|
43
|
+
self.assertEqual(settings.EMAIL_BACKEND, email)
|
|
44
|
+
self.assertEqual(pfx_settings.PFX_SMS_BACKEND, sms)
|
|
45
|
+
finally:
|
|
46
|
+
setup_test_environment(debug=False)
|
|
47
|
+
|
|
48
|
+
def test_the_parallel_workers_get_the_backends(self):
|
|
49
|
+
"""A spawned worker sets up the test environment again, locmem
|
|
50
|
+
included: the suite of the runner uses a worker init that puts the
|
|
51
|
+
backends back."""
|
|
52
|
+
self.assertIs(
|
|
53
|
+
TestRunner.parallel_test_suite, MemoryBackendsParallelTestSuite)
|
|
54
|
+
self.assertIs(
|
|
55
|
+
MemoryBackendsParallelTestSuite.init_worker, _init_worker)
|
|
56
|
+
|
|
57
|
+
def test_the_backends_are_configurable(self):
|
|
58
|
+
self.assertEqual(get_test_backends(), dict(
|
|
59
|
+
EMAIL_BACKEND=MEMORY_EMAIL, PFX_SMS_BACKEND=MEMORY_SMS))
|
|
60
|
+
with override_settings(
|
|
61
|
+
PFX_TEST_EMAIL_BACKEND='my.EmailBackend',
|
|
62
|
+
PFX_TEST_SMS_BACKEND='my.SMSBackend'):
|
|
63
|
+
self.assertEqual(get_test_backends(), dict(
|
|
64
|
+
EMAIL_BACKEND='my.EmailBackend',
|
|
65
|
+
PFX_SMS_BACKEND='my.SMSBackend'))
|
|
66
|
+
|
|
67
|
+
def test_the_email_backend_needs_pfx_emails(self):
|
|
68
|
+
"""Without pfx.emails, there is no email model to fill: locmem
|
|
69
|
+
stays."""
|
|
70
|
+
with patch('pfx.pfxcore.test.apps.is_installed', return_value=False):
|
|
71
|
+
self.assertEqual(
|
|
72
|
+
get_test_backends(), dict(PFX_SMS_BACKEND=MEMORY_SMS))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@override_settings(PFX_SMS_BACKEND=MEMORY_SMS)
|
|
76
|
+
class TestSMSTestMixin(SMSTestMixin, SimpleTestCase):
|
|
77
|
+
|
|
78
|
+
def test_the_sms_are_collected(self):
|
|
79
|
+
get_sms_backend().send_sms('+41791234567', 'Code: 123456')
|
|
80
|
+
self.assertEqual(
|
|
81
|
+
self.sms_outbox(), [('+41791234567', 'Code: 123456')])
|
|
82
|
+
self.clear_sms_outbox()
|
|
83
|
+
self.assertEqual(self.sms_outbox(), [])
|
|
84
|
+
|
|
85
|
+
def test_the_outbox_is_emptied_before_each_test(self):
|
|
86
|
+
"""An SMS left by a previous test is gone when the next starts."""
|
|
87
|
+
class ATest(SMSTestMixin, SimpleTestCase):
|
|
88
|
+
def test(self):
|
|
89
|
+
self.outbox_at_start = self.sms_outbox()
|
|
90
|
+
|
|
91
|
+
MemorySMSBackend.outbox.append(('+41791234567', 'Left over'))
|
|
92
|
+
test = ATest('test')
|
|
93
|
+
result = unittest.TestResult()
|
|
94
|
+
test(result)
|
|
95
|
+
self.assertTrue(result.wasSuccessful(), result.errors)
|
|
96
|
+
self.assertEqual(test.outbox_at_start, [])
|
|
97
|
+
|
|
98
|
+
@override_settings(
|
|
99
|
+
PFX_SMS_BACKEND='pfx.pfxcore.sms.backends.console.ConsoleSMSBackend')
|
|
100
|
+
def test_the_helpers_refuse_another_backend(self):
|
|
101
|
+
with self.assertRaises(AssertionError):
|
|
102
|
+
self.sms_outbox()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class TestXMLTestRunner(SimpleTestCase):
|
|
106
|
+
|
|
107
|
+
def test_the_xml_runner_replaces_the_backends(self):
|
|
108
|
+
"""The XML variant is the same runner: same backends, same parallel
|
|
109
|
+
workers, and the XML reports."""
|
|
110
|
+
from xmlrunner.extra.djangotestrunner import XMLTestRunner as Base
|
|
111
|
+
|
|
112
|
+
from pfx.pfxcore.xml_test_runner import XMLTestRunner
|
|
113
|
+
|
|
114
|
+
self.assertTrue(issubclass(XMLTestRunner, Base))
|
|
115
|
+
self.assertTrue(issubclass(XMLTestRunner, MemoryBackendsRunnerMixin))
|
|
116
|
+
self.assertIs(
|
|
117
|
+
XMLTestRunner.parallel_test_suite, MemoryBackendsParallelTestSuite)
|