clinicedc 2.0.28__py3-none-any.whl → 2.0.29__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 (95) hide show
  1. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/RECORD +95 -95
  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 +9 -11
  29. edc_consent/consent_definition.py +4 -1
  30. edc_model_admin/mixins/model_admin_form_instructions_mixin.py +9 -3
  31. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +7 -7
  32. edc_pharmacy/admin_mixin.py +1 -1
  33. edc_pharmacy/approve_prescription.py +10 -8
  34. edc_pharmacy/auth_objects.py +1 -1
  35. edc_pharmacy/exceptions.py +7 -7
  36. edc_pharmacy/settings.py +1 -1
  37. edc_pharmacy/views/add_to_storage_bin_view.py +22 -24
  38. edc_pharmacy/views/allocate_to_subject_view.py +10 -18
  39. edc_pharmacy/views/celery_task_status_view.py +1 -2
  40. edc_pharmacy/views/confirm_stock_from_instance_view.py +1 -1
  41. edc_pharmacy/views/confirm_stock_from_queryset_view.py +5 -8
  42. edc_pharmacy/views/dispense_view.py +1 -1
  43. edc_pharmacy/views/move_to_storage_bin_view.py +7 -3
  44. edc_pharmacy/views/prepare_and_review_stock_request_view.py +62 -70
  45. edc_pharmacy/views/print_labels_view.py +1 -1
  46. edc_pharmacy/views/transfer_stock_view.py +1 -1
  47. edc_prn/modelform_mixins.py +8 -9
  48. edc_prn/models.py +3 -1
  49. edc_prn/site_prn_forms.py +2 -2
  50. edc_prn/templatetags/edc_prn_extras.py +1 -1
  51. edc_protocol/middleware.py +1 -1
  52. edc_protocol/research_protocol_config.py +7 -5
  53. edc_protocol_incident/admin/protocol_deviation_violation_admin.py +1 -1
  54. edc_protocol_incident/form_validators/mixins.py +9 -6
  55. edc_protocol_incident/modeladmin_mixins.py +1 -1
  56. edc_pylabels/admin/label_configuration_admin.py +1 -1
  57. edc_pylabels/admin/label_specification_admin.py +1 -1
  58. edc_pylabels/auth_objects.py +1 -1
  59. edc_pylabels/site_label_configs.py +2 -2
  60. edc_qareports/admin/qa_report_log_admin.py +5 -5
  61. edc_qareports/admin/qa_report_log_summary_admin.py +1 -1
  62. edc_qareports/forms/note_form.py +2 -3
  63. edc_qareports/modeladmin_mixins/list_filters.py +23 -19
  64. edc_qareports/modeladmin_mixins/note_modeladmin_mixin.py +7 -7
  65. edc_qareports/modeladmin_mixins/on_study_missing_values_modeladmin_mixin.py +8 -8
  66. edc_qareports/modeladmin_mixins/qa_report_modeladmin_mixin.py +3 -7
  67. edc_qareports/sql_generator/crf_case.py +1 -1
  68. edc_qareports/sql_generator/crf_subquery.py +1 -1
  69. edc_qareports/sql_generator/requisition_subquery.py +1 -1
  70. edc_qareports/sql_generator/sql_view_generator.py +1 -1
  71. edc_qareports/sql_generator/subquery_from_dict.py +39 -39
  72. edc_qareports/utils.py +12 -13
  73. edc_randomization/model_mixins.py +1 -1
  74. edc_randomization/system_checks.py +1 -1
  75. edc_refusal/admin.py +4 -2
  76. edc_registration/modeladmin_mixins.py +18 -20
  77. edc_registration/modelform_mixins.py +2 -2
  78. edc_registration/models/signals.py +1 -1
  79. edc_registration/utils.py +1 -1
  80. edc_reportable/age_evaluator.py +4 -4
  81. edc_reportable/data/grading_data/daids_july_2017.py +3 -3
  82. edc_reportable/evaluator.py +15 -15
  83. edc_reportable/exceptions.py +4 -4
  84. edc_reportable/forms/reportables_form_validator_mixin.py +6 -2
  85. edc_reportable/management/commands/export_reportables.py +1 -1
  86. edc_reportable/models/grading_exception.py +1 -6
  87. edc_reportable/models/normal_data.py +3 -3
  88. edc_reportable/models/reference_range_collection.py +1 -6
  89. edc_reportable/utils/get_grade_for_value.py +15 -15
  90. edc_reportable/utils/get_normal_data_or_raise.py +14 -14
  91. edc_reportable/utils/in_normal_bounds_or_raise.py +6 -6
  92. edc_reportable/utils/load_data.py +1 -1
  93. edc_reportable/utils/update_grading_exceptions.py +5 -5
  94. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/WHEEL +0 -0
  95. {clinicedc-2.0.28.dist-info → clinicedc-2.0.29.dist-info}/licenses/LICENSE +0 -0
