django-pfx 1.7.6.dev23__tar.gz → 1.7.6.dev25__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.dev25}/PKG-INFO +1 -1
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/SOURCES.txt +6 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/scm_file_list.json +6 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/scm_version.json +2 -2
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/authentication.md +2 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/testing.md +90 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/email_backend/__init__.py +1 -0
- django_pfx-1.7.6.dev25/pfx/emails/email_backend/memory_email_backend.py +14 -0
- django_pfx-1.7.6.dev25/pfx/emails/test.py +40 -0
- django_pfx-1.7.6.dev25/pfx/pfxcore/sms/backends/memory.py +15 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/test.py +99 -0
- django_pfx-1.7.6.dev25/pfx/pfxcore/xml_test_runner.py +8 -0
- django_pfx-1.7.6.dev25/tests/tests/test_emails_test_tools.py +60 -0
- django_pfx-1.7.6.dev25/tests/tests/test_test_runner.py +117 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/.gitignore +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/.gitlab-ci.yml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/LICENSE +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/MANIFEST.in +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/README.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/Makefile +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/conf.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/index.rst +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/api.views.rst +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/decorator.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/getting_started.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/model.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/profiling.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/settings.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/doc/source/user_jobs.md +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/img/pfx.png +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/img/pfx.svg +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/make_messages +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/manage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/email_backend/q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/mailjet/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/mailjet/mailjet.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/mailjet/message_result.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/0002_alter_email_headers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/0003_alter_email_options.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/0004_alter_email_mail_from.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/0005_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/models/email.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/providers/email_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/templates/emails/base_template.html +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/templates/emails/base_template.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/templates/emails/base_template_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/emails/views/email_rest_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/fields/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/fields/decimal_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/fields/media_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/fields/rich_text_field.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/authenticator.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/base.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/email.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/legacy.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/mfa/sms.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/authentication.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/request_too_big_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/middleware/ws_cookie_authentication_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0005_mfadevice_mfadevice_mfa_device_unique_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0006_alter_pfxuser_managers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0007_alter_pfxuser_options.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/0008_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/attachment_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/mfa_device.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/ordered_model_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/sms/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/sms/backends/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/sms/backends/base.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/sms/backends/console.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/storage/exceptions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/storage/local_storage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/version_check.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/authentication_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/mfa_authentication_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/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.dev25}/pfx/userjobs/migrations/0003_clean_scheduled_tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/migrations/0004_userjob_summary_url.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/migrations/0005_swappable_user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/migrations/0006_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/models/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/models/user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/models/user_job_attachment.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/providers/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/providers/user_job_django_q_executor.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/providers/user_job_websocket_channel_provider.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/tasks.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/views/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/views/user_job_attachment_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/views/user_job_view.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pfx/userjobs/views/user_websocket_consumer.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/pyproject.toml +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/requirements.txt +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/serve-doc +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/setup.cfg +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/setup.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/apps.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/channel_group_send_calls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/mfa_urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/mfa_test_utils.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_api_doc_search.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_client.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_emails_email_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_emails_email_model.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_emails_q_mailjet_email_backend.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_emails_send_email_message.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_choices.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_date.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_decimal.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_help_text.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_minutes_duration.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_one2many.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_rich_text.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_fields_time.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_mfa_legacy.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_mfa_login_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_mfa_setup_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_permissions.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_post_migrate_groups_update.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_settings.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_user_job_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_user_job_messages.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_user_job_model.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_user_websocket.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_version_check.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/tests/test_ws_cookie_middleware.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_base_user/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user/views.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/migrations/0002_lowercase_verbose_names.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/providers.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/scope.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/tests/test_user_job.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_custom_user_job/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/migrations/0001_initial.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/migrations/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/models.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/ci.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/common.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/dev.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/dev_custom_example.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/settings/dev_default.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/tests/__init__.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/tests/test_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/tests/test_auth_api.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/tests_user_email_login/urls.py +0 -0
- {django_pfx-1.7.6.dev23 → django_pfx-1.7.6.dev25}/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.dev25
|
|
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.dev25
|
|
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
|
|
@@ -73,6 +75,7 @@ pfx/pfxcore/shortcuts.py
|
|
|
73
75
|
pfx/pfxcore/test.py
|
|
74
76
|
pfx/pfxcore/urls.py
|
|
75
77
|
pfx/pfxcore/version_check.py
|
|
78
|
+
pfx/pfxcore/xml_test_runner.py
|
|
76
79
|
pfx/pfxcore/apidoc/__init__.py
|
|
77
80
|
pfx/pfxcore/apidoc/parameters.py
|
|
78
81
|
pfx/pfxcore/apidoc/schema.py
|
|
@@ -133,6 +136,7 @@ pfx/pfxcore/sms/__init__.py
|
|
|
133
136
|
pfx/pfxcore/sms/backends/__init__.py
|
|
134
137
|
pfx/pfxcore/sms/backends/base.py
|
|
135
138
|
pfx/pfxcore/sms/backends/console.py
|
|
139
|
+
pfx/pfxcore/sms/backends/memory.py
|
|
136
140
|
pfx/pfxcore/storage/__init__.py
|
|
137
141
|
pfx/pfxcore/storage/exceptions.py
|
|
138
142
|
pfx/pfxcore/storage/local_storage.py
|
|
@@ -225,6 +229,7 @@ tests/tests/test_emails_email_api.py
|
|
|
225
229
|
tests/tests/test_emails_email_model.py
|
|
226
230
|
tests/tests/test_emails_q_mailjet_email_backend.py
|
|
227
231
|
tests/tests/test_emails_send_email_message.py
|
|
232
|
+
tests/tests/test_emails_test_tools.py
|
|
228
233
|
tests/tests/test_fields_choices.py
|
|
229
234
|
tests/tests/test_fields_date.py
|
|
230
235
|
tests/tests/test_fields_decimal.py
|
|
@@ -246,6 +251,7 @@ tests/tests/test_post_migrate_groups_update.py
|
|
|
246
251
|
tests/tests/test_profiling_middleware.py
|
|
247
252
|
tests/tests/test_settings.py
|
|
248
253
|
tests/tests/test_shortcuts.py
|
|
254
|
+
tests/tests/test_test_runner.py
|
|
249
255
|
tests/tests/test_timezone_middleware.py
|
|
250
256
|
tests/tests/test_tools.py
|
|
251
257
|
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",
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"pfx/emails/templates/emails/base_template.html",
|
|
51
52
|
"pfx/emails/templates/emails/base_template.txt",
|
|
52
53
|
"pfx/emails/templates/emails/base_template_subject.txt",
|
|
54
|
+
"pfx/emails/test.py",
|
|
53
55
|
"pfx/emails/urls.py",
|
|
54
56
|
"pfx/emails/views/__init__.py",
|
|
55
57
|
"pfx/emails/views/email_rest_view.py",
|
|
@@ -118,6 +120,7 @@
|
|
|
118
120
|
"pfx/pfxcore/sms/backends/__init__.py",
|
|
119
121
|
"pfx/pfxcore/sms/backends/base.py",
|
|
120
122
|
"pfx/pfxcore/sms/backends/console.py",
|
|
123
|
+
"pfx/pfxcore/sms/backends/memory.py",
|
|
121
124
|
"pfx/pfxcore/storage/__init__.py",
|
|
122
125
|
"pfx/pfxcore/storage/exceptions.py",
|
|
123
126
|
"pfx/pfxcore/storage/local_storage.py",
|
|
@@ -158,6 +161,7 @@
|
|
|
158
161
|
"pfx/pfxcore/views/parameters/subset_page_size.py",
|
|
159
162
|
"pfx/pfxcore/views/parameters/subset_page_subset.py",
|
|
160
163
|
"pfx/pfxcore/views/rest_views.py",
|
|
164
|
+
"pfx/pfxcore/xml_test_runner.py",
|
|
161
165
|
"pfx/settings/__init__.py",
|
|
162
166
|
"pfx/settings/dev.py",
|
|
163
167
|
"pfx/userjobs/__init__.py",
|
|
@@ -215,6 +219,7 @@
|
|
|
215
219
|
"tests/tests/test_emails_email_model.py",
|
|
216
220
|
"tests/tests/test_emails_q_mailjet_email_backend.py",
|
|
217
221
|
"tests/tests/test_emails_send_email_message.py",
|
|
222
|
+
"tests/tests/test_emails_test_tools.py",
|
|
218
223
|
"tests/tests/test_fields_choices.py",
|
|
219
224
|
"tests/tests/test_fields_date.py",
|
|
220
225
|
"tests/tests/test_fields_decimal.py",
|
|
@@ -236,6 +241,7 @@
|
|
|
236
241
|
"tests/tests/test_profiling_middleware.py",
|
|
237
242
|
"tests/tests/test_settings.py",
|
|
238
243
|
"tests/tests/test_shortcuts.py",
|
|
244
|
+
"tests/tests/test_test_runner.py",
|
|
239
245
|
"tests/tests/test_timezone_middleware.py",
|
|
240
246
|
"tests/tests/test_tools.py",
|
|
241
247
|
"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)
|
|
@@ -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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|