clinicedc 2.0.26__py3-none-any.whl → 2.0.28__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.
- {clinicedc-2.0.26.dist-info → clinicedc-2.0.28.dist-info}/METADATA +1 -1
- {clinicedc-2.0.26.dist-info → clinicedc-2.0.28.dist-info}/RECORD +11 -11
- edc_consent/models/__init__.py +2 -2
- edc_consent/models/signals.py +32 -26
- edc_constants/choices.py +26 -0
- edc_constants/constants.py +10 -0
- edc_randomization/randomization_list_importer.py +10 -4
- edc_randomization/randomization_list_verifier.py +5 -3
- edc_visit_schedule/site_visit_schedules.py +8 -12
- {clinicedc-2.0.26.dist-info → clinicedc-2.0.28.dist-info}/WHEEL +0 -0
- {clinicedc-2.0.26.dist-info → clinicedc-2.0.28.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clinicedc
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.28
|
|
4
4
|
Summary: A clinical trials data management framework built on Django
|
|
5
5
|
Keywords: django,clinicedc,edc,clinical trials,research,data management,esource
|
|
6
6
|
Author: Erik van Widenfelt, Jonathan Willitts
|
|
@@ -593,9 +593,9 @@ edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_mixin.py,
|
|
|
593
593
|
edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py,sha256=Wwo3l-pdFlLkK8q50GkaCyPUXtuPJXODqYfb3HF1jDw,9613
|
|
594
594
|
edc_consent/modelform_mixins/consent_modelform_mixin/review_fields_modelform_mixin.py,sha256=HOiWpf8SnPaGMtRbKM6uAglbV1HmQWdzxSoyQW1ab2U,1922
|
|
595
595
|
edc_consent/modelform_mixins/requires_consent_modelform_mixin.py,sha256=-rQAmOvl1fx8-lEUB6M4V7tqaTqDRxtid002EWYPIxM,2340
|
|
596
|
-
edc_consent/models/__init__.py,sha256=
|
|
596
|
+
edc_consent/models/__init__.py,sha256=kTUrf6WlsKInX7jVuD3DyIqRW1OUaeSemflLLzWLV_I,278
|
|
597
597
|
edc_consent/models/edc_permissions.py,sha256=f9PWQ1ZFz4rKT7wFpfr8anQ7mV6sCdNaWNMimPLGae8,338
|
|
598
|
-
edc_consent/models/signals.py,sha256=
|
|
598
|
+
edc_consent/models/signals.py,sha256=kjYIlFTcm395_z4h3wlBkYbcxzAjgqsea3_ik5rm6CM,3320
|
|
599
599
|
edc_consent/navbars.py,sha256=Bqb2UfOCLL6yuT_fSvKYQymbBj7V6q9CwvmI-VdUmls,334
|
|
600
600
|
edc_consent/site_consents.py,sha256=jQYufDBievxoyOlC0Q1Llxv9xYqCEyk58Q1Fg_cu3mY,16882
|
|
601
601
|
edc_consent/stubs.py,sha256=ZXjNqT6nBHRFHCB5tCOzBC3ZdiiBR3IitygO3FldTZA,513
|
|
@@ -611,8 +611,8 @@ edc_consent/views/home_view.py,sha256=TRqEcysATqzVGTHPhn6HxPsWjIGAPDwYaCylIJOWM7
|
|
|
611
611
|
edc_consent/wsgi.py,sha256=IuY8oXnc033507PBykHhWuZxUDpg4MaMvTmVSM6uJ54,390
|
|
612
612
|
edc_constants/__init__.py,sha256=jHg-osFAN-UgMbnvV1MnQ0sD37lq0QisRbJ_oqrGUdw,84
|
|
613
613
|
edc_constants/apps.py,sha256=H3gCke2ogPgCL2sSD44Nb56ZBurei4uXWEhcUTdIlYI,318
|
|
614
|
-
edc_constants/choices.py,sha256=
|
|
615
|
-
edc_constants/constants.py,sha256=
|
|
614
|
+
edc_constants/choices.py,sha256=OvsfqZvb872tANzN0LMLgGLMkqaqRRb1FooXBcTr4cY,19638
|
|
615
|
+
edc_constants/constants.py,sha256=Utlax5PHmnKXe0DQebnz7aEwlE1KM9ItUEET6jPqgN0,5585
|
|
616
616
|
edc_constants/context_processor.py,sha256=JwfB03QXX9AFcVI_-ohdNVTGWpP2DDpH_t_kdiAe-7s,809
|
|
617
617
|
edc_constants/date_constants.py,sha256=5XrhZHz0caO1qghW4_r2slDMVdHsz6QG8OfSo2mMKSg,616
|
|
618
618
|
edc_constants/disease_constants.py,sha256=ZXzwomCaDMtrghHkAHdUUuNbZloIFn0lnG0-nZfdEvE,743
|
|
@@ -2794,8 +2794,8 @@ edc_randomization/model_mixins.py,sha256=BJe7eLxveTFNPIS7hz7796hSL0DFvTml03HmNih
|
|
|
2794
2794
|
edc_randomization/models/__init__.py,sha256=iaJ6FM7VVqLpp8M-OjVWjohp4ELdxtPXqbEiT3iN5Tw,94
|
|
2795
2795
|
edc_randomization/models/edc_permissions.py,sha256=f6P4zXxLQdTAbn2KnFlwfE86Lmzj7Ecp4JJ2F8mrwTc,286
|
|
2796
2796
|
edc_randomization/models/randomization_list.py,sha256=Hd5yUSZ5HBKhNzYdlbJufab8U2x3Dzw8n4WXnYzJxyc,253
|
|
2797
|
-
edc_randomization/randomization_list_importer.py,sha256=
|
|
2798
|
-
edc_randomization/randomization_list_verifier.py,sha256=
|
|
2797
|
+
edc_randomization/randomization_list_importer.py,sha256=FzL7-Iq9GJEXoi_ggGKvk7fApfL_oxcI7eJJUXyc4GM,13076
|
|
2798
|
+
edc_randomization/randomization_list_verifier.py,sha256=o-niIHR6OapiAXbGeLzW03PVz5DdYKOidJIcWJwCalM,7069
|
|
2799
2799
|
edc_randomization/randomizer.py,sha256=_LYZp7gmpOIkovCs7TfAt78wb_Kl4iV6I85YIxgQ5pg,12729
|
|
2800
2800
|
edc_randomization/randomizers.py,sha256=JvMDAnsgvRZkl50Bawm2iLsyw3bfWfGwBafn54K5g44,297
|
|
2801
2801
|
edc_randomization/site_randomizers.py,sha256=CcHRz_J6OlJ64-iNul_LOHM0ai6SbcX5AMDrFFMewDA,4390
|
|
@@ -3292,7 +3292,7 @@ edc_visit_schedule/schedule/schedule.py,sha256=ROUNin-k1oJVtx_wEXwlj5xrhTw3I_6Ve
|
|
|
3292
3292
|
edc_visit_schedule/schedule/visit_collection.py,sha256=9OJKrLtx-H0eL9oo0dsRqYGPICiAMqEF4xIhhlinx0A,2033
|
|
3293
3293
|
edc_visit_schedule/schedule/window.py,sha256=gsXW7z3P84h6kWX7e7CABmalyLGgbbIwe0Q6atIbyEI,5229
|
|
3294
3294
|
edc_visit_schedule/simple_model_validator.py,sha256=5lMyVrrlAy4HxLmAqM3he7D2ssCJoyjAWDWnFmJwRT0,789
|
|
3295
|
-
edc_visit_schedule/site_visit_schedules.py,sha256=
|
|
3295
|
+
edc_visit_schedule/site_visit_schedules.py,sha256=dtFDEWTXQWx1KTFJQQDh2Uv52Ht2Rq64QktkYTsGBIQ,12949
|
|
3296
3296
|
edc_visit_schedule/subject_schedule.py,sha256=gai8sQ9nek3KEu27GL656twm0zKP3I3g510effNdIT8,16552
|
|
3297
3297
|
edc_visit_schedule/system_checks.py,sha256=Gp5DXTThRCFXyZ3dlN2S8FJPz16weonpjedcy6XIIms,9300
|
|
3298
3298
|
edc_visit_schedule/templates/edc_visit_schedule/home.html,sha256=RqtGsq6-zXi43jU0iSv24-xsIXXHkuiHjJvF-yqDyjA,1112
|
|
@@ -3407,7 +3407,7 @@ edc_vitals/models/fields/waist_circumference.py,sha256=fZcHFDdEwWLjIVLktKrFCD9UU
|
|
|
3407
3407
|
edc_vitals/models/fields/weight.py,sha256=zo9_9e3Cpu0UqoRbWS-iDkcDo6fK80b1dDQy4x4MyxE,921
|
|
3408
3408
|
edc_vitals/utils.py,sha256=vXid44KUXxeaSyund_y5MNXc5DFJs052_PwUAjszE2k,1384
|
|
3409
3409
|
edc_vitals/validators.py,sha256=vNiElWMs0rRnHRNuVoPLRf0rW_C_0xcfUyep1Y_Si5s,156
|
|
3410
|
-
clinicedc-2.0.
|
|
3411
|
-
clinicedc-2.0.
|
|
3412
|
-
clinicedc-2.0.
|
|
3413
|
-
clinicedc-2.0.
|
|
3410
|
+
clinicedc-2.0.28.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
|
|
3411
|
+
clinicedc-2.0.28.dist-info/WHEEL,sha256=-neZj6nU9KAMg2CnCY6T3w8J53nx1kFGw_9HfoSzM60,79
|
|
3412
|
+
clinicedc-2.0.28.dist-info/METADATA,sha256=YUfHfAvlHlkygsCSkKKCoV_MMwqlVWaUKE72Gq2R6iA,15787
|
|
3413
|
+
clinicedc-2.0.28.dist-info/RECORD,,
|
edc_consent/models/__init__.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from .edc_permissions import EdcPermissions
|
|
2
2
|
from .signals import (
|
|
3
3
|
requires_consent_on_pre_save,
|
|
4
|
-
|
|
4
|
+
update_appointment_from_consentext_post_save,
|
|
5
5
|
)
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"EdcPermissions",
|
|
9
9
|
"requires_consent_on_pre_save",
|
|
10
|
-
|
|
10
|
+
"update_appointment_from_consentext_post_save",
|
|
11
11
|
]
|
edc_consent/models/signals.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import contextlib
|
|
2
|
+
|
|
3
|
+
from django.db.models.signals import post_save, pre_save
|
|
2
4
|
from django.dispatch import receiver
|
|
3
5
|
|
|
4
6
|
from edc_sites import site_sites
|
|
7
|
+
from edc_visit_schedule.exceptions import NotOnScheduleError
|
|
8
|
+
from edc_visit_schedule.site_visit_schedules import site_visit_schedules
|
|
9
|
+
from edc_visit_schedule.subject_schedule import SubjectSchedule
|
|
5
10
|
|
|
6
|
-
from ..model_mixins import RequiresConsentFieldsModelMixin
|
|
11
|
+
from ..model_mixins import ConsentExtensionModelMixin, RequiresConsentFieldsModelMixin
|
|
7
12
|
from ..site_consents import site_consents
|
|
8
13
|
|
|
9
14
|
|
|
@@ -50,27 +55,28 @@ def requires_consent_on_pre_save(instance, raw, using, update_fields, **kwargs):
|
|
|
50
55
|
instance.consent_model = consent_definition.model
|
|
51
56
|
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
@receiver(
|
|
59
|
+
post_save,
|
|
60
|
+
weak=False,
|
|
61
|
+
dispatch_uid="update_appointment_from_consentext_post_save",
|
|
62
|
+
)
|
|
63
|
+
def update_appointment_from_consentext_post_save(
|
|
64
|
+
sender, instance, raw, created, using, **kwargs
|
|
65
|
+
):
|
|
66
|
+
if (
|
|
67
|
+
not raw
|
|
68
|
+
and not kwargs.get("update_fields")
|
|
69
|
+
and isinstance(instance, (ConsentExtensionModelMixin,))
|
|
70
|
+
):
|
|
71
|
+
cdef = site_consents.get_consent_definition(
|
|
72
|
+
model=instance.subject_consent._meta.label_lower,
|
|
73
|
+
version=instance.subject_consent.version,
|
|
74
|
+
)
|
|
75
|
+
for visit_schedule, schedule in site_visit_schedules.get_by_consent_definition(cdef):
|
|
76
|
+
subject_schedule = SubjectSchedule(
|
|
77
|
+
instance.subject_consent.subject_identifier,
|
|
78
|
+
visit_schedule=visit_schedule,
|
|
79
|
+
schedule=schedule,
|
|
80
|
+
)
|
|
81
|
+
with contextlib.suppress(NotOnScheduleError):
|
|
82
|
+
subject_schedule.refresh_appointments()
|
edc_constants/choices.py
CHANGED
|
@@ -4,6 +4,7 @@ from .constants import (
|
|
|
4
4
|
ABNORMAL,
|
|
5
5
|
ABSENT,
|
|
6
6
|
AFTERNOON,
|
|
7
|
+
AGREE,
|
|
7
8
|
ALIVE,
|
|
8
9
|
ALWAYS,
|
|
9
10
|
ANYTIME,
|
|
@@ -11,8 +12,11 @@ from .constants import (
|
|
|
11
12
|
COMPLETE,
|
|
12
13
|
DEAD,
|
|
13
14
|
DECLINED,
|
|
15
|
+
DIFFICULT,
|
|
16
|
+
DISAGREE,
|
|
14
17
|
DONT_KNOW,
|
|
15
18
|
DWTA,
|
|
19
|
+
EASY,
|
|
16
20
|
EVENING,
|
|
17
21
|
FALSE,
|
|
18
22
|
FASTING,
|
|
@@ -26,6 +30,7 @@ from .constants import (
|
|
|
26
30
|
MORNING,
|
|
27
31
|
NAIVE,
|
|
28
32
|
NEG,
|
|
33
|
+
NEUTRAL,
|
|
29
34
|
NEVER,
|
|
30
35
|
NO,
|
|
31
36
|
NON_FASTING,
|
|
@@ -51,9 +56,13 @@ from .constants import (
|
|
|
51
56
|
REFUSED,
|
|
52
57
|
SMOKER,
|
|
53
58
|
SOMETIMES,
|
|
59
|
+
STRONGLY_AGREE,
|
|
60
|
+
STRONGLY_DISAGREE,
|
|
54
61
|
TBD,
|
|
55
62
|
TRUE,
|
|
56
63
|
UNKNOWN,
|
|
64
|
+
VERY_DIFFICULT,
|
|
65
|
+
VERY_EASY,
|
|
57
66
|
VERY_OFTEN,
|
|
58
67
|
WEEKDAYS,
|
|
59
68
|
WEEKENDS,
|
|
@@ -833,3 +842,20 @@ WHYNOPARTICIPATE_CHOICE = (
|
|
|
833
842
|
("OTHER", _("Other, specify:")),
|
|
834
843
|
("not_answering", _("Don't want to answer")),
|
|
835
844
|
)
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
DISAGREE_TO_AGREE_CHOICE = (
|
|
848
|
+
(STRONGLY_DISAGREE, _("Strongly disagree")),
|
|
849
|
+
(DISAGREE, _("disagree")),
|
|
850
|
+
(NEUTRAL, _("Neutral")),
|
|
851
|
+
(AGREE, _("Agree")),
|
|
852
|
+
(STRONGLY_AGREE, _("Strongly agree")),
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
DIFFICULT_TO_EASY_CHOICE = (
|
|
856
|
+
(VERY_DIFFICULT, _("Very difficult")),
|
|
857
|
+
(DIFFICULT, _("Difficult")),
|
|
858
|
+
(NEUTRAL, _("Neutral")),
|
|
859
|
+
(EASY, _("Easy")),
|
|
860
|
+
(VERY_EASY, _("Very easy")),
|
|
861
|
+
)
|
edc_constants/constants.py
CHANGED
|
@@ -8,6 +8,7 @@ ABNORMAL = "ABNORMAL"
|
|
|
8
8
|
ABSENT = "absent"
|
|
9
9
|
ADDITIONAL = True
|
|
10
10
|
AFTERNOON = "afternoon"
|
|
11
|
+
AGREE = "agree"
|
|
11
12
|
ALIVE = "alive"
|
|
12
13
|
ALWAYS = "always"
|
|
13
14
|
ANONYMOUS = "anonymous"
|
|
@@ -40,6 +41,7 @@ DEFAULTER = "defaulter"
|
|
|
40
41
|
DELETE = "DELETE"
|
|
41
42
|
DELIVERY = "delivery"
|
|
42
43
|
DIABETES = "diabetes"
|
|
44
|
+
DISAGREE = "disagree"
|
|
43
45
|
DIVORCED = "divorced"
|
|
44
46
|
DM = "dm"
|
|
45
47
|
DONE = "done"
|
|
@@ -109,6 +111,7 @@ MULTI_MORBIDITY = "multi"
|
|
|
109
111
|
NAIVE = "NAIVE"
|
|
110
112
|
NCD = "NCD"
|
|
111
113
|
NEG = "NEG"
|
|
114
|
+
NEUTRAL = "neutral"
|
|
112
115
|
NEVER = "NEVER"
|
|
113
116
|
NEW = "New"
|
|
114
117
|
NEW_FIELD = "new_field"
|
|
@@ -192,6 +195,8 @@ SMOKER = "smoker"
|
|
|
192
195
|
SOMETIMES = "sometimes"
|
|
193
196
|
STEROIDS = "steroids"
|
|
194
197
|
STOPPED = "stopped"
|
|
198
|
+
STRONGLY_AGREE = "strongly_agree"
|
|
199
|
+
STRONGLY_DISAGREE = "strongly_disagree"
|
|
195
200
|
STUDY_DEFINED_TIMEPOINT = "study_defined_timepoint"
|
|
196
201
|
SUBJECT = "subject"
|
|
197
202
|
SYSTEMATIC = "systematic"
|
|
@@ -238,3 +243,8 @@ THURSDAY = "thursday"
|
|
|
238
243
|
FRIDAY = "friday"
|
|
239
244
|
SATURDAY = "saturday"
|
|
240
245
|
SUNDAY = "sunday"
|
|
246
|
+
|
|
247
|
+
VERY_DIFFICULT = "very_difficult"
|
|
248
|
+
DIFFICULT = "difficult"
|
|
249
|
+
EASY = "easy"
|
|
250
|
+
VERY_EASY = "very_easy"
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import csv
|
|
4
4
|
import sys
|
|
5
|
+
from itertools import islice
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from pprint import pprint
|
|
7
8
|
from uuid import uuid4
|
|
@@ -72,6 +73,7 @@ class RandomizationListImporter:
|
|
|
72
73
|
username: str | None = None,
|
|
73
74
|
revision: str | None = None,
|
|
74
75
|
sid_count_for_tests: int | None = None,
|
|
76
|
+
skip_verify: bool | None = None,
|
|
75
77
|
extra_csv_fieldnames: tuple[str] | None = None,
|
|
76
78
|
**kwargs, # noqa: ARG002
|
|
77
79
|
):
|
|
@@ -84,6 +86,7 @@ class RandomizationListImporter:
|
|
|
84
86
|
self.revision = revision
|
|
85
87
|
self.user = username
|
|
86
88
|
self.sid_count_for_tests = sid_count_for_tests
|
|
89
|
+
self.skip_verify = skip_verify
|
|
87
90
|
self.randomizer_model_cls = randomizer_model_cls
|
|
88
91
|
self.randomizer_name = randomizer_name
|
|
89
92
|
self.assignment_map = assignment_map
|
|
@@ -120,8 +123,9 @@ class RandomizationListImporter:
|
|
|
120
123
|
)
|
|
121
124
|
)
|
|
122
125
|
rec_count = self._import_csv_to_model()
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
if not self.skip_verify:
|
|
127
|
+
self.verify_messages = self._verify_data(**kwargs)
|
|
128
|
+
self._summarize_results()
|
|
125
129
|
if self.verbose:
|
|
126
130
|
sys.stdout.write(
|
|
127
131
|
style.SUCCESS("\nDone.------------------------------------------------\n")
|
|
@@ -221,13 +225,15 @@ class RandomizationListImporter:
|
|
|
221
225
|
sid_count = len(self.get_sid_list())
|
|
222
226
|
with self.randomizationlist_path.open(mode="r") as f:
|
|
223
227
|
reader = csv.DictReader(f)
|
|
228
|
+
if self.sid_count_for_tests:
|
|
229
|
+
reader = islice(reader, self.sid_count_for_tests)
|
|
224
230
|
all_rows = [{k: v.strip() for k, v in row.items() if k} for row in reader]
|
|
225
231
|
sorted_rows = sorted(
|
|
226
232
|
all_rows, key=lambda row: (row.get("site_name", ""), row.get("sid", ""))
|
|
227
233
|
)
|
|
228
234
|
for row in tqdm(sorted_rows, total=sid_count):
|
|
229
|
-
if self.sid_count_for_tests and len(objs) == self.sid_count_for_tests:
|
|
230
|
-
|
|
235
|
+
# if self.sid_count_for_tests and len(objs) == self.sid_count_for_tests:
|
|
236
|
+
# break
|
|
231
237
|
try:
|
|
232
238
|
self.randomizer_model_cls.objects.get(sid=row["sid"])
|
|
233
239
|
except ObjectDoesNotExist:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
import sys
|
|
3
|
+
from itertools import islice
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
from django.core.exceptions import ObjectDoesNotExist
|
|
@@ -72,15 +73,16 @@ class RandomizationListVerifier:
|
|
|
72
73
|
|
|
73
74
|
def verify(self) -> str | None:
|
|
74
75
|
message = None
|
|
75
|
-
|
|
76
76
|
# read and sort from CSV file
|
|
77
77
|
with self.randomizationlist_path.open(mode="r") as f:
|
|
78
78
|
reader = csv.DictReader(f)
|
|
79
|
+
if self.sid_count_for_tests:
|
|
80
|
+
reader = islice(reader, self.sid_count_for_tests)
|
|
79
81
|
all_rows = [{k: v.strip() for k, v in row.items() if k} for row in reader]
|
|
80
82
|
sorted_rows = sorted(
|
|
81
|
-
all_rows,
|
|
83
|
+
all_rows,
|
|
84
|
+
key=lambda row: (row.get("site_name", ""), int(row.get("sid", 0))),
|
|
82
85
|
)
|
|
83
|
-
|
|
84
86
|
# compare sorted CSV length with DB
|
|
85
87
|
if len(sorted_rows) != self.randomizer_model_cls.objects.all().count():
|
|
86
88
|
expected_cnt = len(sorted_rows)
|
|
@@ -95,9 +95,11 @@ class SiteVisitSchedules:
|
|
|
95
95
|
def get_by_consent_definition(
|
|
96
96
|
self,
|
|
97
97
|
cdef: ConsentDefinition,
|
|
98
|
-
) -> tuple[VisitSchedule, Schedule]:
|
|
99
|
-
"""Returns a visit schedule
|
|
100
|
-
|
|
98
|
+
) -> tuple[tuple[VisitSchedule, Schedule], ...]:
|
|
99
|
+
"""Returns a tuple of (visit schedule, schedule instances) that
|
|
100
|
+
match this cdef or raises.
|
|
101
|
+
"""
|
|
102
|
+
visit_schedules = []
|
|
101
103
|
attr = "consent_definitions"
|
|
102
104
|
for visit_schedule in self.visit_schedules.values():
|
|
103
105
|
for schedule in visit_schedule.schedules.values():
|
|
@@ -109,18 +111,12 @@ class SiteVisitSchedules:
|
|
|
109
111
|
) from e
|
|
110
112
|
for _cdef in consent_definitions:
|
|
111
113
|
if _cdef == cdef:
|
|
112
|
-
|
|
113
|
-
if not
|
|
114
|
+
visit_schedules.append((visit_schedule, schedule)) # noqa: PERF401
|
|
115
|
+
if not visit_schedules:
|
|
114
116
|
raise SiteVisitScheduleError(
|
|
115
117
|
f"Schedule not found. No schedule exists for {attr}={cdef}."
|
|
116
118
|
)
|
|
117
|
-
|
|
118
|
-
raise SiteVisitScheduleError(
|
|
119
|
-
f"Schedule is ambiguous. More than one schedule exists for "
|
|
120
|
-
f"{attr}={cdef}. Got {ret}"
|
|
121
|
-
)
|
|
122
|
-
visit_schedule, schedule = ret[0]
|
|
123
|
-
return visit_schedule, schedule
|
|
119
|
+
return tuple(visit_schedules)
|
|
124
120
|
|
|
125
121
|
def get_by_onschedule_model(self, onschedule_model: str) -> tuple[VisitSchedule, Schedule]:
|
|
126
122
|
"""Returns a tuple of (visit_schedule, schedule)
|
|
File without changes
|
|
File without changes
|