@@ -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:
@@ -36,5 +36,5 @@ class CrfCase:
36
36
  try:
37
37
  cursor.execute(self.sql)
38
38
  except OperationalError as e:
39
- raise CrfCaseError(f"{e}. See {self}.")
39
+ raise CrfCaseError(f"{e}. See {self}.") from e
40
40
  return cursor.fetchall()
@@ -59,5 +59,5 @@ class CrfSubquery:
59
59
  try:
60
60
  sql = self.template.substitute(**opts).replace(";", "")
61
61
  except KeyError as e:
62
- raise CrfSubqueryError(e)
62
+ raise CrfSubqueryError(e) from e
63
63
  return sql
@@ -27,7 +27,7 @@ class RequisitionSubquery(CrfSubquery):
27
27
  template: str = field(
28
28
  init=False,
29
29
  default=Template(
30
- "select req.subject_identifier, req.id as original_id, " # nosec B608
30
+ "select req.subject_identifier, req.id as original_id, " # nosec B608 # noqa: S608
31
31
  "req.subject_visit_id, req.report_datetime, req.site_id, v.visit_code, "
32
32
  "v.visit_code_sequence, "
33
33
  "v.schedule_name, req.modified, '${label_lower}' as label_lower, "
@@ -30,7 +30,7 @@ class SqlViewGenerator:
30
30
  self.footer = f") as A ORDER BY {self.order_by}"
31
31
 
32
32
  @staticmethod
33
- def transpile(sql: str, read: str | None = None, write: str = None) -> str:
33
+ def transpile(sql: str, read: str | None = None, write: str | None = None) -> str:
34
34
  read = read or "mysql"
35
35
  sql = sql.replace(";", "")
36
36
  return sqlglot.transpile(sql, read=read, write=write)[0]
@@ -1,39 +1,39 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- from .subquery import Subquery
6
-
7
- if TYPE_CHECKING:
8
- from .qa_case import QaCase
9
-
10
-
11
- def subquery_from_dict(
12
- cases: list[dict[str:str, str:str, str:str] | QaCase],
13
- as_list: bool | None = False,
14
- ) -> str | list:
15
- """Returns an SQL select statement as a union of the select
16
- statements of each case.
17
-
18
- args:
19
- cases = [{
20
- "label_lower": "my_app.hivhistory",
21
- "dbtable": "my_app_hivhistory",
22
- "field": "hiv_init_date",
23
- "label": "missing HIV initiation date",
24
- "list_tables": [(list_field, list_dbtable, alias), ...],
25
- }, ...]
26
-
27
- Note: `list_field` is the CRF id field, for example:
28
- left join <list_dbtable> as <alias> on crf.<list_field>=<alias>.id
29
- """
30
- subqueries = []
31
- for case in cases:
32
- try:
33
- subquery = case.sql
34
- except AttributeError:
35
- subquery = Subquery(**case).sql
36
- subqueries.append(subquery)
37
- if as_list:
38
- return subqueries
39
- return " UNION ".join(subqueries)
1
+ # from __future__ import annotations
2
+ #
3
+ # from typing import TYPE_CHECKING
4
+ #
5
+ # from .subquery import Subquery
6
+ #
7
+ # if TYPE_CHECKING:
8
+ # from .qa_case import QaCase
9
+ #
10
+ #
11
+ # def subquery_from_dict(
12
+ # cases: list[dict[str:str, str:str, str:str] | QaCase],
13
+ # as_list: bool | None = False,
14
+ # ) -> str | list:
15
+ # """Returns an SQL select statement as a union of the select
16
+ # statements of each case.
17
+ #
18
+ # args:
19
+ # cases = [{
20
+ # "label_lower": "my_app.hivhistory",
21
+ # "dbtable": "my_app_hivhistory",
22
+ # "field": "hiv_init_date",
23
+ # "label": "missing HIV initiation date",
24
+ # "list_tables": [(list_field, list_dbtable, alias), ...],
25
+ # }, ...]
26
+ #
27
+ # Note: `list_field` is the CRF id field, for example:
28
+ # left join <list_dbtable> as <alias> on crf.<list_field>=<alias>.id
29
+ # """
30
+ # subqueries = []
31
+ # for case in cases:
32
+ # try:
33
+ # subquery = case.sql
34
+ # except AttributeError:
35
+ # subquery = Subquery(**case).sql
36
+ # subqueries.append(subquery)
37
+ # if as_list:
38
+ # return subqueries
39
+ # return " UNION ".join(subqueries)
edc_qareports/utils.py CHANGED
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import sys
2
3
  from pathlib import Path
3
4
  from warnings import warn
@@ -27,10 +28,10 @@ def read_unmanaged_model_sql(
27
28
  parsed_sql = []
28
29
  with fullpath.open("r") as f:
29
30
  for line in f:
30
- line = line.split("#", maxsplit=1)[0]
31
- line = line.split("-- ", maxsplit=1)[0]
32
- line = line.replace("\n", "")
33
- line = line.strip()
31
+ line = line.split("#", maxsplit=1)[0] # noqa: PLW2901
32
+ line = line.split("-- ", maxsplit=1)[0] # noqa: PLW2901
33
+ line = line.replace("\n", "") # noqa: PLW2901
34
+ line = line.strip() # noqa: PLW2901
34
35
  if line:
35
36
  parsed_sql.append(line)
36
37
 
@@ -88,17 +89,15 @@ def recreate_db_view(model_cls, drop: bool | None = None, verbose: bool | None =
88
89
  except AttributeError as e:
89
90
  raise AttributeError(
90
91
  f"Is this model linked to a view? Declare model with `DBView`. Got {e}"
91
- )
92
+ ) from e
92
93
  else:
93
94
  sql = sql.replace(";", "")
94
95
  if verbose:
95
- print(f"create view {model_cls._meta.db_table} as {sql};")
96
+ sys.stdout.write(f"create view {model_cls._meta.db_table} as {sql};\n")
96
97
  with connection.cursor() as c:
97
98
  if drop:
98
- try:
99
+ with contextlib.suppress(OperationalError):
99
100
  c.execute(f"drop view {model_cls._meta.db_table};")
100
- except OperationalError:
101
- pass
102
101
  c.execute(f"create view {model_cls._meta.db_table} as {sql};")
103
102
  if verbose:
104
103
  sys.stdout.write(
@@ -107,14 +106,14 @@ def recreate_db_view(model_cls, drop: bool | None = None, verbose: bool | None =
107
106
 
108
107
 
109
108
  def recreate_dbview_for_all():
110
- from .model_mixins import QaReportModelMixin
109
+ from .model_mixins import QaReportModelMixin # noqa: PLC0415
111
110
 
112
111
  for model_cls in django_apps.get_models():
113
112
  if issubclass(model_cls, (QaReportModelMixin,)):
114
- print(model_cls)
113
+ sys.stdout.write(f"{model_cls}\n")
115
114
  try:
116
115
  model_cls.recreate_db_view()
117
116
  except AttributeError as e:
118
- print(e)
117
+ sys.stdout.write(f"{e}\n")
119
118
  except TypeError as e:
120
- print(e)
119
+ sys.stdout.write(f"{e}\n")
@@ -71,7 +71,7 @@ class RandomizationListModelMixin(models.Model):
71
71
  def save(self, *args, **kwargs):
72
72
  self.randomizer_name = self.randomizer_cls.name
73
73
  try:
74
- self.assignment_description
74
+ self.assignment_description # noqa: B018
75
75
  except RandomizationError as e:
76
76
  raise RandomizationListModelError(e) from e
77
77
  try: