clinicedc 2.0.14__py3-none-any.whl → 2.0.16__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 (64) hide show
  1. {clinicedc-2.0.14.dist-info → clinicedc-2.0.16.dist-info}/METADATA +1 -1
  2. {clinicedc-2.0.14.dist-info → clinicedc-2.0.16.dist-info}/RECORD +64 -64
  3. edc_analytics/custom_tables/age.py +1 -0
  4. edc_analytics/custom_tables/art.py +1 -0
  5. edc_analytics/custom_tables/bmi.py +1 -0
  6. edc_analytics/custom_tables/bp.py +1 -0
  7. edc_analytics/custom_tables/fasting.py +1 -0
  8. edc_analytics/custom_tables/fbg.py +1 -0
  9. edc_analytics/custom_tables/fbg_ogtt.py +1 -0
  10. edc_analytics/custom_tables/hba1c.py +1 -0
  11. edc_analytics/custom_tables/ogtt.py +1 -0
  12. edc_analytics/custom_tables/waist.py +1 -0
  13. edc_analytics/row/row_definitions.py +1 -1
  14. edc_analytics/row/row_statistics_with_gender.py +1 -0
  15. edc_analytics/stata/get_stata_labels_from_model.py +5 -6
  16. edc_analytics/table.py +1 -0
  17. edc_appointment/creators/appointments_creator.py +5 -9
  18. edc_dx/diagnoses.py +2 -2
  19. edc_dx/form_validators/diagnosis_form_validator_mixin.py +1 -0
  20. edc_dx/form_validators/result_form_validator_mixin.py +14 -16
  21. edc_dx_review/form_mixins/clinical_review_baseline_required_form_mixin.py +1 -0
  22. edc_dx_review/medical_date.py +2 -1
  23. edc_dx_review/model_mixins/clinical_review_baseline_model_mixin.py +1 -0
  24. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_chol_model_mixin.py +1 -0
  25. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_dm_model_mixin.py +1 -0
  26. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_hiv_model_mixin.py +1 -0
  27. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_htn_model_mixin.py +1 -0
  28. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_model_mixin.py +1 -0
  29. edc_dx_review/model_mixins/dx_location_model_mixin.py +1 -0
  30. edc_dx_review/model_mixins/factory/baseline_review_model_mixin_factory.py +1 -0
  31. edc_dx_review/model_mixins/factory/calculate_date.py +1 -0
  32. edc_dx_review/model_mixins/factory/dx_initial_review_model_mixin_factory.py +2 -1
  33. edc_dx_review/model_mixins/factory/followup_review_model_mixin_factory.py +1 -0
  34. edc_dx_review/model_mixins/factory/rx_initial_review_model_mixin_factory.py +1 -0
  35. edc_dx_review/model_mixins/followup_review/followup_review_model_mixin.py +1 -0
  36. edc_dx_review/model_mixins/followup_review/hiv_followup_review_model_mixin.py +1 -0
  37. edc_dx_review/model_mixins/initial_review/chol_initial_review_model_mixin.py +1 -0
  38. edc_dx_review/model_mixins/initial_review/hiv_initial_model_mixins.py +1 -0
  39. edc_dx_review/model_mixins/initial_review/ncd_initial_review_model_mixin.py +1 -0
  40. edc_dx_review/radio_fields.py +3 -3
  41. edc_dx_review/utils.py +2 -1
  42. edc_form_describer/form_describer.py +13 -8
  43. edc_form_describer/forms_reference.py +24 -25
  44. edc_form_describer/make_forms_reference.py +10 -12
  45. edc_form_describer/management/commands/make_forms_reference.py +8 -8
  46. edc_form_describer/markdown_writer.py +11 -10
  47. edc_randomization/randomizer.py +2 -5
  48. edc_randomization/utils.py +10 -0
  49. edc_visit_schedule/schedule/schedule.py +13 -13
  50. edc_visit_tracking/action_items.py +1 -2
  51. edc_visit_tracking/apps.py +1 -1
  52. edc_visit_tracking/context_processors.py +1 -2
  53. edc_visit_tracking/crf_date_validator.py +4 -4
  54. edc_visit_tracking/form_validators/visit_form_validator.py +51 -45
  55. edc_visit_tracking/form_validators/visit_missed_form_validator.py +6 -1
  56. edc_visit_tracking/model_mixins/utils.py +1 -1
  57. edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +4 -4
  58. edc_visit_tracking/modelform_mixins/utils.py +2 -2
  59. edc_visit_tracking/models/signals.py +1 -1
  60. edc_visit_tracking/typing_stubs.py +3 -3
  61. edc_visit_tracking/utils.py +1 -1
  62. edc_visit_tracking/visit_sequence.py +3 -4
  63. {clinicedc-2.0.14.dist-info → clinicedc-2.0.16.dist-info}/WHEEL +0 -0
  64. {clinicedc-2.0.14.dist-info → clinicedc-2.0.16.dist-info}/licenses/LICENSE +0 -0
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from datetime import date
4
4
 
