clinicedc 2.0.28__py3-none-any.whl → 2.0.30__py3-none-any.whl

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.

Potentially problematic release.


This version of clinicedc might be problematic. Click here for more details.

Files changed (98) hide show
  1. {clinicedc-2.0.28.dist-info → clinicedc-2.0.30.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.28.dist-info → clinicedc-2.0.30.dist-info}/RECORD +98 -98
  3. edc_auth/admin/fieldsets.py +11 -15
  4. edc_auth/admin/group_admin.py +2 -5
  5. edc_auth/admin/list_filters.py +8 -7
  6. edc_auth/admin/role_admin.py +7 -10
  7. edc_auth/admin/user_admin.py +2 -2
  8. edc_auth/admin/user_profile_admin.py +3 -7
  9. edc_auth/apps.py +2 -2
  10. edc_auth/auth_updater/group_updater.py +4 -4
  11. edc_auth/auth_updater/role_updater.py +1 -3
  12. edc_auth/backends.py +1 -1
  13. edc_auth/export_users.py +6 -5
  14. edc_auth/fix_export_permissions.py +8 -8
  15. edc_auth/forms.py +21 -24
  16. edc_auth/get_app_codenames.py +2 -2
  17. edc_auth/import_users.py +25 -24
  18. edc_auth/management/commands/export_users.py +1 -1
  19. edc_auth/management/commands/fix_export_permissions.py +1 -1
  20. edc_auth/management/commands/import_users.py +1 -1
  21. edc_auth/management/commands/reset_password.py +2 -2
  22. edc_auth/models/signals.py +1 -1
  23. edc_auth/models/user_profile.py +4 -5
  24. edc_auth/password_setter.py +4 -4
  25. edc_auth/post_migrate_signals.py +2 -2
  26. edc_auth/send_new_credentials_to_user.py +1 -1
  27. edc_auth/system_checks.py +7 -6
  28. edc_auth/utils.py +10 -12
  29. edc_consent/consent_definition.py +4 -1
  30. edc_dashboard/view_mixins/edc_view_mixin.py +1 -1
  31. edc_model_admin/mixins/model_admin_form_instructions_mixin.py +9 -3
  32. edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +3 -3
  33. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +7 -7
  34. edc_model_admin/mixins/model_admin_redirect_on_delete_mixin.py +6 -8
  35. edc_pharmacy/admin_mixin.py +1 -1
  36. edc_pharmacy/approve_prescription.py +10 -8
  37. edc_pharmacy/auth_objects.py +1 -1
  38. edc_pharmacy/exceptions.py +7 -7
  39. edc_pharmacy/settings.py +1 -1
  40. edc_pharmacy/views/add_to_storage_bin_view.py +22 -24
  41. edc_pharmacy/views/allocate_to_subject_view.py +10 -18
  42. edc_pharmacy/views/celery_task_status_view.py +1 -2
  43. edc_pharmacy/views/confirm_stock_from_instance_view.py +1 -1
  44. edc_pharmacy/views/confirm_stock_from_queryset_view.py +5 -8
  45. edc_pharmacy/views/dispense_view.py +1 -1
  46. edc_pharmacy/views/move_to_storage_bin_view.py +7 -3
  47. edc_pharmacy/views/prepare_and_review_stock_request_view.py +62 -70
  48. edc_pharmacy/views/print_labels_view.py +1 -1
  49. edc_pharmacy/views/transfer_stock_view.py +1 -1
  50. edc_prn/modelform_mixins.py +8 -9
  51. edc_prn/models.py +3 -1
  52. edc_prn/site_prn_forms.py +2 -2
  53. edc_prn/templatetags/edc_prn_extras.py +1 -1
  54. edc_protocol/middleware.py +1 -1
  55. edc_protocol/research_protocol_config.py +7 -5
  56. edc_protocol_incident/admin/protocol_deviation_violation_admin.py +1 -1
  57. edc_protocol_incident/form_validators/mixins.py +9 -6
  58. edc_protocol_incident/modeladmin_mixins.py +1 -1
  59. edc_pylabels/admin/label_configuration_admin.py +1 -1
  60. edc_pylabels/admin/label_specification_admin.py +1 -1
  61. edc_pylabels/auth_objects.py +1 -1
  62. edc_pylabels/site_label_configs.py +2 -2
  63. edc_qareports/admin/qa_report_log_admin.py +5 -5
  64. edc_qareports/admin/qa_report_log_summary_admin.py +1 -1
  65. edc_qareports/forms/note_form.py +2 -3
  66. edc_qareports/modeladmin_mixins/list_filters.py +23 -19
  67. edc_qareports/modeladmin_mixins/note_modeladmin_mixin.py +7 -7
  68. edc_qareports/modeladmin_mixins/on_study_missing_values_modeladmin_mixin.py +8 -8
  69. edc_qareports/modeladmin_mixins/qa_report_modeladmin_mixin.py +3 -7
  70. edc_qareports/sql_generator/crf_case.py +1 -1
  71. edc_qareports/sql_generator/crf_subquery.py +1 -1
  72. edc_qareports/sql_generator/requisition_subquery.py +1 -1
  73. edc_qareports/sql_generator/sql_view_generator.py +1 -1
  74. edc_qareports/sql_generator/subquery_from_dict.py +39 -39
  75. edc_qareports/utils.py +12 -13
  76. edc_randomization/model_mixins.py +1 -1
  77. edc_randomization/system_checks.py +1 -1
  78. edc_refusal/admin.py +4 -2
  79. edc_registration/modeladmin_mixins.py +18 -20
  80. edc_registration/modelform_mixins.py +2 -2
  81. edc_registration/models/signals.py +1 -1
  82. edc_registration/utils.py +1 -1
  83. edc_reportable/age_evaluator.py +4 -4
  84. edc_reportable/data/grading_data/daids_july_2017.py +3 -3
  85. edc_reportable/evaluator.py +15 -15
  86. edc_reportable/exceptions.py +4 -4
  87. edc_reportable/forms/reportables_form_validator_mixin.py +6 -2
  88. edc_reportable/management/commands/export_reportables.py +1 -1
  89. edc_reportable/models/grading_exception.py +1 -6
  90. edc_reportable/models/normal_data.py +3 -3
  91. edc_reportable/models/reference_range_collection.py +1 -6
  92. edc_reportable/utils/get_grade_for_value.py +15 -15
  93. edc_reportable/utils/get_normal_data_or_raise.py +14 -14
  94. edc_reportable/utils/in_normal_bounds_or_raise.py +6 -6
  95. edc_reportable/utils/load_data.py +1 -1
  96. edc_reportable/utils/update_grading_exceptions.py +5 -5
  97. {clinicedc-2.0.28.dist-info → clinicedc-2.0.30.dist-info}/WHEEL +0 -0
  98. {clinicedc-2.0.28.dist-info → clinicedc-2.0.30.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,5 @@
1
1
  from uuid import uuid4
2
2
 
3
- import pandas as pd
4
3
  from celery.states import PENDING
5
4
  from django.apps import apps as django_apps
6
5
  from django.conf import settings
@@ -9,7 +8,6 @@ from django.contrib.auth.decorators import login_required
9
8
  from django.http import HttpResponseRedirect
10
9
  from django.urls import reverse
11
10
  from django.utils.decorators import method_decorator
12
- from django.utils.html import format_html
13
11
  from django.utils.safestring import mark_safe
14
12
  from django.views.generic import TemplateView
15
13
  from django_pandas.io import read_frame
@@ -37,22 +35,24 @@ class PrepareAndReviewStockRequestView(
37
35
  df = get_next_scheduled_visit_for_subjects_df(stock_request)
38
36
 
39
37
  # get unallocated stock that appears in a stock request for this location
40
- df_unallocated_request_items = read_frame(
41
- StockRequestItem.objects.values(
42
- "stock_request__request_identifier",
43
- "registered_subject__subject_identifier",
44
- ).filter(stock_request__location=stock_request.location, allocation__isnull=True)
45
- )
46
- df_unallocated_request_items.rename(
47
- columns={
48
- "registered_subject__subject_identifier": "subject_identifier",
49
- "stock_request__request_identifier": "request_identifier",
50
- },
51
- inplace=True,
38
+ df_unallocated_request_items = (
39
+ read_frame(
40
+ StockRequestItem.objects.values(
41
+ "stock_request__request_identifier",
42
+ "registered_subject__subject_identifier",
43
+ ).filter(
44
+ stock_request__location=stock_request.location, allocation__isnull=True
45
+ )
46
+ )
47
+ .rename(
48
+ columns={
49
+ "registered_subject__subject_identifier": "subject_identifier",
50
+ "stock_request__request_identifier": "request_identifier",
51
+ },
52
+ )
53
+ .reset_index(drop=True)
52
54
  )
53
- df_unallocated_request_items.reset_index(drop=True, inplace=True)
54
- df_unallocated_request_items = pd.merge(
55
- df_unallocated_request_items,
55
+ df_unallocated_request_items = df_unallocated_request_items.merge(
56
56
  df[["subject_identifier", "next_visit_code", "next_appt_datetime"]],
57
57
  on="subject_identifier",
58
58
  how="left",
@@ -60,13 +60,14 @@ class PrepareAndReviewStockRequestView(
60
60
  df_unallocated_request_items = df_unallocated_request_items[
61
61
  df_unallocated_request_items.next_visit_code.notna()
62
62
  ]
63
- df_unallocated_request_items.sort_values(by=["subject_identifier"]).reset_index(
64
- drop=True, inplace=True
65
- )
63
+ df_unallocated_request_items = df_unallocated_request_items.sort_values(
64
+ by=["subject_identifier"]
65
+ ).reset_index()
66
66
 
67
67
  # exclude unallocated subjects from appts
68
- df = df[~df.subject_identifier.isin(df_unallocated_request_items.subject_identifier)]
69
- df.reset_index(drop=True, inplace=True)
68
+ df = df[
69
+ ~df.subject_identifier.isin(df_unallocated_request_items.subject_identifier)
70
+ ].reset_index(drop=True)
70
71
 
71
72
  kwargs.update(
72
73
  stock_request=stock_request,
@@ -128,55 +129,46 @@ class PrepareAndReviewStockRequestView(
128
129
  subjects_excluded_by_request=len(
129
130
  df_unallocated_request_items.subject_identifier.unique()
130
131
  ),
131
- nostock_table=format_html(
132
- "{}",
133
- mark_safe(
134
- df_nostock.to_html(
135
- columns=[
136
- "subject_identifier",
137
- "next_visit_code",
138
- "next_appt_datetime",
139
- ],
140
- index=True,
141
- border=0,
142
- classes="table table-striped",
143
- table_id="my_table",
144
- )
145
- ), # nosec B703 B308
132
+ nostock_table=mark_safe( # noqa: S308
133
+ df_nostock.to_html(
134
+ columns=[
135
+ "subject_identifier",
136
+ "next_visit_code",
137
+ "next_appt_datetime",
138
+ ],
139
+ index=True,
140
+ border=0,
141
+ classes="table table-striped",
142
+ table_id="my_table",
143
+ )
146
144
  ),
147
- instock_table=format_html(
148
- "{}",
149
- mark_safe(
150
- df_instock.to_html(
151
- columns=[
152
- "subject_identifier",
153
- "next_visit_code",
154
- "next_appt_datetime",
155
- "code",
156
- ],
157
- index=True,
158
- border=0,
159
- classes="table table-striped",
160
- table_id="in_stock_table",
161
- )
162
- ), # nosec B703 B308
145
+ instock_table=mark_safe( # noqa: S308
146
+ df_instock.to_html(
147
+ columns=[
148
+ "subject_identifier",
149
+ "next_visit_code",
150
+ "next_appt_datetime",
151
+ "code",
152
+ ],
153
+ index=True,
154
+ border=0,
155
+ classes="table table-striped",
156
+ table_id="in_stock_table",
157
+ )
163
158
  ),
164
- unallocated_table=format_html(
165
- "{}",
166
- mark_safe(
167
- df_unallocated_request_items.to_html(
168
- columns=[
169
- "subject_identifier",
170
- "next_visit_code",
171
- "next_appt_datetime",
172
- "request_identifier",
173
- ],
174
- index=True,
175
- border=0,
176
- classes="table table-striped",
177
- table_id="unallocated_table",
178
- )
179
- ), # nosec B703 B308
159
+ unallocated_table=mark_safe( # noqa: S308
160
+ df_unallocated_request_items.to_html(
161
+ columns=[
162
+ "subject_identifier",
163
+ "next_visit_code",
164
+ "next_appt_datetime",
165
+ "request_identifier",
166
+ ],
167
+ index=True,
168
+ border=0,
169
+ classes="table table-striped",
170
+ table_id="unallocated_table",
171
+ )
180
172
  ),
181
173
  session_uuid=session_uuid,
182
174
  )
@@ -190,7 +182,7 @@ class PrepareAndReviewStockRequestView(
190
182
  def model_cls(self):
191
183
  return django_apps.get_model("edc_pharmacy.stocktransfer")
192
184
 
193
- def post(self, request, *args, **kwargs):
185
+ def post(self, request, *args, **kwargs): # noqa: ARG002
194
186
  session_uuid = request.POST.get("session_uuid")
195
187
  stock_request = StockRequest.objects.get(pk=request.POST.get("stock_request"))
196
188
  if not request.POST.get("cancel") and session_uuid:
@@ -58,7 +58,7 @@ class PrintLabelsView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Templ
58
58
  def model_cls(self):
59
59
  return django_apps.get_model(f"edc_pharmacy.{self.kwargs.get('model')}")
60
60
 
61
- def post(self, request, *args, **kwargs):
61
+ def post(self, request, *args, **kwargs): # noqa: ARG002
62
62
  session_uuid = str(kwargs.get("session_uuid"))
63
63
  stock_pks = request.session.get(session_uuid, [])
64
64
  url = self.source_changelist_url
@@ -54,7 +54,7 @@ class TransferStockView(EdcViewMixin, NavbarViewMixin, EdcProtocolViewMixin, Tem
54
54
  def model_cls(self):
55
55
  return django_apps.get_model("edc_pharmacy.stocktransfer")
56
56
 
57
- def post(self, request, *args, **kwargs):
57
+ def post(self, request, *args, **kwargs): # noqa: ARG002
58
58
  stock_transfer = StockTransfer.objects.get(pk=self.kwargs.get("stock_transfer"))
59
59
  stock_codes = request.POST.getlist("codes")
60
60
  if stock_codes:
@@ -8,7 +8,6 @@ from django.utils.text import format_lazy
8
8
  from django.utils.translation import gettext_lazy as _
9
9
 
10
10
  from edc_consent import site_consents
11
- from edc_consent.consent_definition import ConsentDefinition
12
11
  from edc_crf.crf_form_validator_mixins import BaseFormValidatorMixin
13
12
 
14
13
 
@@ -19,17 +18,17 @@ class PrnFormValidatorMixin(BaseFormValidatorMixin):
19
18
 
20
19
  @property
21
20
  def subject_consent(self):
22
- return self.get_consent_definition(
21
+ return site_consents.get_consent_definition(
23
22
  report_datetime=self.report_datetime
24
23
  ).model_cls.objects.get(subject_identifier=self.subject_identifier)
25
24
 
26
- def get_consent_definition(
27
- self,
28
- report_datetime: datetime = None,
29
- fldname: str = None,
30
- error_code: str = None,
31
- ) -> ConsentDefinition:
32
- return site_consents.get_consent_definition(report_datetime=self.report_datetime)
25
+ # def get_consent_definition(
26
+ # self,
27
+ # report_datetime: datetime | None = None,
28
+ # fldname: str | None = None,
29
+ # error_code: str | None = None,
30
+ # ) -> ConsentDefinition:
31
+ # return site_consents.get_consent_definition(report_datetime=self.report_datetime)
33
32
 
34
33
  @property
35
34
  def report_datetime(self) -> datetime:
edc_prn/models.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  from django.db import models
4
4
 
5
+ from edc_constants.constants import NULL_STRING
6
+
5
7
 
6
8
  class SingletonPrnModelMixin(models.Model):
7
9
  """Enforces one record per subject."""
@@ -11,7 +13,7 @@ class SingletonPrnModelMixin(models.Model):
11
13
  max_length=50,
12
14
  unique=True,
13
15
  help_text="auto updated for unique constraint",
14
- null=True,
16
+ default=NULL_STRING,
15
17
  editable=False,
16
18
  )
17
19
 
edc_prn/site_prn_forms.py CHANGED
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
14
14
  from edc_prn import Prn
15
15
 
16
16
 
17
- class AlreadyRegistered(Exception):
17
+ class AlreadyRegistered(Exception): # noqa: N818
18
18
  pass
19
19
 
20
20
 
@@ -72,7 +72,7 @@ class PrnFormsCollection:
72
72
  except ImportError as e:
73
73
  site_prn_forms.registry = before_import_registry
74
74
  if module_has_submodule(mod, module_name):
75
- raise SitePrnFormsError(str(e))
75
+ raise SitePrnFormsError(str(e)) from e
76
76
  except ImportError:
77
77
  pass
78
78
 
@@ -23,7 +23,7 @@ def prn_list_items(subject_identifier, **kwargs):
23
23
  prn_forms = []
24
24
  for prn in site_prn_forms:
25
25
  if prn.get_show_on_dashboard(subject_identifier=subject_identifier):
26
- prn_forms.append(prn)
26
+ prn_forms.append(prn) # noqa: PERF401
27
27
  if prn_forms:
28
28
  prn_forms = sorted(prn_forms, key=lambda x: x.verbose_name)
29
29
  return dict(prn_forms=prn_forms, subject_identifier=subject_identifier)
@@ -11,7 +11,7 @@ class ResearchProtocolConfigMiddleware:
11
11
  def process_view(self, request, *args):
12
12
  pass
13
13
 
14
- def process_template_response(self, request, response):
14
+ def process_template_response(self, request, response): # noqa: ARG002
15
15
  if not response.context_data:
16
16
  response.context_data = {}
17
17
  protocol_config = ResearchProtocolConfig()
@@ -134,7 +134,9 @@ class ResearchProtocolConfig:
134
134
  return getattr(
135
135
  settings,
136
136
  "EDC_PROTOCOL_SUBJECT_IDENTIFIER_PATTERN",
137
- r"%(protocol_number)s\-[0-9\-]+" % dict(protocol_number=self.protocol_number),
137
+ r"{protocol_number}\-[0-9\-]+".format(
138
+ **dict(protocol_number=self.protocol_number)
139
+ ),
138
140
  )
139
141
 
140
142
  @property
@@ -145,14 +147,14 @@ class ResearchProtocolConfig:
145
147
  def study_open_datetime(self) -> datetime:
146
148
  try:
147
149
  study_open_datetime = settings.EDC_PROTOCOL_STUDY_OPEN_DATETIME
148
- except AttributeError:
150
+ except AttributeError as e:
149
151
  raise ImproperlyConfigured(
150
152
  self.error_msg1
151
153
  % {
152
154
  "attr": "study_open_datetime",
153
155
  "settings_attr": "EDC_PROTOCOL_STUDY_OPEN_DATETIME",
154
156
  }
155
- )
157
+ ) from e
156
158
  if not study_open_datetime:
157
159
  raise ImproperlyConfigured(
158
160
  self.error_msg2
@@ -167,14 +169,14 @@ class ResearchProtocolConfig:
167
169
  def study_close_datetime(self) -> datetime:
168
170
  try:
169
171
  study_close_datetime = settings.EDC_PROTOCOL_STUDY_CLOSE_DATETIME
170
- except AttributeError:
172
+ except AttributeError as e:
171
173
  raise ImproperlyConfigured(
172
174
  self.error_msg1
173
175
  % {
174
176
  "attr": "study_close_datetime",
175
177
  "settings_attr": "EDC_PROTOCOL_STUDY_CLOSE_DATETIME",
176
178
  }
177
- )
179
+ ) from e
178
180
  if not study_close_datetime:
179
181
  raise ImproperlyConfigured(
180
182
  self.error_msg2
@@ -65,7 +65,7 @@ class ProtocolDeviationViolationAdmin(ModelAdminSubjectDashboardMixin, SimpleHis
65
65
  audit_fieldset_tuple,
66
66
  )
67
67
 
68
- radio_fields = {
68
+ radio_fields = { # noqa: RUF012
69
69
  "action_required": admin.VERTICAL,
70
70
  "report_status": admin.VERTICAL,
71
71
  "report_type": admin.VERTICAL,
@@ -40,9 +40,12 @@ class IncidentFormvalidatorMixin:
40
40
  self.validate_date_not_before_incident("report_closed_datetime")
41
41
 
42
42
  def validate_date_not_before_incident(self, fld_name):
43
- if self.cleaned_data.get(fld_name) and self.cleaned_data.get("incident_datetime"):
44
- if self.cleaned_data.get(fld_name) < self.cleaned_data.get("incident_datetime"):
45
- self.raise_validation_error(
46
- {fld_name: "May not be before incident date/time"},
47
- error_code=INVALID_ERROR,
48
- )
43
+ if (
44
+ self.cleaned_data.get(fld_name)
45
+ and self.cleaned_data.get("incident_datetime")
46
+ and self.cleaned_data.get(fld_name) < self.cleaned_data.get("incident_datetime")
47
+ ):
48
+ self.raise_validation_error(
49
+ {fld_name: "May not be before incident date/time"},
50
+ error_code=INVALID_ERROR,
51
+ )
@@ -60,7 +60,7 @@ class ProtocolIncidentModelAdminMixin:
60
60
  audit_fieldset_tuple,
61
61
  )
62
62
 
63
- radio_fields = {
63
+ radio_fields = { # noqa: RUF012
64
64
  "action_required": admin.VERTICAL,
65
65
  "report_status": admin.VERTICAL,
66
66
  "report_type": admin.VERTICAL,
@@ -29,7 +29,7 @@ class LabelConfigurationAdmin(
29
29
  admin.ModelAdmin,
30
30
  ):
31
31
  show_object_tools = True
32
- actions = [print_test_label_sheet_action]
32
+ actions = (print_test_label_sheet_action,)
33
33
  form = LabelConfigurationForm
34
34
 
35
35
  instructions = (
@@ -26,7 +26,7 @@ class LabelSpecificationAdmin(
26
26
  ModelAdminRedirectOnDeleteMixin,
27
27
  admin.ModelAdmin,
28
28
  ):
29
- actions = [copy_label_specification, export_to_csv]
29
+ actions = (copy_label_specification, export_to_csv)
30
30
 
31
31
  instructions = (
32
32
  "This model captures the dimensions, rows, columns, "
@@ -11,5 +11,5 @@ for app_config in django_apps.get_app_configs():
11
11
  for model_cls in app_config.get_models():
12
12
  app_name, model_name = model_cls._meta.label_lower.split(".")
13
13
  for prefix in ["add", "change", "view", "delete"]:
14
- codenames.append(f"{app_name}.{prefix}_{model_name}")
14
+ codenames.append(f"{app_name}.{prefix}_{model_name}") # noqa: PERF401
15
15
  codenames.sort()
@@ -11,7 +11,7 @@ from django.core.management.color import color_style
11
11
  from django.utils.module_loading import module_has_submodule
12
12
 
13
13
 
14
- class AlreadyRegistered(Exception):
14
+ class AlreadyRegistered(Exception): # noqa: N818
15
15
  pass
16
16
 
17
17
 
@@ -104,7 +104,7 @@ class SiteLabelConfigs:
104
104
  except ImportError as e:
105
105
  site_label_configs.registry = before_import_registry
106
106
  if module_has_submodule(mod, module_name):
107
- raise SitePharmacyError(str(e))
107
+ raise SitePharmacyError(str(e)) from e
108
108
  except ImportError:
109
109
  pass
110
110
 
@@ -17,15 +17,15 @@ class QaReportLogAdmin(
17
17
  TemplatesModelAdminMixin,
18
18
  admin.ModelAdmin,
19
19
  ):
20
- ordering = ["-accessed"]
20
+ ordering = ("-accessed",)
21
21
 
22
- list_display = ["report", "username", "site", "accessed", "report_model"]
22
+ list_display = ("report", "username", "site", "accessed", "report_model")
23
23
 
24
- list_filter = ["accessed", "report_model", "username", "site"]
24
+ list_filter = ("accessed", "report_model", "username", "site")
25
25
 
26
- search_fields = ["report_model", "username"]
26
+ search_fields = ("report_model", "username")
27
27
 
28
- readonly_fields = ["report_model", "username", "site", "accessed"]
28
+ readonly_fields = ("report_model", "username", "site", "accessed")
29
29
 
30
30
  @admin.display(description="Report", ordering="report_model")
31
31
  def report(self, obj=None):
@@ -17,7 +17,7 @@ class QaReportLogSummaryAdmin(
17
17
  TemplatesModelAdminMixin,
18
18
  admin.ModelAdmin,
19
19
  ):
20
- ordering = ["-last_accessed"]
20
+ ordering = ("-last_accessed",)
21
21
 
22
22
  list_display = (
23
23
  "username",
@@ -18,15 +18,14 @@ class NoteForm(
18
18
  FormValidatorMixin,
19
19
  forms.ModelForm,
20
20
  ):
21
-
22
21
  report_datetime_field_attr = "report_datetime"
23
22
  form_validator_cls = NoteFormValidator
24
23
 
25
24
  class Meta:
26
25
  model = Note
27
26
  fields = "__all__"
28
- help_text = {"subject_identifier": "(read-only)", "name": "(read-only)"}
29
- widgets = {
27
+ help_text = {"subject_identifier": "(read-only)", "name": "(read-only)"} # noqa: RUF012
28
+ widgets = { # noqa: RUF012
30
29
  "report_model": forms.TextInput(attrs={"readonly": "readonly"}),
31
30
  "subject_identifier": forms.TextInput(attrs={"readonly": "readonly"}),
32
31
  "name": forms.TextInput(attrs={"readonly": "readonly"}),
@@ -17,7 +17,7 @@ class NoteStatusListFilter(SimpleListFilter):
17
17
  self.note_model_cls = model_admin.note_model_cls
18
18
  super().__init__(request, params, model, model_admin)
19
19
 
20
- def lookups(self, request, model_admin):
20
+ def lookups(self, request, model_admin): # noqa: ARG002
21
21
  status_dict = {tpl[0]: tpl[1] for tpl in self.note_model_status_choices}
22
22
  names = [(NEW, status_dict.get(NEW, "New"))]
23
23
  qs = (
@@ -27,7 +27,7 @@ class NoteStatusListFilter(SimpleListFilter):
27
27
  )
28
28
 
29
29
  for obj in qs:
30
- names.append((f"{obj.get('status')}", status_dict[obj.get("status")]))
30
+ names.append((f"{obj.get('status')}", status_dict[obj.get("status")])) # noqa: PERF401
31
31
  return tuple(names)
32
32
 
33
33
  @staticmethod
@@ -39,22 +39,26 @@ class NoteStatusListFilter(SimpleListFilter):
39
39
  )
40
40
  for obj in qs:
41
41
  return obj.get("report_model")
42
+ return ""
42
43
 
43
- def queryset(self, request, queryset):
44
- if self.value() and self.value() != "none":
45
- if report_model := self.report_model(queryset):
46
- if self.value() == NEW:
47
- qs = self.note_model_cls.objects.values("subject_identifier").filter(
48
- report_model=report_model
49
- )
50
- queryset = queryset.exclude(
51
- subject_identifier__in=[obj.get("subject_identifier") for obj in qs]
52
- )
53
- elif self.value() in [tpl[0] for tpl in self.note_model_status_choices]:
54
- qs = self.note_model_cls.objects.values("subject_identifier").filter(
55
- report_model=report_model, status=self.value()
56
- )
57
- queryset = queryset.filter(
58
- subject_identifier__in=[obj.get("subject_identifier") for obj in qs]
59
- )
44
+ def queryset(self, request, queryset): # noqa: ARG002
45
+ if (
46
+ self.value()
47
+ and self.value() != "none"
48
+ and (report_model := self.report_model(queryset))
49
+ ):
50
+ if self.value() == NEW:
51
+ qs = self.note_model_cls.objects.values("subject_identifier").filter(
52
+ report_model=report_model
53
+ )
54
+ queryset = queryset.exclude(
55
+ subject_identifier__in=[obj.get("subject_identifier") for obj in qs]
56
+ )
57
+ elif self.value() in [tpl[0] for tpl in self.note_model_status_choices]:
58
+ qs = self.note_model_cls.objects.values("subject_identifier").filter(
59
+ report_model=report_model, status=self.value()
60
+ )
61
+ queryset = queryset.filter(
62
+ subject_identifier__in=[obj.get("subject_identifier") for obj in qs]
63
+ )
60
64
  return queryset
@@ -32,7 +32,7 @@ class NoteModelAdminMixin(
32
32
  """A modeladmin mixin class for the Note model."""
33
33
 
34
34
  form = NoteForm
35
- ordering = ["site", "subject_identifier"]
35
+ ordering = ("site", "subject_identifier")
36
36
 
37
37
  note_template_name = "edc_qareports/qa_report_note.html"
38
38
 
@@ -52,26 +52,26 @@ class NoteModelAdminMixin(
52
52
  audit_fieldset_tuple,
53
53
  )
54
54
 
55
- list_display = [
55
+ list_display = (
56
56
  "dashboard",
57
57
  "subject_identifier",
58
58
  "report",
59
59
  "status",
60
60
  "report_note",
61
61
  "report_datetime",
62
- ]
62
+ )
63
63
 
64
- radio_fields = {"status": admin.VERTICAL}
64
+ radio_fields = {"status": admin.VERTICAL} # noqa: RUF012
65
65
 
66
- list_filter = [
66
+ list_filter = (
67
67
  "report_datetime",
68
68
  "status",
69
69
  "report_model",
70
70
  "user_created",
71
71
  "user_modified",
72
- ]
72
+ )
73
73
 
74
- search_fields = ["subject_identifier", "name"]
74
+ search_fields = ("subject_identifier", "name")
75
75
 
76
76
  @admin.display(description="Report", ordering="report_name")
77
77
  def report(self, obj=None):
@@ -23,9 +23,9 @@ class OnStudyMissingValuesModelAdminMixin(
23
23
  include_note_column: bool = True
24
24
  site_list_display_insert_pos: int = 2
25
25
  qa_report_list_display_insert_pos = 4
26
- ordering = ["site", "subject_identifier"]
26
+ ordering = ("site", "subject_identifier")
27
27
 
28
- list_display = [
28
+ list_display = (
29
29
  "dashboard",
30
30
  "render_button",
31
31
  "subject",
@@ -35,16 +35,16 @@ class OnStudyMissingValuesModelAdminMixin(
35
35
  "visit",
36
36
  "report_date",
37
37
  "created",
38
- ]
38
+ )
39
39
 
40
- list_filter = [
40
+ list_filter = (
41
41
  ScheduleStatusListFilter,
42
42
  "label",
43
43
  "visit_code",
44
44
  "report_datetime",
45
- ]
45
+ )
46
46
 
47
- search_fields = ["subject_identifier", "label"]
47
+ search_fields = ("subject_identifier", "label")
48
48
 
49
49
  @admin.display(description="Update")
50
50
  def render_button(self, obj=None):
@@ -64,7 +64,7 @@ class OnStudyMissingValuesModelAdminMixin(
64
64
  f"&appointment={self.related_visit(obj).appointment.id}"
65
65
  f"&requisition={obj.original_id}"
66
66
  )
67
- title = _(f"Add {crf_model_cls._meta.verbose_name}")
67
+ title = _("Add {}") % crf_model_cls._meta.verbose_name
68
68
  label = _("Add CRF")
69
69
  crf_button = render_to_string(
70
70
  "edc_qareports/columns/add_button.html",
@@ -80,7 +80,7 @@ class OnStudyMissingValuesModelAdminMixin(
80
80
  f"{url}?next={self.admin_site.name}:"
81
81
  f"{self.model._meta.label_lower.replace('.', '_')}_changelist"
82
82
  )
83
- title = _(f"Change {crf_model_cls._meta.verbose_name}")
83
+ title = _("Change {}") % crf_model_cls._meta.verbose_name
84
84
  label = _("Change CRF")
85
85
  crf_button = render_to_string(
86
86
  "edc_qareports/columns/change_button.html",
@@ -62,13 +62,9 @@ class QaReportModelAdminMixin:
62
62
  return tuple(list_filter)
63
63
 
64
64
  def get_note_model_obj_or_raise(self, obj=None):
65
- try:
66
- note_model_obj = self.note_model_cls.objects.get(
67
- report_model=obj.report_model, subject_identifier=obj.subject_identifier
68
- )
69
- except ObjectDoesNotExist:
70
- raise
71
- return note_model_obj
65
+ return self.note_model_cls.objects.get(
66
+ report_model=obj.report_model, subject_identifier=obj.subject_identifier
67
+ )
72
68
 
73
69
  @admin.display(description="Status")
74
70
  def status(self, obj) -> str: