From a325288ecc449ce3f4a704aae772fc5c66c5701d Mon Sep 17 00:00:00 2001 From: Jonathan Willitts Date: Tue, 14 Jan 2025 12:09:49 +0000 Subject: [PATCH 1/5] bump pre-commit repos --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bace820..5825210 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ exclude: tests/etc/user-* repos: - repo: https://github.com/PyCQA/bandit - rev: 1.7.10 + rev: 1.8.2 hooks: - id: bandit args: From 034575f228b3cff413472f534ed9e7f645677e6a Mon Sep 17 00:00:00 2001 From: Jonathan Willitts Date: Tue, 21 Jan 2025 16:51:40 +0000 Subject: [PATCH 2/5] Refactor tests to use edc_test_settings.default_test_settings --- edc_qol/tests/test_settings.py | 59 ++++++++++++++++++++++++++++ runtests.py | 70 +--------------------------------- 2 files changed, 61 insertions(+), 68 deletions(-) create mode 100644 edc_qol/tests/test_settings.py diff --git a/edc_qol/tests/test_settings.py b/edc_qol/tests/test_settings.py new file mode 100644 index 0000000..573c83f --- /dev/null +++ b/edc_qol/tests/test_settings.py @@ -0,0 +1,59 @@ +import sys +from pathlib import Path + +from edc_test_settings.default_test_settings import DefaultTestSettings + +app_name = "edc_qol" +base_dir = Path(__file__).absolute().parent.parent.parent + +project_settings = DefaultTestSettings( + calling_file=__file__, + BASE_DIR=base_dir, + APP_NAME=app_name, + SILENCED_SYSTEM_CHECKS=[ + "sites.E101", + "edc_navbar.E003", + "edc_consent.E001", + "edc_sites.E001", + "edc_sites.E002", + ], + SUBJECT_VISIT_MODEL="edc_visit_tracking.subjectvisit", + EDC_AUTH_SKIP_SITE_AUTHS=True, + INSTALLED_APPS=[ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.sites", + "multisite", + "django_crypto_fields.apps.AppConfig", + "django_revision.apps.AppConfig", + "edc_action_item.apps.AppConfig", + "edc_appointment.apps.AppConfig", + "edc_auth.apps.AppConfig", + "edc_dashboard.apps.AppConfig", + "edc_data_manager.apps.AppConfig", + "edc_facility.apps.AppConfig", + "edc_form_runners.apps.AppConfig", + "edc_lab.apps.AppConfig", + "edc_list_data.apps.AppConfig", + "edc_listboard.apps.AppConfig", + "edc_metadata.apps.AppConfig", + "edc_navbar.apps.AppConfig", + "edc_notification.apps.AppConfig", + "edc_registration.apps.AppConfig", + "edc_review_dashboard.apps.AppConfig", + "edc_sites.apps.AppConfig", + "edc_subject_dashboard.apps.AppConfig", + "edc_visit_schedule.apps.AppConfig", + "edc_visit_tracking.apps.AppConfig", + "edc_qol.apps.AppConfig", + "edc_appconfig.apps.AppConfig", + ], + add_dashboard_middleware=True, +).settings + +for k, v in project_settings.items(): + setattr(sys.modules[__name__], k, v) diff --git a/runtests.py b/runtests.py index 5614335..9834a70 100644 --- a/runtests.py +++ b/runtests.py @@ -1,71 +1,5 @@ #!/usr/bin/env python -import logging -from pathlib import Path - -from edc_test_utils import DefaultTestSettings, func_main - -app_name = "edc_qol" - -base_dir = Path(__file__).absolute().parent - -project_settings = DefaultTestSettings( - calling_file=__file__, - BASE_DIR=base_dir, - APP_NAME=app_name, - SILENCED_SYSTEM_CHECKS=[ - "sites.E101", - "edc_navbar.E002", - "edc_navbar.E003", - "edc_consent.E001", - "edc_sites.E001", - "edc_sites.E002", - ], - SUBJECT_VISIT_MODEL="edc_visit_tracking.subjectvisit", - ETC_DIR=str(base_dir / app_name / "tests" / "etc"), - EDC_AUTH_SKIP_SITE_AUTHS=True, - EDC_AUTH_SKIP_AUTH_UPDATER=True, - EDC_SITES_REGISTER_DEFAULT=True, - INSTALLED_APPS=[ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "django.contrib.sites", - "multisite", - "django_crypto_fields.apps.AppConfig", - "django_revision.apps.AppConfig", - "edc_action_item.apps.AppConfig", - "edc_appointment.apps.AppConfig", - "edc_auth.apps.AppConfig", - "edc_dashboard.apps.AppConfig", - "edc_data_manager.apps.AppConfig", - "edc_facility.apps.AppConfig", - "edc_form_runners.apps.AppConfig", - "edc_lab.apps.AppConfig", - "edc_list_data.apps.AppConfig", - "edc_listboard.apps.AppConfig", - "edc_metadata.apps.AppConfig", - "edc_navbar.apps.AppConfig", - "edc_notification.apps.AppConfig", - "edc_registration.apps.AppConfig", - "edc_review_dashboard.apps.AppConfig", - "edc_sites.apps.AppConfig", - "edc_subject_dashboard.apps.AppConfig", - "edc_visit_schedule.apps.AppConfig", - "edc_visit_tracking.apps.AppConfig", - "edc_qol.apps.AppConfig", - "edc_appconfig.apps.AppConfig", - ], - add_dashboard_middleware=True, -).settings - - -def main(): - func_main(project_settings, *[f"{app_name}.tests"]) - +from edc_test_settings.func_main import func_main2 if __name__ == "__main__": - logging.basicConfig() - main() + func_main2("edc_qol.tests.test_settings", "edc_qol.tests") From 158dbefa0263ccc9f60eda29d0cf1a6f3c33a8ee Mon Sep 17 00:00:00 2001 From: Jonathan Willitts Date: Tue, 21 Jan 2025 17:06:20 +0000 Subject: [PATCH 3/5] Fix navbar warning --- edc_qol/tests/test_settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/edc_qol/tests/test_settings.py b/edc_qol/tests/test_settings.py index 573c83f..7d10c03 100644 --- a/edc_qol/tests/test_settings.py +++ b/edc_qol/tests/test_settings.py @@ -19,6 +19,7 @@ ], SUBJECT_VISIT_MODEL="edc_visit_tracking.subjectvisit", EDC_AUTH_SKIP_SITE_AUTHS=True, + EDC_AUTH_SKIP_AUTH_UPDATER=True, INSTALLED_APPS=[ "django.contrib.admin", "django.contrib.auth", From 3b46a3d4135cdfb7665dbb635a4febaa38910422 Mon Sep 17 00:00:00 2001 From: Jonathan Willitts Date: Tue, 21 Jan 2025 20:10:32 +0000 Subject: [PATCH 4/5] Update format_html usages --- edc_qol/admin/sf12_admin.py | 34 +++++++---- edc_qol/model_mixins/eq5d3l_model_mixin.py | 10 ++- edc_qol/model_mixins/sf12_model_mixin.py | 61 +++++++++++++------ .../eq5d3l_model_admin_mixin.py | 5 +- 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/edc_qol/admin/sf12_admin.py b/edc_qol/admin/sf12_admin.py index 236c4f0..cae6ad6 100644 --- a/edc_qol/admin/sf12_admin.py +++ b/edc_qol/admin/sf12_admin.py @@ -1,5 +1,6 @@ from django.contrib import admin from django.utils.html import format_html +from django.utils.safestring import mark_safe from django_audit_fields.admin import audit_fieldset_tuple from edc_model_admin.dashboard import ModelAdminSubjectDashboardMixin from edc_model_admin.history import SimpleHistoryAdmin @@ -9,13 +10,16 @@ from ..models import Sf12 additional_instructions = format_html( - "

" - "This survey asks for your views about your health. This information " - "will help keep track of how you feel and how well you are able to do " - "your usual activities. " - "Answer each question by choosing just one answer. If you are " - "unsure how to answer a question, please give the best answer you can." - "

" + "{}", + mark_safe( # nosec B308, B703 + "

" + "This survey asks for your views about your health. This information " + "will help keep track of how you feel and how well you are able to do " + "your usual activities. " + "Answer each question by choosing just one answer. If you are " + "unsure how to answer a question, please give the best answer you can." + "

" + ), ) past_4w = "past 4 weeks" @@ -61,7 +65,9 @@ def sf12_fieldsets(): ( "Part 2: Activities limited by health", { - "description": format_html(part2_description), + "description": format_html( + "{}", mark_safe(part2_description) # nosec B308, B703 + ), "fields": ( "moderate_activities_now_limited", "climbing_stairs_now_limited", @@ -71,7 +77,9 @@ def sf12_fieldsets(): ( "Part 3: Physical health problems (last 4 weeks)", { - "description": format_html(part3_description), + "description": format_html( + "{}", mark_safe(part3_description) # nosec B308, B703 + ), "fields": ( "accomplished_less_physical_health", "work_limited_physical_health", @@ -81,7 +89,9 @@ def sf12_fieldsets(): ( "Part 4: Emotional problems (last 4 weeks)", { - "description": format_html(part4_description), + "description": format_html( + "{}", mark_safe(part4_description) # nosec B308, B703 + ), "fields": ( "accomplished_less_emotional", "work_less_carefully_emotional", @@ -95,7 +105,9 @@ def sf12_fieldsets(): ( "Part 6: Feeling (last 4 weeks)", { - "description": format_html(part6_description), + "description": format_html( + "{}", mark_safe(part6_description) # nosec B308, B703 + ), "fields": ( "felt_calm_peaceful", "felt_lot_energy", diff --git a/edc_qol/model_mixins/eq5d3l_model_mixin.py b/edc_qol/model_mixins/eq5d3l_model_mixin.py index f84367c..b6066ad 100644 --- a/edc_qol/model_mixins/eq5d3l_model_mixin.py +++ b/edc_qol/model_mixins/eq5d3l_model_mixin.py @@ -1,6 +1,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.utils.html import format_html +from django.utils.safestring import mark_safe from ..choices import ( ANXIETY_DEPRESSION, @@ -32,14 +33,17 @@ class Eq5d3lModelMixin(models.Model): ) health_today_score_slider = models.CharField( - verbose_name=format_html("Visual score for how your health is TODAY"), + verbose_name=format_html("{}", "Visual score for how your health is TODAY"), max_length=3, ) health_today_score_confirmed = models.IntegerField( verbose_name=format_html( - "Interviewer: " - "please confirm the number on the scale indicated from above." + "{}", + mark_safe( # nosec B308, B703 + "Interviewer: " + "please confirm the number on the scale indicated from above." + ), ), validators=[MinValueValidator(0), MaxValueValidator(100)], help_text=( diff --git a/edc_qol/model_mixins/sf12_model_mixin.py b/edc_qol/model_mixins/sf12_model_mixin.py index f2a1df0..ea4d9d7 100644 --- a/edc_qol/model_mixins/sf12_model_mixin.py +++ b/edc_qol/model_mixins/sf12_model_mixin.py @@ -1,5 +1,6 @@ from django.db import models from django.utils.html import format_html +from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from edc_constants.choices import YES_NO @@ -21,44 +22,62 @@ class Sf12ModelMixin(models.Model): moderate_activities_now_limited = models.CharField( verbose_name=format_html( - _( - "Moderate activities such as moving a table, " - "pushing a vacuum cleaner, bowling, or playing golf:" - ) + "{}", + mark_safe( # nosec B308, B703 + _( + "Moderate activities such as moving a table, " + "pushing a vacuum cleaner, bowling, or playing golf:" + ) + ), ), max_length=20, choices=HEALTH_LIMITED_CHOICES, ) climbing_stairs_now_limited = models.CharField( - verbose_name=format_html(_("Climbing several flights of stairs:")), + verbose_name=format_html( + "{}", + mark_safe(_("Climbing several flights of stairs:")), # nosec B308, B703 + ), max_length=20, choices=HEALTH_LIMITED_CHOICES, ) accomplished_less_physical_health = models.CharField( - verbose_name=format_html(_("Accomplished less than you would like:")), + verbose_name=format_html( + "{}", + mark_safe(_("Accomplished less than you would like:")), # nosec B308, B703 + ), max_length=15, choices=YES_NO, ) work_limited_physical_health = models.CharField( verbose_name=format_html( - _("Were limited in the kind of work or other activities:") + "{}", + mark_safe( # nosec B308, B703 + _("Were limited in the kind of work or other activities:") + ), ), max_length=15, choices=YES_NO, ) accomplished_less_emotional = models.CharField( - verbose_name=format_html(_("Accomplished less than you would like:")), + verbose_name=format_html( + "{}", + mark_safe(_("Accomplished less than you would like:")), # nosec B308, B703 + ), max_length=15, choices=YES_NO, ) work_less_carefully_emotional = models.CharField( verbose_name=format_html( - _("Did work or activities less carefully than usual:") + "{}", + mark_safe( # nosec B308, B703 + _("Did work or activities less carefully than usual:") + ), ), max_length=15, choices=YES_NO, @@ -66,10 +85,13 @@ class Sf12ModelMixin(models.Model): pain_interfere_work = models.CharField( verbose_name=format_html( - _( - "During the past 4 weeks, how much did pain interfere " - "with your normal work (including work outside the home and housework)?" - ) + "{}", + mark_safe( # nosec B308, B703 + _( + "During the past 4 weeks, how much did pain interfere " + "with your normal work (including work outside the home and housework)?" + ) + ), ), max_length=15, choices=WORK_PAIN_INTERFERENCE_CHOICES, @@ -95,11 +117,14 @@ class Sf12ModelMixin(models.Model): social_activities_interfered = models.CharField( verbose_name=format_html( - _( - "During the past 4 weeks, how much of the time has your physical " - "health or emotional problems interfered with your social " - "activities (like visiting friends, relatives, etc.)?" - ) + "{}", + mark_safe( # nosec B308, B703 + _( + "During the past 4 weeks, how much of the time has your physical " + "health or emotional problems interfered with your social " + "activities (like visiting friends, relatives, etc.)?" + ) + ), ), max_length=25, choices=INTERFERENCE_DURATION_CHOICES, diff --git a/edc_qol/modeladmin_mixins/eq5d3l_model_admin_mixin.py b/edc_qol/modeladmin_mixins/eq5d3l_model_admin_mixin.py index 6398736..0125c9a 100644 --- a/edc_qol/modeladmin_mixins/eq5d3l_model_admin_mixin.py +++ b/edc_qol/modeladmin_mixins/eq5d3l_model_admin_mixin.py @@ -1,5 +1,6 @@ from django.contrib import admin from django.utils.html import format_html +from django.utils.safestring import mark_safe from django_audit_fields.admin import audit_fieldset_tuple eq5d3l_description = """ @@ -36,7 +37,9 @@ def eq5d3l_fieldsets(): ( "How is your health TODAY?", { - "description": format_html(eq5d3l_description), + "description": format_html( + "{}", mark_safe(eq5d3l_description) # nosec B308, B703 + ), "fields": ( "health_today_score_slider", "health_today_score_confirmed", From c926309a9a2ff9e99e5ef7e06f11312ec1c5780b Mon Sep 17 00:00:00 2001 From: erikvw Date: Tue, 21 Jan 2025 19:53:00 -0600 Subject: [PATCH 5/5] format_html, mark_safe, translations --- edc_qol/model_mixins/eq5d3l_model_mixin.py | 38 +++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/edc_qol/model_mixins/eq5d3l_model_mixin.py b/edc_qol/model_mixins/eq5d3l_model_mixin.py index b6066ad..9778c4d 100644 --- a/edc_qol/model_mixins/eq5d3l_model_mixin.py +++ b/edc_qol/model_mixins/eq5d3l_model_mixin.py @@ -2,6 +2,7 @@ from django.db import models from django.utils.html import format_html from django.utils.safestring import mark_safe +from django.utils.translation import gettext as _ from ..choices import ( ANXIETY_DEPRESSION, @@ -18,42 +19,49 @@ class Eq5d3lModelMixin(models.Model): self_care = models.CharField(verbose_name="Self-care", max_length=45, choices=SELF_CARE) usual_activities = models.CharField( - verbose_name="Usual activities", + verbose_name=_("Usual activities"), max_length=45, - help_text="Example. work, study, housework, family or leisure activities", + help_text=_("Example. work, study, housework, family or leisure activities"), choices=USUAL_ACTIVITIES, ) pain_discomfort = models.CharField( - verbose_name="Pain / Discomfort", max_length=45, choices=PAIN_DISCOMFORT + verbose_name=_("Pain / Discomfort"), max_length=45, choices=PAIN_DISCOMFORT ) anxiety_depression = models.CharField( - verbose_name="Anxiety / Depression", max_length=45, choices=ANXIETY_DEPRESSION + verbose_name=_("Anxiety / Depression"), max_length=45, choices=ANXIETY_DEPRESSION ) health_today_score_slider = models.CharField( - verbose_name=format_html("{}", "Visual score for how your health is TODAY"), + verbose_name=_("Visual score for how your health is TODAY"), max_length=3, ) health_today_score_confirmed = models.IntegerField( verbose_name=format_html( "{}", - mark_safe( # nosec B308, B703 - "Interviewer: " - "please confirm the number on the scale indicated from above." - ), + mark_safe( + _( + "Interviewer: " + "please confirm the number on the scale indicated from above." + ) + ), # nosec B308, B703 ), validators=[MinValueValidator(0), MaxValueValidator(100)], - help_text=( - "This scale is numbered from 0 to 100. " - "100 means the best health you can imagine" - "0 means the worst health you can imagine." + help_text=format_html( + "{}", + mark_safe( + _( + "This scale is numbered from 0 to 100. " + "100 means the best health you can imagine" + "0 means the worst health you can imagine." + ) + ), # nosec B308, B703 ), ) class Meta: abstract = True - verbose_name = "EuroQol EQ-5D-3L Instrument" - verbose_name_plural = "EuroQol EQ-5D-3L Instrument" + verbose_name = _("EuroQol EQ-5D-3L Instrument") + verbose_name_plural = _("EuroQol EQ-5D-3L Instrument")