5
5
  from django.db import models
6
+
6
7
  from edc_constants.choices import YES_NO
7
8
  from edc_constants.constants import NOT_APPLICABLE, YES
8
9
  from edc_dx import Diagnoses
@@ -36,7 +37,7 @@ def dx_initial_review_methods_model_mixin_factory():
36
37
 
37
38
  @property
38
39
  def diagnoses(self):
39
- subject_identifier = getattr(self, "subject_identifier")
40
+ subject_identifier = self.subject_identifier
40
41
  return Diagnoses(
41
42
  subject_identifier=subject_identifier,
42
43
  report_datetime=getattr(self, get_report_datetime_field_name()),
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from django.db import models
4
+
4
5
  from edc_constants.choices import YES_NO_NA
5
6
  from edc_constants.constants import CHOL, DM, HIV, HTN, NOT_APPLICABLE
6
7
  from edc_dx import get_diagnosis_labels
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from django.db import models
4
+
4
5
  from edc_constants.choices import YES_NO, YES_NO_NA
5
6
  from edc_constants.constants import NOT_APPLICABLE, YES
6
7
  from edc_model.models import DurationYMDField
@@ -1,4 +1,5 @@
1
1
  from django.db import models
2
+
2
3
  from edc_constants.choices import YES_NO_NA
3
4
  from edc_constants.constants import NOT_APPLICABLE
4
5
 
@@ -1,4 +1,5 @@
1
1
  from django.db import models
2
+
2
3
  from edc_constants.choices import YES_NO_NA
3
4
  from edc_constants.constants import NOT_APPLICABLE
4
5
 
@@ -1,4 +1,5 @@
1
1
  from django.db import models
2
+
2
3
  from edc_constants.choices import YES_NO
3
4
  from edc_constants.constants import NOT_APPLICABLE
4
5
 
@@ -1,5 +1,6 @@
1
1
  from django.core.validators import MaxValueValidator, MinValueValidator
2
2
  from django.db import models
3
+
3
4
  from edc_constants.choices import YES_NO, YES_NO_NA, YES_NO_PENDING_NA
4
5
  from edc_constants.constants import NOT_APPLICABLE, YES
5
6
  from edc_lab.choices import VL_QUANTIFIER_NA
@@ -1,4 +1,5 @@
1
1
  from django.db import models
2
+
2
3
  from edc_constants.choices import YES_NO
3
4
  from edc_constants.constants import YES
4
5
  from edc_model import models as edc_models
@@ -1,10 +1,10 @@
1
- from typing import Dict
2
1
 
3
2
  from django.contrib import admin
3
+
4
4
  from edc_dx import get_diagnosis_labels_prefixes
5
5
 
6
6
 
7
- def get_clinical_review_cond_radio_fields() -> Dict[str, int]:
7
+ def get_clinical_review_cond_radio_fields() -> dict[str, int]:
8
8
  radio_fields = {}
9
9
  for prefix in get_diagnosis_labels_prefixes():
10
10
  cond = prefix.lower()
@@ -17,7 +17,7 @@ def get_clinical_review_cond_radio_fields() -> Dict[str, int]:
17
17
  return radio_fields
18
18
 
19
19
 
20
- def get_clinical_review_baseline_cond_radio_fields() -> Dict[str, int]:
20
+ def get_clinical_review_baseline_cond_radio_fields() -> dict[str, int]:
21
21
  radio_fields = {}
22
22
  for prefix in get_diagnosis_labels_prefixes():
23
23
  cond = prefix.lower()
edc_dx_review/utils.py CHANGED
@@ -7,6 +7,7 @@ from django import forms
7
7
  from django.apps import apps as django_apps
8
8
  from django.conf import settings
9
9
  from django.core.exceptions import ObjectDoesNotExist
10
+
10
11
  from edc_constants.constants import HIV, YES
11
12
  from edc_model.utils import model_exists_or_raise
12
13
  from edc_visit_schedule.baseline import VisitScheduleBaselineError
@@ -78,7 +79,7 @@ def get_extra_attrs():
78
79
  "review": "review",
79
80
  }
80
81
  try:
81
- data = getattr(settings, "EDC_DX_REVIEW_EXTRA_ATTRS")
82
+ data = settings.EDC_DX_REVIEW_EXTRA_ATTRS
82
83
  except AttributeError:
83
84
  pass
84
85
  else:
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  import re
4
5
  import string
5
6
  import sys
6
- from datetime import datetime
7
7
  from math import floor
8
8
 
9
9
  from django.core.management.color import color_style
10
+ from django.utils import timezone
10
11
 
11
12
  from edc_fieldsets.fieldsets import Fieldsets
12
13
  from edc_model.constants import DEFAULT_BASE_FIELDS
@@ -57,14 +58,20 @@ class FormDescriber:
57
58
  self.markdown: list[str] = []
58
59
  add_timestamp = True if add_timestamp is None else add_timestamp
59
60
  self.anchor_prefix = anchor_prefix or self.anchor_prefix
60
- timestamp = datetime.today().strftime("%Y-%m-%d %H:%M")
61
+ timestamp = timezone.now().strftime("%Y-%m-%d %H:%M")
61
62
  self.level = level or self.level
62
63
  self.conditional_fieldset = None
63
64
  self.admin_cls = admin_cls
64
65
  try:
65
66
  self.model_cls = admin_cls.model
66
67
  except AttributeError:
67
- self.model_cls = admin_cls.form._meta.model
68
+ try:
69
+ self.model_cls = admin_cls.form._meta.model
70
+ except AttributeError as e:
71
+ raise FormDescriberError(
72
+ f"Unable to determine admin class model. Got {admin_cls}"
73
+ ) from e
74
+
68
75
  self.visit_code = visit_code
69
76
  self.models_fields = {fld.name: fld for fld in self.model_cls._meta.get_fields()}
70
77
 
@@ -115,7 +122,7 @@ class FormDescriber:
115
122
  def anchor(self):
116
123
  allow = string.ascii_letters + string.digits + "-"
117
124
  slug = self.verbose_name.lower().replace(" ", "-")
118
- slug = re.sub("[^%s]" % allow, "", slug)
125
+ slug = re.sub(f"[^{allow}]", "", slug)
119
126
  return f"{self.anchor_prefix}-{slug}"
120
127
 
121
128
  def describe(self):
@@ -135,7 +142,7 @@ class FormDescriber:
135
142
 
136
143
  for fieldset_name, fieldset in self.fieldsets:
137
144
  if fieldset_name not in ["Audit"]:
138
- fieldset_name = fieldset_name or "Main"
145
+ fieldset_name = fieldset_name or "Main" # noqa: PLW2901
139
146
  self.markdown.append(f"\n**Section: {fieldset_name}**")
140
147
  if fieldset.get("classes") != "collapse":
141
148
  for fname in fieldset.get("fields"):
@@ -172,10 +179,8 @@ class FormDescriber:
172
179
  self.markdown.append(f"* custom_prompt: *{self.custom_form_labels.get(fname)}*")
173
180
  self.markdown.append(f"- db_table: {self.model_cls._meta.db_table}")
174
181
  self.markdown.append(f"- column: {field_cls.name}")
175
- try:
182
+ with contextlib.suppress(AttributeError):
176
183
  self.markdown.append(f"- metadata: {field_cls.metadata}")
177
- except AttributeError:
178
- pass
179
184
  self.markdown.append(f"- type: {field_cls.get_internal_type()}")
180
185
  if field_cls.max_length:
181
186
  self.markdown.append(f"- length: {field_cls.max_length}")
@@ -1,8 +1,9 @@
1
- from datetime import datetime
2
1
  from importlib.metadata import version
2
+ from pathlib import Path
3
3
 
4
4
  from django.apps import apps as django_apps
5
5
  from django.conf import settings
6
+ from django.utils import timezone
6
7
 
7
8
  from .form_describer import FormDescriber
8
9
  from .markdown_writer import MarkdownWriter
@@ -36,24 +37,20 @@ class FormsReference:
36
37
  self.add_per_form_timestamp = (
37
38
  True if add_per_form_timestamp is None else add_per_form_timestamp
38
39
  )
39
- self.timestamp = datetime.today().strftime("%Y-%m-%d %H:%M")
40
+ self.timestamp = timezone.now().strftime("%Y-%m-%d %H:%M")
40
41
  for visit_schedule in self.visit_schedules:
41
42
  self.plans.update({visit_schedule.name: {}})
42
43
  for schedule in visit_schedule.schedules.values():
43
44
  for visit_code, visit in schedule.visits.items():
44
- crfs = []
45
- requisitions = []
46
- for c in visit.crfs:
47
- crfs.append(c.model)
48
- for r in visit.requisitions:
49
- requisitions.append(r.panel.name)
45
+ crfs = [c.model for c in visit.crfs]
46
+ requisitions = [r.panel.name for r in visit.requisitions]
50
47
  self.plans[visit_schedule.name].update(
51
48
  {visit_code: {"crfs": crfs, "requisitions": requisitions}}
52
49
  )
53
50
 
54
51
  def to_file(
55
52
  self,
56
- path: str | None = None,
53
+ path: Path | str | None = None,
57
54
  overwrite: bool | None = None,
58
55
  pad: int | None = None,
59
56
  ):
@@ -95,23 +92,25 @@ class FormsReference:
95
92
  for index, model in enumerate(documents.get("crfs")):
96
93
  model_cls = django_apps.get_model(model)
97
94
  admin_cls = self.admin_site._registry.get(model_cls)
98
- describer = self.describer_cls(
99
- admin_cls=admin_cls,
100
- include_hidden_fields=self.include_hidden_fields,
101
- visit_code=visit_code,
102
- level=self.h4,
103
- anchor_prefix=self.anchor_prefix,
104
- add_timestamp=self.add_per_form_timestamp,
105
- )
106
- describer.markdown.append("\n")
107
- anchor = f"{self.get_anchor(describer.anchor)}"
108
- toc.append(
109
- f'{index + 1}. <a href="#{anchor}">{describer.verbose_name}</a>'
110
- )
111
- markdown.extend(describer.markdown)
95
+ if admin_cls:
96
+ describer = self.describer_cls(
97
+ admin_cls=admin_cls,
98
+ include_hidden_fields=self.include_hidden_fields,
99
+ visit_code=visit_code,
100
+ level=self.h4,
101
+ anchor_prefix=self.anchor_prefix,
102
+ add_timestamp=self.add_per_form_timestamp,
103
+ )
104
+ describer.markdown.append("\n")
105
+ anchor = f"{self.get_anchor(describer.anchor)}"
106
+ toc.append(
107
+ f'{index + 1}. <a href="#{anchor}">{describer.verbose_name}</a>'
108
+ )
109
+ markdown.extend(describer.markdown)
112
110
  markdown.append(f"{self.h4} Requisitions\n")
113
- for panel_name in documents.get("requisitions"):
114
- markdown.append(f"* {panel_name}\n")
111
+ markdown.extend(
112
+ [f"* {panel_name}\n" for panel_name in documents.get("requisitions")]
113
+ )
115
114
  markdown = self.insert_toc(toc, markdown)
116
115
  markdown.insert(0, f"{self.h1} {self.title}")
117
116
  markdown.append(
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  import sys
5
4
  from importlib import import_module
6
5
 
@@ -16,11 +15,10 @@ style = color_style()
16
15
 
17
16
 
18
17
  def make_forms_reference(
19
- app_label: str = None,
20
- admin_site_name: str = None,
21
- visit_schedule_name: str = None,
22
- title: str = None,
23
- path: str | None = None,
18
+ app_label: str,
19
+ admin_site_name: str,
20
+ visit_schedule_name: str,
21
+ title: str | None = None,
24
22
  ):
25
23
  module = import_module(app_label)
26
24
  admin_site = getattr(module.admin_site, admin_site_name)
@@ -29,9 +27,9 @@ def make_forms_reference(
29
27
  sys.stdout.write(
30
28
  style.MIGRATE_HEADING(f"Refreshing CRF reference document for {app_label}\n")
31
29
  )
32
- doc_folder = os.path.join(settings.BASE_DIR, "docs")
33
- if not os.path.exists(doc_folder):
34
- os.mkdir(doc_folder)
30
+ doc_folder = settings.BASE_DIR / "docs"
31
+ if not doc_folder.exists():
32
+ doc_folder.mkdir()
35
33
 
36
34
  forms = FormsReference(
37
35
  visit_schedules=[visit_schedule],
@@ -40,8 +38,8 @@ def make_forms_reference(
40
38
  add_per_form_timestamp=False,
41
39
  )
42
40
 
43
- path = os.path.join(doc_folder, "forms_reference.md")
41
+ path = doc_folder / f"forms_reference_{app_label}.md"
44
42
  forms.to_file(path=path, overwrite=True)
45
43
 
46
- print(path)
47
- print("Done.")
44
+ sys.stdout.write(f"{path}\n")
45
+ sys.stdout.write("Done.\n")
@@ -17,16 +17,16 @@ style = color_style()
17
17
 
18
18
 
19
19
  def update_forms_reference(
20
- app_label: str = None,
21
- admin_site_name: str = None,
22
- visit_schedule_name: str = None,
23
- title: str = None,
20
+ app_label: str,
21
+ admin_site_name: str,
22
+ visit_schedule_name: str,
23
+ title: str | None = None,
24
24
  filename: str | None = None,
25
25
  doc_folder: str | None = None,
26
26
  ):
27
27
  module = import_module(app_label)
28
28
  default_doc_folder = Path(settings.BASE_DIR / "docs")
29
- filename = filename or "forms_reference.md"
29
+ filename = filename or f"forms_reference_{app_label}.md"
30
30
  admin_site = getattr(module.admin_site, admin_site_name)
31
31
  visit_schedule = site_visit_schedules.get_visit_schedule(visit_schedule_name)
32
32
  title = title or _("%(title_app)s Forms Reference") % dict(title_app=app_label.upper())
@@ -47,8 +47,8 @@ def update_forms_reference(
47
47
  path = doc_folder / filename
48
48
  forms.to_file(path=path, overwrite=True)
49
49
 
50
- print(path)
51
- print("Done.")
50
+ sys.stdout.write(f"{path}\n")
51
+ sys.stdout.write("Done\n")
52
52
 
53
53
 
54
54
  class Command(BaseCommand):
@@ -85,7 +85,7 @@ class Command(BaseCommand):
85
85
  default=None,
86
86
  )
87
87
 
88
- def handle(self, *args, **options):
88
+ def handle(self, *args, **options): # noqa: ARG002
89
89
  app_label = options["app_label"]
90
90
  admin_site_name = options["admin_site_name"]
91
91
  visit_schedule_name = options["visit_schedule_name"]
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
- from datetime import datetime
3
+ from pathlib import Path
4
+
5
+ from django.utils import timezone
5
6
 
6
7
 
7
8
  class MarkdownWriter:
@@ -11,23 +12,23 @@ class MarkdownWriter:
11
12
  @staticmethod
12
13
  def get_path(path: str | None = None, overwrite: bool | None = None) -> str:
13
14
  if not path:
14
- timestamp = datetime.today().strftime("%Y%m%d%H%M")
15
+ timestamp = timezone.now().strftime("%Y%m%d%H%M")
15
16
  path = f"forms_{timestamp}.md"
16
- if os.path.exists(path):
17
+ if Path(path).exists():
17
18
  if overwrite:
18
- os.remove(path)
19
+ Path(path).unlink()
19
20
  else:
20
21
  raise FileExistsError(f"File exists. Got '{path}'")
21
22
  return path
22
23
 
23
24
  @staticmethod
24
- def to_markdown(markdown: list[str] = None) -> str:
25
+ def to_markdown(markdown: list[str]) -> str:
25
26
  """Returns the markdown as a text string."""
26
27
  return "\n".join(markdown)
27
28
 
28
29
  def to_file(
29
30
  self,
30
- markdown: list[str] = None,
31
+ markdown: list[str],
31
32
  pad: int | None = None,
32
33
  append: bool | None = None,
33
34
  prepend: bool | None = None,
@@ -42,9 +43,9 @@ class MarkdownWriter:
42
43
  else:
43
44
  self._write(markdown)
44
45
 
45
- def _write(self, markdown: str = None, mode: str | None = None) -> None:
46
+ def _write(self, markdown: str, mode: str | None = None) -> None:
46
47
  mode = mode or "w"
47
- with open(self.path, mode) as f:
48
+ with Path(self.path).open(mode) as f:
48
49
  f.write(markdown)
49
50
 
50
51
  def _append(self, markdown) -> None:
@@ -53,7 +54,7 @@ class MarkdownWriter:
53
54
 
54
55
  def _prepend(self, markdown=None) -> None:
55
56
  mode = "r+"
56
- with open(self.path, mode) as f:
57
+ with Path(self.path).open(mode) as f:
57
58
  content = f.read()
58
59
  f.seek(0, 0)
59
60
  f.write(markdown + "\n" + content)
@@ -22,6 +22,7 @@ from .randomization_list_importer import (
22
22
  RandomizationListAlreadyImported,
23
23
  RandomizationListImporter,
24
24
  )
25
+ from .utils import get_randomization_list_path
25
26
 
26
27
  if TYPE_CHECKING:
27
28
  from edc_registration.models import RegisteredSubject
@@ -99,11 +100,7 @@ class Randomizer:
99
100
  DEFAULT_ASSIGNMENT_DESCRIPTION_MAP,
100
101
  )
101
102
  filename: str = "randomization_list.csv"
102
- randomizationlist_folder: Path | str = getattr(
103
- settings,
104
- "EDC_RANDOMIZATION_LIST_PATH",
105
- Path(settings.BASE_DIR).expanduser() / ".etc",
106
- )
103
+ randomizationlist_folder: Path | str = get_randomization_list_path()
107
104
  extra_csv_fieldnames: list[str] | None = None
108
105
  trial_is_blinded: bool = True
109
106
  importer_cls: Any = RandomizationListImporter
@@ -25,6 +25,16 @@ class SubjectNotRandomization(Exception): # noqa: N818
25
25
  pass
26
26
 
27
27
 
28
+ def get_randomization_list_path() -> Path:
29
+ return Path(
30
+ getattr(
31
+ settings,
32
+ "EDC_RANDOMIZATION_LIST_PATH",
33
+ settings.ETC_DIR,
34
+ )
35
+ ).expanduser()
36
+
37
+
28
38
  def get_assignment_for_subject(
29
39
  subject_identifier: str,
30
40
  randomizer_name: str,
@@ -45,7 +45,7 @@ class ScheduleNameError(Exception):
45
45
  pass
46
46
 
47
47
 
48
- class AlreadyRegisteredVisit(Exception):
48
+ class AlreadyRegisteredVisit(Exception): # noqa: N818
49
49
  pass
50
50
 
51
51
 
@@ -69,15 +69,15 @@ class Schedule:
69
69
 
70
70
  def __init__(
71
71
  self,
72
- name=None,
73
- verbose_name: str = None,
74
- onschedule_model: str = None,
75
- offschedule_model: str = None,
76
- loss_to_followup_model: str = None,
77
- appointment_model: str | None = None,
78
- history_model: str | None = None,
72
+ name: str,
73
+ onschedule_model: str,
74
+ offschedule_model: str,
79
75
  consent_definitions: list[ConsentDefinition] | ConsentDefinition = None,
76
+ loss_to_followup_model: str | None = None,
77
+ appointment_model: str | None = None,
80
78
  offstudymedication_model: str | None = None,
79
+ history_model: str | None = None,
80
+ verbose_name: str | None = None,
81
81
  sequence: str | None = None,
82
82
  base_timepoint: float | Decimal | None = None,
83
83
  ):
@@ -146,10 +146,10 @@ class Schedule:
146
146
 
147
147
  def visits_for_subject(
148
148
  self,
149
- subject_identifier: str = None,
150
- report_datetime: datetime = None,
151
- site_id: int = None,
152
- consent_definition: ConsentDefinition = None,
149
+ subject_identifier: str,
150
+ report_datetime: datetime,
151
+ site_id: int | None = None,
152
+ consent_definition: ConsentDefinition | None = None,
153
153
  ) -> VisitCollection:
154
154
  """Returns a deep copy of visits collection filtered for a
155
155
  given consented subject.
@@ -352,7 +352,7 @@ class Schedule:
352
352
 
353
353
  def get_consent_definition(
354
354
  self,
355
- report_datetime: datetime = None,
355
+ report_datetime: datetime,
356
356
  site: SingleSite = None,
357
357
  consent_definition: ConsentDefinition = None,
358
358
  ) -> ConsentDefinition:
@@ -26,12 +26,11 @@ class VisitMissedAction(ActionWithNotification):
26
26
 
27
27
  def get_next_actions(self) -> list[Action]:
28
28
  next_actions: list[Action] = []
29
- next_actions = self.append_to_next_if_required(
29
+ return self.append_to_next_if_required(
30
30
  next_actions=next_actions,
31
31
  action_name=self.get_loss_to_followup_action_name(),
32
32
  required=self.is_ltfu(),
33
33
  )
34
- return next_actions
35
34
 
36
35
 
37
36
  class MissedVisitAction(VisitMissedAction):
@@ -12,7 +12,7 @@ class AppConfig(DjangoAppConfig):
12
12
  verbose_name = "Edc Visit Tracking"
13
13
  report_datetime_allowance: int = 30
14
14
  allow_crf_report_datetime_before_visit: bool = False
15
- reason_field: dict = {}
15
+ reason_field: dict = {} # noqa: RUF012
16
16
 
17
17
  def ready(self):
18
18
  register(context_processors_check)
@@ -2,11 +2,10 @@ from .constants import DEFERRED_VISIT, LOST_VISIT, MISSED_VISIT, SCHEDULED, UNSC
2
2
 
3
3
 
4
4
  def constants(request) -> dict:
5
- dct = dict(
5
+ return dict(
6
6
  DEFERRED_VISIT=DEFERRED_VISIT,
7
7
  LOST_VISIT=LOST_VISIT,
8
8
  MISSED_VISIT=MISSED_VISIT,
9
9
  SCHEDULED=SCHEDULED,
10
10
  UNSCHEDULED=UNSCHEDULED,
11
11
  )
12
- return dct
@@ -14,11 +14,11 @@ class CrfReportDateAllowanceError(Exception):
14
14
  pass
15
15
 
16
16
 
17
- class CrfReportDateBeforeStudyStart(Exception):
17
+ class CrfReportDateBeforeStudyStart(Exception): # noqa: N818
18
18
  pass
19
19
 
20
20
 
21
- class CrfReportDateIsFuture(Exception):
21
+ class CrfReportDateIsFuture(Exception): # noqa: N818
22
22
  pass
23
23
 
24
24
 
@@ -58,13 +58,13 @@ class CrfDateValidator:
58
58
  datetime_not_before_study_start(self.report_datetime)
59
59
  except ValidationError as e:
60
60
  message = e.message if hasattr(e, "message") else str(e)
61
- raise CrfReportDateBeforeStudyStart(message)
61
+ raise CrfReportDateBeforeStudyStart(message) from e
62
62
  # datetime_not_future
63
63
  try:
64
64
  datetime_not_future(self.report_datetime)
65
65
  except ValidationError as e:
66
66
  message = e.message if hasattr(e, "message") else str(e)
67
- raise CrfReportDateIsFuture(message)
67
+ raise CrfReportDateIsFuture(message) from e
68
68
 
69
69
  formatted_visit_datetime = self.visit_report_datetime.strftime(
70
70
  convert_php_dateformat(settings.SHORT_DATE_FORMAT)