Coverage for tasks/ceca.py: 46%
617 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/tasks/ceca.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
13 CamCOPS is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
18 CamCOPS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
26===============================================================================
28"""
30from typing import Any, Dict, List, Optional, Sequence
32import cardinal_pythonlib.rnc_web as ws
33from sqlalchemy.sql.schema import Column
34from sqlalchemy.sql.sqltypes import Boolean, Float, Integer, UnicodeText
36from camcops_server.cc_modules.cc_constants import CssClass
37from camcops_server.cc_modules.cc_html import (
38 answer,
39 get_yes_no,
40 get_yes_no_none,
41 subheading_spanning_two_columns,
42 tr,
43 tr_qa,
44)
45from camcops_server.cc_modules.cc_request import CamcopsRequest
46from camcops_server.cc_modules.cc_sqla_coltypes import (
47 BIT_CHECKER,
48 CamcopsColumn,
49 MIN_ZERO_CHECKER,
50 ONE_TO_FOUR_CHECKER,
51 ONE_TO_FIVE_CHECKER,
52 PermittedValueChecker,
53 ZERO_TO_TWO_CHECKER,
54 ZERO_TO_THREE_CHECKER,
55 ZERO_TO_FOUR_CHECKER,
56 ZERO_TO_FIVE_CHECKER,
57)
58from camcops_server.cc_modules.cc_summaryelement import SummaryElement
59from camcops_server.cc_modules.cc_task import (
60 get_from_dict,
61 Task,
62 TaskHasPatientMixin,
63)
66# =============================================================================
67# CECA-Q3
68# =============================================================================
70FREQUENCY_COMMENT = "Frequency (0 never - 3 often)"
73class CecaQ3(TaskHasPatientMixin, Task):
74 """
75 Server implementation of the CECA-Q3 task.
76 """
78 __tablename__ = "cecaq3"
79 shortname = "CECA-Q3"
81 # -------------------------------------------------------------------------
82 # Section 1(A)
83 # -------------------------------------------------------------------------
84 s1a_motherfigure_birthmother = CamcopsColumn(
85 "s1a_motherfigure_birthmother",
86 Boolean,
87 permitted_value_checker=BIT_CHECKER,
88 comment="Raised by, maternal, birth mother?",
89 )
90 s1a_motherfigure_stepmother = CamcopsColumn(
91 "s1a_motherfigure_stepmother",
92 Boolean,
93 permitted_value_checker=BIT_CHECKER,
94 comment="Raised by, maternal, stepmother?",
95 )
96 s1a_motherfigure_femalerelative = CamcopsColumn(
97 "s1a_motherfigure_femalerelative",
98 Boolean,
99 permitted_value_checker=BIT_CHECKER,
100 comment="Raised by, maternal, female relative?",
101 )
102 s1a_motherfigure_femalerelative_detail = Column(
103 "s1a_motherfigure_femalerelative_detail",
104 UnicodeText,
105 comment="Raised by, maternal, female relative, detail",
106 )
107 s1a_motherfigure_familyfriend = CamcopsColumn(
108 "s1a_motherfigure_familyfriend",
109 Boolean,
110 permitted_value_checker=BIT_CHECKER,
111 comment="Raised by, maternal, family friend?",
112 )
113 s1a_motherfigure_fostermother = CamcopsColumn(
114 "s1a_motherfigure_fostermother",
115 Boolean,
116 permitted_value_checker=BIT_CHECKER,
117 comment="Raised by, maternal, foster mother?",
118 )
119 s1a_motherfigure_adoptivemother = CamcopsColumn(
120 "s1a_motherfigure_adoptivemother",
121 Boolean,
122 permitted_value_checker=BIT_CHECKER,
123 comment="Raised by, maternal, adoptive mother?",
124 )
125 s1a_motherfigure_other = CamcopsColumn(
126 "s1a_motherfigure_other",
127 Boolean,
128 permitted_value_checker=BIT_CHECKER,
129 comment="Raised by, maternal, other?",
130 )
131 s1a_motherfigure_other_detail = Column(
132 "s1a_motherfigure_other_detail",
133 UnicodeText,
134 comment="Raised by, maternal, other, detail",
135 )
136 s1a_fatherfigure_birthfather = CamcopsColumn(
137 "s1a_fatherfigure_birthfather",
138 Boolean,
139 permitted_value_checker=BIT_CHECKER,
140 comment="Raised by, paternal, birth father?",
141 )
142 s1a_fatherfigure_stepfather = CamcopsColumn(
143 "s1a_fatherfigure_stepfather",
144 Boolean,
145 permitted_value_checker=BIT_CHECKER,
146 comment="Raised by, paternal, stepfather?",
147 )
148 s1a_fatherfigure_malerelative = CamcopsColumn(
149 "s1a_fatherfigure_malerelative",
150 Boolean,
151 permitted_value_checker=BIT_CHECKER,
152 comment="Raised by, paternal, male relative?",
153 )
154 s1a_fatherfigure_malerelative_detail = Column(
155 "s1a_fatherfigure_malerelative_detail",
156 UnicodeText,
157 comment="Raised by, paternal, male relative, detail",
158 )
159 s1a_fatherfigure_familyfriend = CamcopsColumn(
160 "s1a_fatherfigure_familyfriend",
161 Boolean,
162 permitted_value_checker=BIT_CHECKER,
163 comment="Raised by, paternal, family friend?",
164 )
165 s1a_fatherfigure_fosterfather = CamcopsColumn(
166 "s1a_fatherfigure_fosterfather",
167 Boolean,
168 permitted_value_checker=BIT_CHECKER,
169 comment="Raised by, paternal, foster father?",
170 )
171 s1a_fatherfigure_adoptivefather = CamcopsColumn(
172 "s1a_fatherfigure_adoptivefather",
173 Boolean,
174 permitted_value_checker=BIT_CHECKER,
175 comment="Raised by, paternal, adoptive father?",
176 )
177 s1a_fatherfigure_other = CamcopsColumn(
178 "s1a_fatherfigure_other",
179 Boolean,
180 permitted_value_checker=BIT_CHECKER,
181 comment="Raised by, paternal, other?",
182 )
183 s1a_fatherfigure_other_detail = Column(
184 "s1a_fatherfigure_other_detail",
185 UnicodeText,
186 comment="Raised by, paternal, other, detail",
187 )
189 # -------------------------------------------------------------------------
190 # Section 1(B)
191 # -------------------------------------------------------------------------
192 s1b_institution = CamcopsColumn(
193 "s1b_institution",
194 Boolean,
195 permitted_value_checker=BIT_CHECKER,
196 comment="In institution before 17?",
197 )
198 s1b_institution_time_years = CamcopsColumn(
199 "s1b_institution_time_years",
200 Float,
201 permitted_value_checker=MIN_ZERO_CHECKER,
202 comment="In institution, time (years)",
203 )
205 # -------------------------------------------------------------------------
206 # Section 1(C)
207 # -------------------------------------------------------------------------
208 s1c_mother_died = CamcopsColumn(
209 "s1c_mother_died",
210 Boolean,
211 permitted_value_checker=BIT_CHECKER,
212 comment="Mother died before 17?",
213 )
214 s1c_father_died = CamcopsColumn(
215 "s1c_father_died",
216 Boolean,
217 permitted_value_checker=BIT_CHECKER,
218 comment="Father died before 17?",
219 )
220 s1c_mother_died_subject_aged = CamcopsColumn(
221 "s1c_mother_died_subject_aged",
222 Float,
223 permitted_value_checker=MIN_ZERO_CHECKER,
224 comment="Age when mother died (years)",
225 )
226 s1c_father_died_subject_aged = CamcopsColumn(
227 "s1c_father_died_subject_aged",
228 Float,
229 permitted_value_checker=MIN_ZERO_CHECKER,
230 comment="Age when father died (years)",
231 )
232 s1c_separated_from_mother = CamcopsColumn(
233 "s1c_separated_from_mother",
234 Boolean,
235 permitted_value_checker=BIT_CHECKER,
236 comment="Separated from mother for >=1y before 17?",
237 )
238 s1c_separated_from_father = CamcopsColumn(
239 "s1c_separated_from_father",
240 Boolean,
241 permitted_value_checker=BIT_CHECKER,
242 comment="Separated from father for >=1y before 17?",
243 )
244 s1c_first_separated_from_mother_aged = CamcopsColumn(
245 "s1c_first_separated_from_mother_aged",
246 Float,
247 permitted_value_checker=MIN_ZERO_CHECKER,
248 comment="Maternal separation, age (years)",
249 )
250 s1c_first_separated_from_father_aged = CamcopsColumn(
251 "s1c_first_separated_from_father_aged",
252 Float,
253 permitted_value_checker=MIN_ZERO_CHECKER,
254 comment="Paternal separation, age (years)",
255 )
256 s1c_mother_how_long_first_separation_years = CamcopsColumn(
257 "s1c_mother_how_long_first_separation_years",
258 Float,
259 permitted_value_checker=MIN_ZERO_CHECKER,
260 comment="Maternal separation, how long first separation (y)",
261 )
262 s1c_father_how_long_first_separation_years = CamcopsColumn(
263 "s1c_father_how_long_first_separation_years",
264 Float,
265 permitted_value_checker=MIN_ZERO_CHECKER,
266 comment="Paternal separation, how long first separation (y)",
267 )
268 s1c_mother_separation_reason = CamcopsColumn(
269 "s1c_mother_separation_reason",
270 Integer,
271 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6),
272 comment="Maternal separation, reason "
273 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, "
274 "5 abandoned, 6 other)",
275 )
276 s1c_father_separation_reason = CamcopsColumn(
277 "s1c_father_separation_reason",
278 Integer,
279 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6),
280 comment="Paternal separation, reason "
281 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, "
282 "5 abandoned, 6 other)",
283 )
284 s1c_describe_experience = Column(
285 "s1c_describe_experience",
286 UnicodeText,
287 comment="Loss of/separation from parent, description",
288 )
290 # -------------------------------------------------------------------------
291 # Section 2(A)
292 # -------------------------------------------------------------------------
293 s2a_which_mother_figure = CamcopsColumn(
294 "s2a_which_mother_figure",
295 Integer,
296 permitted_value_checker=PermittedValueChecker(minimum=0, maximum=5),
297 comment="Mother figure, which one (0 none/skip, 1 birth mother, "
298 "2 stepmother, 3 other relative, 4 other non-relative, "
299 "5 other)",
300 )
301 s2a_which_mother_figure_other_detail = Column(
302 "s2a_which_mother_figure_other_detail",
303 UnicodeText,
304 comment="Mother figure, other, detail",
305 )
306 s2a_q1 = CamcopsColumn(
307 "s2a_q1",
308 Integer,
309 permitted_value_checker=ONE_TO_FIVE_CHECKER,
310 comment="Mother figure, difficult to please (1 no - 5 yes)",
311 )
312 s2a_q2 = CamcopsColumn(
313 "s2a_q2",
314 Integer,
315 permitted_value_checker=ONE_TO_FIVE_CHECKER,
316 comment="Mother figure, concerned re my worries (1 no - 5 yes)",
317 )
318 s2a_q3 = CamcopsColumn(
319 "s2a_q3",
320 Integer,
321 permitted_value_checker=ONE_TO_FIVE_CHECKER,
322 comment="Mother figure, interested re school (1 no - 5 yes)",
323 )
324 s2a_q4 = CamcopsColumn(
325 "s2a_q4",
326 Integer,
327 permitted_value_checker=ONE_TO_FIVE_CHECKER,
328 comment="Mother figure, made me feel unwanted (1 no - 5 yes)",
329 )
330 s2a_q5 = CamcopsColumn(
331 "s2a_q5",
332 Integer,
333 permitted_value_checker=ONE_TO_FIVE_CHECKER,
334 comment="Mother figure, better when upset (1 no - 5 yes)",
335 )
336 s2a_q6 = CamcopsColumn(
337 "s2a_q6",
338 Integer,
339 permitted_value_checker=ONE_TO_FIVE_CHECKER,
340 comment="Mother figure, critical (1 no - 5 yes)",
341 )
342 s2a_q7 = CamcopsColumn(
343 "s2a_q7",
344 Integer,
345 permitted_value_checker=ONE_TO_FIVE_CHECKER,
346 comment="Mother figure, unsupervised <10y (1 no - 5 yes)",
347 )
348 s2a_q8 = CamcopsColumn(
349 "s2a_q8",
350 Integer,
351 permitted_value_checker=ONE_TO_FIVE_CHECKER,
352 comment="Mother figure, time to talk (1 no - 5 yes)",
353 )
354 s2a_q9 = CamcopsColumn(
355 "s2a_q9",
356 Integer,
357 permitted_value_checker=ONE_TO_FIVE_CHECKER,
358 comment="Mother figure, nuisance (1 no - 5 yes)",
359 )
360 s2a_q10 = CamcopsColumn(
361 "s2a_q10",
362 Integer,
363 permitted_value_checker=ONE_TO_FIVE_CHECKER,
364 comment="Mother figure, picked on unfairly (1 no - 5 yes)",
365 )
366 s2a_q11 = CamcopsColumn(
367 "s2a_q11",
368 Integer,
369 permitted_value_checker=ONE_TO_FIVE_CHECKER,
370 comment="Mother figure, there if needed (1 no - 5 yes)",
371 )
372 s2a_q12 = CamcopsColumn(
373 "s2a_q12",
374 Integer,
375 permitted_value_checker=ONE_TO_FIVE_CHECKER,
376 comment="Mother figure, interested in friends (1 no - 5 yes)",
377 )
378 s2a_q13 = CamcopsColumn(
379 "s2a_q13",
380 Integer,
381 permitted_value_checker=ONE_TO_FIVE_CHECKER,
382 comment="Mother figure, concerned re whereabouts (1 no - 5 yes)",
383 )
384 s2a_q14 = CamcopsColumn(
385 "s2a_q14",
386 Integer,
387 permitted_value_checker=ONE_TO_FIVE_CHECKER,
388 comment="Mother figure, cared when ill (1 no - 5 yes)",
389 )
390 s2a_q15 = CamcopsColumn(
391 "s2a_q15",
392 Integer,
393 permitted_value_checker=ONE_TO_FIVE_CHECKER,
394 comment="Mother figure, neglected basic needs (1 no - 5 yes)",
395 )
396 s2a_q16 = CamcopsColumn(
397 "s2a_q16",
398 Integer,
399 permitted_value_checker=ONE_TO_FIVE_CHECKER,
400 comment="Mother figure, preferred siblings (1 no - 5 yes)",
401 )
402 s2a_extra = Column(
403 "s2a_extra", UnicodeText, comment="Mother figure, extra detail"
404 )
406 # -------------------------------------------------------------------------
407 # Section 2(B)
408 # -------------------------------------------------------------------------
409 s2b_q1 = CamcopsColumn(
410 "s2b_q1",
411 Integer,
412 permitted_value_checker=ZERO_TO_TWO_CHECKER,
413 comment="Mother figure, tease me (0 no - 2 yes)",
414 )
415 s2b_q2 = CamcopsColumn(
416 "s2b_q2",
417 Integer,
418 permitted_value_checker=ZERO_TO_TWO_CHECKER,
419 comment="Mother figure, made me keep secrets (0 no - 2 yes)",
420 )
421 s2b_q3 = CamcopsColumn(
422 "s2b_q3",
423 Integer,
424 permitted_value_checker=ZERO_TO_TWO_CHECKER,
425 comment="Mother figure, undermined confidence (0 no - 2 yes)",
426 )
427 s2b_q4 = CamcopsColumn(
428 "s2b_q4",
429 Integer,
430 permitted_value_checker=ZERO_TO_TWO_CHECKER,
431 comment="Mother figure, contradictory (0 no - 2 yes)",
432 )
433 s2b_q5 = CamcopsColumn(
434 "s2b_q5",
435 Integer,
436 permitted_value_checker=ZERO_TO_TWO_CHECKER,
437 comment="Mother figure, played on fears (0 no - 2 yes)",
438 )
439 s2b_q6 = CamcopsColumn(
440 "s2b_q6",
441 Integer,
442 permitted_value_checker=ZERO_TO_TWO_CHECKER,
443 comment="Mother figure, liked to see me suffer (0 no - 2 yes)",
444 )
445 s2b_q7 = CamcopsColumn(
446 "s2b_q7",
447 Integer,
448 permitted_value_checker=ZERO_TO_TWO_CHECKER,
449 comment="Mother figure, humiliated me (0 no - 2 yes)",
450 )
451 s2b_q8 = CamcopsColumn(
452 "s2b_q8",
453 Integer,
454 permitted_value_checker=ZERO_TO_TWO_CHECKER,
455 comment="Mother figure, shamed me before others (0 no - 2 yes)",
456 )
457 s2b_q9 = CamcopsColumn(
458 "s2b_q9",
459 Integer,
460 permitted_value_checker=ZERO_TO_TWO_CHECKER,
461 comment="Mother figure, rejecting (0 no - 2 yes)",
462 )
463 s2b_q10 = CamcopsColumn(
464 "s2b_q10",
465 Integer,
466 permitted_value_checker=ZERO_TO_TWO_CHECKER,
467 comment="Mother figure, took things I cherished (0 no - 2 yes)",
468 )
469 s2b_q11 = CamcopsColumn(
470 "s2b_q11",
471 Integer,
472 permitted_value_checker=ZERO_TO_TWO_CHECKER,
473 comment="Mother figure, eat disliked until sick (0 no - 2 yes)",
474 )
475 s2b_q12 = CamcopsColumn(
476 "s2b_q12",
477 Integer,
478 permitted_value_checker=ZERO_TO_TWO_CHECKER,
479 comment="Mother figure, deprived light/food/company (0 no - 2 yes)",
480 )
481 s2b_q13 = CamcopsColumn(
482 "s2b_q13",
483 Integer,
484 permitted_value_checker=ZERO_TO_TWO_CHECKER,
485 comment="Mother figure, wouldn't let me mix (0 no - 2 yes)",
486 )
487 s2b_q14 = CamcopsColumn(
488 "s2b_q14",
489 Integer,
490 permitted_value_checker=ZERO_TO_TWO_CHECKER,
491 comment="Mother figure, obedience through guilt (0 no - 2 yes)",
492 )
493 s2b_q15 = CamcopsColumn(
494 "s2b_q15",
495 Integer,
496 permitted_value_checker=ZERO_TO_TWO_CHECKER,
497 comment="Mother figure, threatened to hurt people dear to me "
498 "(0 no - 2 yes)",
499 )
500 s2b_q16 = CamcopsColumn(
501 "s2b_q16",
502 Integer,
503 permitted_value_checker=ZERO_TO_TWO_CHECKER,
504 comment="Mother figure, forced to break law (0 no - 2 yes)",
505 )
506 s2b_q17 = CamcopsColumn(
507 "s2b_q17",
508 Integer,
509 permitted_value_checker=ZERO_TO_TWO_CHECKER,
510 comment="Mother figure, said wanted me dead (0 no - 2 yes)",
511 )
512 s2b_q1_frequency = CamcopsColumn(
513 "s2b_q1_frequency",
514 Integer,
515 permitted_value_checker=ZERO_TO_THREE_CHECKER,
516 comment=FREQUENCY_COMMENT,
517 )
518 s2b_q2_frequency = CamcopsColumn(
519 "s2b_q2_frequency",
520 Integer,
521 permitted_value_checker=ZERO_TO_THREE_CHECKER,
522 comment=FREQUENCY_COMMENT,
523 )
524 s2b_q3_frequency = CamcopsColumn(
525 "s2b_q3_frequency",
526 Integer,
527 permitted_value_checker=ZERO_TO_THREE_CHECKER,
528 comment=FREQUENCY_COMMENT,
529 )
530 s2b_q4_frequency = CamcopsColumn(
531 "s2b_q4_frequency",
532 Integer,
533 permitted_value_checker=ZERO_TO_THREE_CHECKER,
534 comment=FREQUENCY_COMMENT,
535 )
536 s2b_q5_frequency = CamcopsColumn(
537 "s2b_q5_frequency",
538 Integer,
539 permitted_value_checker=ZERO_TO_THREE_CHECKER,
540 comment=FREQUENCY_COMMENT,
541 )
542 s2b_q6_frequency = CamcopsColumn(
543 "s2b_q6_frequency",
544 Integer,
545 permitted_value_checker=ZERO_TO_THREE_CHECKER,
546 comment=FREQUENCY_COMMENT,
547 )
548 s2b_q7_frequency = CamcopsColumn(
549 "s2b_q7_frequency",
550 Integer,
551 permitted_value_checker=ZERO_TO_THREE_CHECKER,
552 comment=FREQUENCY_COMMENT,
553 )
554 s2b_q8_frequency = CamcopsColumn(
555 "s2b_q8_frequency",
556 Integer,
557 permitted_value_checker=ZERO_TO_THREE_CHECKER,
558 comment=FREQUENCY_COMMENT,
559 )
560 s2b_q9_frequency = CamcopsColumn(
561 "s2b_q9_frequency",
562 Integer,
563 permitted_value_checker=ZERO_TO_THREE_CHECKER,
564 comment=FREQUENCY_COMMENT,
565 )
566 s2b_q10_frequency = CamcopsColumn(
567 "s2b_q10_frequency",
568 Integer,
569 permitted_value_checker=ZERO_TO_THREE_CHECKER,
570 comment=FREQUENCY_COMMENT,
571 )
572 s2b_q11_frequency = CamcopsColumn(
573 "s2b_q11_frequency",
574 Integer,
575 permitted_value_checker=ZERO_TO_THREE_CHECKER,
576 comment=FREQUENCY_COMMENT,
577 )
578 s2b_q12_frequency = CamcopsColumn(
579 "s2b_q12_frequency",
580 Integer,
581 permitted_value_checker=ZERO_TO_THREE_CHECKER,
582 comment=FREQUENCY_COMMENT,
583 )
584 s2b_q13_frequency = CamcopsColumn(
585 "s2b_q13_frequency",
586 Integer,
587 permitted_value_checker=ZERO_TO_THREE_CHECKER,
588 comment=FREQUENCY_COMMENT,
589 )
590 s2b_q14_frequency = CamcopsColumn(
591 "s2b_q14_frequency",
592 Integer,
593 permitted_value_checker=ZERO_TO_THREE_CHECKER,
594 comment=FREQUENCY_COMMENT,
595 )
596 s2b_q15_frequency = CamcopsColumn(
597 "s2b_q15_frequency",
598 Integer,
599 permitted_value_checker=ZERO_TO_THREE_CHECKER,
600 comment=FREQUENCY_COMMENT,
601 )
602 s2b_q16_frequency = CamcopsColumn(
603 "s2b_q16_frequency",
604 Integer,
605 permitted_value_checker=ZERO_TO_THREE_CHECKER,
606 comment=FREQUENCY_COMMENT,
607 )
608 s2b_q17_frequency = CamcopsColumn(
609 "s2b_q17_frequency",
610 Integer,
611 permitted_value_checker=ZERO_TO_THREE_CHECKER,
612 comment=FREQUENCY_COMMENT,
613 )
614 s2b_age_began = CamcopsColumn(
615 "s2b_age_began",
616 Float,
617 permitted_value_checker=MIN_ZERO_CHECKER,
618 comment="Age these experienced began (years)",
619 )
620 s2b_extra = Column("s2b_extra", UnicodeText, comment="Extra detail")
622 # -------------------------------------------------------------------------
623 # Section 3(A)
624 # -------------------------------------------------------------------------
625 s3a_which_father_figure = CamcopsColumn(
626 "s3a_which_father_figure",
627 Integer,
628 permitted_value_checker=ZERO_TO_FIVE_CHECKER,
629 comment="Father figure, which one (0 none/skip, 1 birth father, "
630 "2 stepfather, 3 other relative, 4 other non-relative, "
631 "5 other)",
632 )
633 s3a_which_father_figure_other_detail = Column(
634 "s3a_which_father_figure_other_detail",
635 UnicodeText,
636 comment="Father figure, other, detail",
637 )
638 s3a_q1 = CamcopsColumn(
639 "s3a_q1",
640 Integer,
641 permitted_value_checker=ONE_TO_FIVE_CHECKER,
642 comment="Father figure, difficult to please (1 no - 5 yes)",
643 )
644 s3a_q2 = CamcopsColumn(
645 "s3a_q2",
646 Integer,
647 permitted_value_checker=ONE_TO_FIVE_CHECKER,
648 comment="Father figure, concerned re my worries (1 no - 5 yes)",
649 )
650 s3a_q3 = CamcopsColumn(
651 "s3a_q3",
652 Integer,
653 permitted_value_checker=ONE_TO_FIVE_CHECKER,
654 comment="Father figure, interested re school (1 no - 5 yes)",
655 )
656 s3a_q4 = CamcopsColumn(
657 "s3a_q4",
658 Integer,
659 permitted_value_checker=ONE_TO_FIVE_CHECKER,
660 comment="Father figure, made me feel unwanted (1 no - 5 yes)",
661 )
662 s3a_q5 = CamcopsColumn(
663 "s3a_q5",
664 Integer,
665 permitted_value_checker=ONE_TO_FIVE_CHECKER,
666 comment="Father figure, better when upset (1 no - 5 yes)",
667 )
668 s3a_q6 = CamcopsColumn(
669 "s3a_q6",
670 Integer,
671 permitted_value_checker=ONE_TO_FIVE_CHECKER,
672 comment="Father figure, critical (1 no - 5 yes)",
673 )
674 s3a_q7 = CamcopsColumn(
675 "s3a_q7",
676 Integer,
677 permitted_value_checker=ONE_TO_FIVE_CHECKER,
678 comment="Father figure, unsupervised <10y (1 no - 5 yes)",
679 )
680 s3a_q8 = CamcopsColumn(
681 "s3a_q8",
682 Integer,
683 permitted_value_checker=ONE_TO_FIVE_CHECKER,
684 comment="Father figure, time to talk (1 no - 5 yes)",
685 )
686 s3a_q9 = CamcopsColumn(
687 "s3a_q9",
688 Integer,
689 permitted_value_checker=ONE_TO_FIVE_CHECKER,
690 comment="Father figure, nuisance (1 no - 5 yes)",
691 )
692 s3a_q10 = CamcopsColumn(
693 "s3a_q10",
694 Integer,
695 permitted_value_checker=ONE_TO_FIVE_CHECKER,
696 comment="Father figure, picked on unfairly (1 no - 5 yes)",
697 )
698 s3a_q11 = CamcopsColumn(
699 "s3a_q11",
700 Integer,
701 permitted_value_checker=ONE_TO_FIVE_CHECKER,
702 comment="Father figure, there if needed (1 no - 5 yes)",
703 )
704 s3a_q12 = CamcopsColumn(
705 "s3a_q12",
706 Integer,
707 permitted_value_checker=ONE_TO_FIVE_CHECKER,
708 comment="Father figure, interested in friends (1 no - 5 yes)",
709 )
710 s3a_q13 = CamcopsColumn(
711 "s3a_q13",
712 Integer,
713 permitted_value_checker=ONE_TO_FIVE_CHECKER,
714 comment="Father figure, concerned re whereabouts (1 no - 5 yes)",
715 )
716 s3a_q14 = CamcopsColumn(
717 "s3a_q14",
718 Integer,
719 permitted_value_checker=ONE_TO_FIVE_CHECKER,
720 comment="Father figure, cared when ill (1 no - 5 yes)",
721 )
722 s3a_q15 = CamcopsColumn(
723 "s3a_q15",
724 Integer,
725 permitted_value_checker=ONE_TO_FIVE_CHECKER,
726 comment="Father figure, neglected basic needs (1 no - 5 yes)",
727 )
728 s3a_q16 = CamcopsColumn(
729 "s3a_q16",
730 Integer,
731 permitted_value_checker=ONE_TO_FIVE_CHECKER,
732 comment="Father figure, preferred siblings (1 no - 5 yes)",
733 )
734 s3a_extra = Column(
735 "s3a_extra", UnicodeText, comment="Father figure, extra detail"
736 )
738 # -------------------------------------------------------------------------
739 # Section 3(B)
740 # -------------------------------------------------------------------------
741 s3b_q1 = CamcopsColumn(
742 "s3b_q1",
743 Integer,
744 permitted_value_checker=ZERO_TO_TWO_CHECKER,
745 comment="Father figure, tease me (0 no - 2 yes)",
746 )
747 s3b_q2 = CamcopsColumn(
748 "s3b_q2",
749 Integer,
750 permitted_value_checker=ZERO_TO_TWO_CHECKER,
751 comment="Father figure, made me keep secrets (0 no - 2 yes)",
752 )
753 s3b_q3 = CamcopsColumn(
754 "s3b_q3",
755 Integer,
756 permitted_value_checker=ZERO_TO_TWO_CHECKER,
757 comment="Father figure, undermined confidence (0 no - 2 yes)",
758 )
759 s3b_q4 = CamcopsColumn(
760 "s3b_q4",
761 Integer,
762 permitted_value_checker=ZERO_TO_TWO_CHECKER,
763 comment="Father figure, contradictory (0 no - 2 yes)",
764 )
765 s3b_q5 = CamcopsColumn(
766 "s3b_q5",
767 Integer,
768 permitted_value_checker=ZERO_TO_TWO_CHECKER,
769 comment="Father figure, played on fears (0 no - 2 yes)",
770 )
771 s3b_q6 = CamcopsColumn(
772 "s3b_q6",
773 Integer,
774 permitted_value_checker=ZERO_TO_TWO_CHECKER,
775 comment="Father figure, liked to see me suffer (0 no - 2 yes)",
776 )
777 s3b_q7 = CamcopsColumn(
778 "s3b_q7",
779 Integer,
780 permitted_value_checker=ZERO_TO_TWO_CHECKER,
781 comment="Father figure, humiliated me (0 no - 2 yes)",
782 )
783 s3b_q8 = CamcopsColumn(
784 "s3b_q8",
785 Integer,
786 permitted_value_checker=ZERO_TO_TWO_CHECKER,
787 comment="Father figure, shamed me before others (0 no - 2 yes)",
788 )
789 s3b_q9 = CamcopsColumn(
790 "s3b_q9",
791 Integer,
792 permitted_value_checker=ZERO_TO_TWO_CHECKER,
793 comment="Father figure, rejecting (0 no - 2 yes)",
794 )
795 s3b_q10 = CamcopsColumn(
796 "s3b_q10",
797 Integer,
798 permitted_value_checker=ZERO_TO_TWO_CHECKER,
799 comment="Father figure, took things I cherished (0 no - 2 yes)",
800 )
801 s3b_q11 = CamcopsColumn(
802 "s3b_q11",
803 Integer,
804 permitted_value_checker=ZERO_TO_TWO_CHECKER,
805 comment="Father figure, eat disliked until sick (0 no - 2 yes)",
806 )
807 s3b_q12 = CamcopsColumn(
808 "s3b_q12",
809 Integer,
810 permitted_value_checker=ZERO_TO_TWO_CHECKER,
811 comment="Father figure, deprived light/food/company (0 no - 2 yes)",
812 )
813 s3b_q13 = CamcopsColumn(
814 "s3b_q13",
815 Integer,
816 permitted_value_checker=ZERO_TO_TWO_CHECKER,
817 comment="Father figure, wouldn't let me mix (0 no - 2 yes)",
818 )
819 s3b_q14 = CamcopsColumn(
820 "s3b_q14",
821 Integer,
822 permitted_value_checker=ZERO_TO_TWO_CHECKER,
823 comment="Father figure, obedience through guilt (0 no - 2 yes)",
824 )
825 s3b_q15 = CamcopsColumn(
826 "s3b_q15",
827 Integer,
828 permitted_value_checker=ZERO_TO_TWO_CHECKER,
829 comment="Father figure, threatened to hurt people dear to me "
830 "(0 no - 2 yes)",
831 )
832 s3b_q16 = CamcopsColumn(
833 "s3b_q16",
834 Integer,
835 permitted_value_checker=ZERO_TO_TWO_CHECKER,
836 comment="Father figure, forced to break law (0 no - 2 yes)",
837 )
838 s3b_q17 = CamcopsColumn(
839 "s3b_q17",
840 Integer,
841 permitted_value_checker=ZERO_TO_TWO_CHECKER,
842 comment="Father figure, said wanted me dead (0 no - 2 yes)",
843 )
844 s3b_q1_frequency = CamcopsColumn(
845 "s3b_q1_frequency",
846 Integer,
847 permitted_value_checker=ZERO_TO_THREE_CHECKER,
848 comment=FREQUENCY_COMMENT,
849 )
850 s3b_q2_frequency = CamcopsColumn(
851 "s3b_q2_frequency",
852 Integer,
853 permitted_value_checker=ZERO_TO_THREE_CHECKER,
854 comment=FREQUENCY_COMMENT,
855 )
856 s3b_q3_frequency = CamcopsColumn(
857 "s3b_q3_frequency",
858 Integer,
859 permitted_value_checker=ZERO_TO_THREE_CHECKER,
860 comment=FREQUENCY_COMMENT,
861 )
862 s3b_q4_frequency = CamcopsColumn(
863 "s3b_q4_frequency",
864 Integer,
865 permitted_value_checker=ZERO_TO_THREE_CHECKER,
866 comment=FREQUENCY_COMMENT,
867 )
868 s3b_q5_frequency = CamcopsColumn(
869 "s3b_q5_frequency",
870 Integer,
871 permitted_value_checker=ZERO_TO_THREE_CHECKER,
872 comment=FREQUENCY_COMMENT,
873 )
874 s3b_q6_frequency = CamcopsColumn(
875 "s3b_q6_frequency",
876 Integer,
877 permitted_value_checker=ZERO_TO_THREE_CHECKER,
878 comment=FREQUENCY_COMMENT,
879 )
880 s3b_q7_frequency = CamcopsColumn(
881 "s3b_q7_frequency",
882 Integer,
883 permitted_value_checker=ZERO_TO_THREE_CHECKER,
884 comment=FREQUENCY_COMMENT,
885 )
886 s3b_q8_frequency = CamcopsColumn(
887 "s3b_q8_frequency",
888 Integer,
889 permitted_value_checker=ZERO_TO_THREE_CHECKER,
890 comment=FREQUENCY_COMMENT,
891 )
892 s3b_q9_frequency = CamcopsColumn(
893 "s3b_q9_frequency",
894 Integer,
895 permitted_value_checker=ZERO_TO_THREE_CHECKER,
896 comment=FREQUENCY_COMMENT,
897 )
898 s3b_q10_frequency = CamcopsColumn(
899 "s3b_q10_frequency",
900 Integer,
901 permitted_value_checker=ZERO_TO_THREE_CHECKER,
902 comment=FREQUENCY_COMMENT,
903 )
904 s3b_q11_frequency = CamcopsColumn(
905 "s3b_q11_frequency",
906 Integer,
907 permitted_value_checker=ZERO_TO_THREE_CHECKER,
908 comment=FREQUENCY_COMMENT,
909 )
910 s3b_q12_frequency = CamcopsColumn(
911 "s3b_q12_frequency",
912 Integer,
913 permitted_value_checker=ZERO_TO_THREE_CHECKER,
914 comment=FREQUENCY_COMMENT,
915 )
916 s3b_q13_frequency = CamcopsColumn(
917 "s3b_q13_frequency",
918 Integer,
919 permitted_value_checker=ZERO_TO_THREE_CHECKER,
920 comment=FREQUENCY_COMMENT,
921 )
922 s3b_q14_frequency = CamcopsColumn(
923 "s3b_q14_frequency",
924 Integer,
925 permitted_value_checker=ZERO_TO_THREE_CHECKER,
926 comment=FREQUENCY_COMMENT,
927 )
928 s3b_q15_frequency = CamcopsColumn(
929 "s3b_q15_frequency",
930 Integer,
931 permitted_value_checker=ZERO_TO_THREE_CHECKER,
932 comment=FREQUENCY_COMMENT,
933 )
934 s3b_q16_frequency = CamcopsColumn(
935 "s3b_q16_frequency",
936 Integer,
937 permitted_value_checker=ZERO_TO_THREE_CHECKER,
938 comment=FREQUENCY_COMMENT,
939 )
940 s3b_q17_frequency = CamcopsColumn(
941 "s3b_q17_frequency",
942 Integer,
943 permitted_value_checker=ZERO_TO_THREE_CHECKER,
944 comment=FREQUENCY_COMMENT,
945 )
946 s3b_age_began = CamcopsColumn(
947 "s3b_age_began",
948 Float,
949 permitted_value_checker=MIN_ZERO_CHECKER,
950 comment="Age these experienced began (years)",
951 )
952 s3b_extra = Column("s3b_extra", UnicodeText, comment="Extra detail")
954 # -------------------------------------------------------------------------
955 # Section 3(C)
956 # -------------------------------------------------------------------------
957 s3c_q1 = CamcopsColumn(
958 "s3c_q1",
959 Integer,
960 permitted_value_checker=ONE_TO_FIVE_CHECKER,
961 comment="Responsibility (1 no - 5 yes)",
962 )
963 s3c_q2 = CamcopsColumn(
964 "s3c_q2",
965 Integer,
966 permitted_value_checker=ONE_TO_FIVE_CHECKER,
967 comment="Housework (1 no - 5 yes)",
968 )
969 s3c_q3 = CamcopsColumn(
970 "s3c_q3",
971 Integer,
972 permitted_value_checker=ONE_TO_FIVE_CHECKER,
973 comment="Look after young siblings (1 no - 5 yes)",
974 )
975 s3c_q4 = CamcopsColumn(
976 "s3c_q4",
977 Integer,
978 permitted_value_checker=ONE_TO_FIVE_CHECKER,
979 comment="Cooking/cleaning (1 no - 5 yes)",
980 )
981 s3c_q5 = CamcopsColumn(
982 "s3c_q5",
983 Integer,
984 permitted_value_checker=ONE_TO_FIVE_CHECKER,
985 comment="Miss school for domestic responsibilities (1 no - 5 yes)",
986 )
987 s3c_q6 = CamcopsColumn(
988 "s3c_q6",
989 Integer,
990 permitted_value_checker=ONE_TO_FIVE_CHECKER,
991 comment="Miss seeing friends for domestic responsibilities "
992 "(1 no - 5 yes)",
993 )
994 s3c_q7 = CamcopsColumn(
995 "s3c_q7",
996 Integer,
997 permitted_value_checker=ONE_TO_FIVE_CHECKER,
998 comment="Parents said they couldn't cope (1 no - 5 yes)",
999 )
1000 s3c_q8 = CamcopsColumn(
1001 "s3c_q8",
1002 Integer,
1003 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1004 comment="Parents looked to you for help (1 no - 5 yes)",
1005 )
1006 s3c_q9 = CamcopsColumn(
1007 "s3c_q9",
1008 Integer,
1009 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1010 comment="Parents coped if you were hurt/ill (1 no - 5 yes)",
1011 )
1012 s3c_q10 = CamcopsColumn(
1013 "s3c_q10",
1014 Integer,
1015 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1016 comment="Parents confided their problems (1 no - 5 yes)",
1017 )
1018 s3c_q11 = CamcopsColumn(
1019 "s3c_q11",
1020 Integer,
1021 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1022 comment="Parents relied on you for emotional support (1 no - 5 yes)",
1023 )
1024 s3c_q12 = CamcopsColumn(
1025 "s3c_q12",
1026 Integer,
1027 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1028 comment="Parents cried in front of you (1 no - 5 yes)",
1029 )
1030 s3c_q13 = CamcopsColumn(
1031 "s3c_q13",
1032 Integer,
1033 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1034 comment="Concerned/worried re parent (1 no - 5 yes)",
1035 )
1036 s3c_q14 = CamcopsColumn(
1037 "s3c_q14",
1038 Integer,
1039 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1040 comment="Tried to support/care for parent (1 no - 5 yes)",
1041 )
1042 s3c_q15 = CamcopsColumn(
1043 "s3c_q15",
1044 Integer,
1045 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1046 comment="Try to make parent smile when upset (1 no - 5 yes)",
1047 )
1048 s3c_q16 = CamcopsColumn(
1049 "s3c_q16",
1050 Integer,
1051 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1052 comment="Parents made you feel guilty for their sacrifices "
1053 "(1 no - 5 yes)",
1054 )
1055 s3c_q17 = CamcopsColumn(
1056 "s3c_q17",
1057 Integer,
1058 permitted_value_checker=ONE_TO_FIVE_CHECKER,
1059 comment="Had to keep secrets for parent (1 no - 5 yes)",
1060 )
1061 s3c_which_parent_cared_for = CamcopsColumn(
1062 "s3c_which_parent_cared_for",
1063 Integer,
1064 permitted_value_checker=ZERO_TO_FOUR_CHECKER,
1065 comment="Which parent did you have to provide care for (0 none, "
1066 "1 mother, 2 father, 3 both, 4 other)",
1067 )
1068 s3c_parent_mental_problem = CamcopsColumn(
1069 "s3c_parent_mental_problem",
1070 Integer,
1071 permitted_value_checker=ZERO_TO_TWO_CHECKER,
1072 comment="Parent/s had emotional/mental health problems (0 no - 2 yes)",
1073 )
1074 s3c_parent_physical_problem = CamcopsColumn(
1075 "s3c_parent_physical_problem",
1076 Integer,
1077 permitted_value_checker=ZERO_TO_TWO_CHECKER,
1078 comment="Parent/s had disability/physical illness (0 no - 2 yes)",
1079 )
1081 # -------------------------------------------------------------------------
1082 # Section 4(A)
1083 # -------------------------------------------------------------------------
1084 s4a_adultconfidant = CamcopsColumn(
1085 "s4a_adultconfidant",
1086 Boolean,
1087 permitted_value_checker=BIT_CHECKER,
1088 comment="Adult confidant?",
1089 )
1090 s4a_adultconfidant_mother = CamcopsColumn(
1091 "s4a_adultconfidant_mother",
1092 Boolean,
1093 permitted_value_checker=BIT_CHECKER,
1094 comment="Adult confidant, mother?",
1095 )
1096 s4a_adultconfidant_father = CamcopsColumn(
1097 "s4a_adultconfidant_father",
1098 Boolean,
1099 permitted_value_checker=BIT_CHECKER,
1100 comment="Adult confidant, father?",
1101 )
1102 s4a_adultconfidant_otherrelative = CamcopsColumn(
1103 "s4a_adultconfidant_otherrelative",
1104 Boolean,
1105 permitted_value_checker=BIT_CHECKER,
1106 comment="Adult confidant, other relative?",
1107 )
1108 s4a_adultconfidant_familyfriend = CamcopsColumn(
1109 "s4a_adultconfidant_familyfriend",
1110 Boolean,
1111 permitted_value_checker=BIT_CHECKER,
1112 comment="Adult confidant, family friend?",
1113 )
1114 s4a_adultconfidant_responsibleadult = CamcopsColumn(
1115 "s4a_adultconfidant_responsibleadult",
1116 Boolean,
1117 permitted_value_checker=BIT_CHECKER,
1118 comment="Adult confidant, teacher/vicar/etc.?",
1119 )
1120 s4a_adultconfidant_other = CamcopsColumn(
1121 "s4a_adultconfidant_other",
1122 Boolean,
1123 permitted_value_checker=BIT_CHECKER,
1124 comment="Adult confidant, other?",
1125 )
1126 s4a_adultconfidant_other_detail = Column(
1127 "s4a_adultconfidant_other_detail",
1128 UnicodeText,
1129 comment="Adult confidant, other, detail",
1130 )
1131 s4a_adultconfidant_additional = Column(
1132 "s4a_adultconfidant_additional",
1133 UnicodeText,
1134 comment="Adult confidant, additional notes",
1135 )
1137 # -------------------------------------------------------------------------
1138 # Section 4(B)
1139 # -------------------------------------------------------------------------
1140 s4b_childconfidant = CamcopsColumn(
1141 "s4b_childconfidant",
1142 Boolean,
1143 permitted_value_checker=BIT_CHECKER,
1144 comment="Child confidant?",
1145 )
1146 s4b_childconfidant_sister = CamcopsColumn(
1147 "s4b_childconfidant_sister",
1148 Boolean,
1149 permitted_value_checker=BIT_CHECKER,
1150 comment="Child confidant, sister?",
1151 )
1152 s4b_childconfidant_brother = CamcopsColumn(
1153 "s4b_childconfidant_brother",
1154 Boolean,
1155 permitted_value_checker=BIT_CHECKER,
1156 comment="Child confidant, brother?",
1157 )
1158 s4b_childconfidant_otherrelative = CamcopsColumn(
1159 "s4b_childconfidant_otherrelative",
1160 Boolean,
1161 permitted_value_checker=BIT_CHECKER,
1162 comment="Child confidant, other relative?",
1163 )
1164 s4b_childconfidant_closefriend = CamcopsColumn(
1165 "s4b_childconfidant_closefriend",
1166 Boolean,
1167 permitted_value_checker=BIT_CHECKER,
1168 comment="Child confidant, close friend?",
1169 )
1170 s4b_childconfidant_otherfriend = CamcopsColumn(
1171 "s4b_childconfidant_otherfriend",
1172 Boolean,
1173 permitted_value_checker=BIT_CHECKER,
1174 comment="Child confidant, other less close friend(s)?",
1175 )
1176 s4b_childconfidant_other = CamcopsColumn(
1177 "s4b_childconfidant_other",
1178 Boolean,
1179 permitted_value_checker=BIT_CHECKER,
1180 comment="Child confidant, other person?",
1181 )
1182 s4b_childconfidant_other_detail = Column(
1183 "s4b_childconfidant_other_detail",
1184 UnicodeText,
1185 comment="Child confidant, other person, detail",
1186 )
1187 s4b_childconfidant_additional = Column(
1188 "s4b_childconfidant_additional",
1189 UnicodeText,
1190 comment="Child confidant, additional notes",
1191 )
1193 # -------------------------------------------------------------------------
1194 # Section 4(C)
1195 # -------------------------------------------------------------------------
1196 s4c_closest_mother = CamcopsColumn(
1197 "s4c_closest_mother",
1198 Boolean,
1199 permitted_value_checker=BIT_CHECKER,
1200 comment="Two closest people include: mother?",
1201 )
1202 s4c_closest_father = CamcopsColumn(
1203 "s4c_closest_father",
1204 Boolean,
1205 permitted_value_checker=BIT_CHECKER,
1206 comment="Two closest people include: father?",
1207 )
1208 s4c_closest_sibling = CamcopsColumn(
1209 "s4c_closest_sibling",
1210 Boolean,
1211 permitted_value_checker=BIT_CHECKER,
1212 comment="Two closest people include: sibling?",
1213 )
1214 s4c_closest_otherrelative = CamcopsColumn(
1215 "s4c_closest_otherrelative",
1216 Boolean,
1217 permitted_value_checker=BIT_CHECKER,
1218 comment="Two closest people include: other relative?",
1219 )
1220 s4c_closest_adultfriend = CamcopsColumn(
1221 "s4c_closest_adultfriend",
1222 Boolean,
1223 permitted_value_checker=BIT_CHECKER,
1224 comment="Two closest people include: adult family friend?",
1225 )
1226 s4c_closest_childfriend = CamcopsColumn(
1227 "s4c_closest_childfriend",
1228 Boolean,
1229 permitted_value_checker=BIT_CHECKER,
1230 comment="Two closest people include: friend your age?",
1231 )
1232 s4c_closest_other = CamcopsColumn(
1233 "s4c_closest_other",
1234 Boolean,
1235 permitted_value_checker=BIT_CHECKER,
1236 comment="Two closest people include: other?",
1237 )
1238 s4c_closest_other_detail = Column(
1239 "s4c_closest_other_detail",
1240 UnicodeText,
1241 comment="Two closest people include: other, detail",
1242 )
1243 s4c_closest_additional = Column(
1244 "s4c_closest_additional",
1245 UnicodeText,
1246 comment="Two closest people include: additional notes",
1247 )
1249 # -------------------------------------------------------------------------
1250 # Section 5(C)
1251 # -------------------------------------------------------------------------
1252 s5c_physicalabuse = CamcopsColumn(
1253 "s5c_physicalabuse",
1254 Boolean,
1255 permitted_value_checker=BIT_CHECKER,
1256 comment="Physical abuse?",
1257 )
1258 s5c_abused_by_mother = CamcopsColumn(
1259 "s5c_abused_by_mother",
1260 Boolean,
1261 permitted_value_checker=BIT_CHECKER,
1262 comment="Physical abuse, by mother?",
1263 )
1264 s5c_abused_by_father = CamcopsColumn(
1265 "s5c_abused_by_father",
1266 Boolean,
1267 permitted_value_checker=BIT_CHECKER,
1268 comment="Physical abuse, by father?",
1269 )
1270 s5c_mother_abuse_age_began = CamcopsColumn(
1271 "s5c_mother_abuse_age_began",
1272 Float,
1273 comment="Physical abuse, by mother, age began (y)",
1274 )
1275 s5c_father_abuse_age_began = CamcopsColumn(
1276 "s5c_father_abuse_age_began",
1277 Float,
1278 comment="Physical abuse, by father, age began (y)",
1279 )
1280 s5c_mother_hit_more_than_once = CamcopsColumn(
1281 "s5c_mother_hit_more_than_once",
1282 Boolean,
1283 permitted_value_checker=BIT_CHECKER,
1284 comment="Physical abuse, by mother, hit on >1 occasion",
1285 )
1286 s5c_father_hit_more_than_once = CamcopsColumn(
1287 "s5c_father_hit_more_than_once",
1288 Boolean,
1289 permitted_value_checker=BIT_CHECKER,
1290 comment="Physical abuse, by father, hit on >1 occasion",
1291 )
1292 s5c_mother_hit_how = CamcopsColumn(
1293 "s5c_mother_hit_how",
1294 Integer,
1295 permitted_value_checker=ONE_TO_FOUR_CHECKER,
1296 comment="Physical abuse, by mother, hit how (1 belt/stick, "
1297 "2 punched/kicked, 3 hit with hand, 4 other)",
1298 )
1299 s5c_father_hit_how = CamcopsColumn(
1300 "s5c_father_hit_how",
1301 Integer,
1302 permitted_value_checker=ONE_TO_FOUR_CHECKER,
1303 comment="Physical abuse, by father, hit how (1 belt/stick, "
1304 "2 punched/kicked, 3 hit with hand, 4 other)",
1305 )
1306 s5c_mother_injured = CamcopsColumn(
1307 "s5c_mother_injured",
1308 Boolean,
1309 permitted_value_checker=BIT_CHECKER,
1310 comment="Physical abuse, by mother, injured?",
1311 )
1312 s5c_father_injured = CamcopsColumn(
1313 "s5c_father_injured",
1314 Boolean,
1315 permitted_value_checker=BIT_CHECKER,
1316 comment="Physical abuse, by father, injured?",
1317 )
1318 s5c_mother_out_of_control = CamcopsColumn(
1319 "s5c_mother_out_of_control",
1320 Boolean,
1321 permitted_value_checker=BIT_CHECKER,
1322 comment="Physical abuse, by mother, out of control?",
1323 )
1324 s5c_father_out_of_control = CamcopsColumn(
1325 "s5c_father_out_of_control",
1326 Boolean,
1327 permitted_value_checker=BIT_CHECKER,
1328 comment="Physical abuse, by father, out of control?",
1329 )
1330 s5c_parental_abuse_description = Column(
1331 "s5c_parental_abuse_description",
1332 UnicodeText,
1333 comment="Physical abuse, description",
1334 )
1335 s5c_abuse_by_nonparent = CamcopsColumn(
1336 "s5c_abuse_by_nonparent",
1337 Boolean,
1338 permitted_value_checker=BIT_CHECKER,
1339 comment="Physical abuse, by anyone else in household?",
1340 )
1341 s5c_nonparent_abuse_description = Column(
1342 "s5c_nonparent_abuse_description",
1343 UnicodeText,
1344 comment="Physical abuse, nonparent, description",
1345 )
1347 # -------------------------------------------------------------------------
1348 # Section 6
1349 # -------------------------------------------------------------------------
1350 s6_any_unwanted_sexual_experience = CamcopsColumn(
1351 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave
1352 # TINYINT(1), which can store -128 to 128. Corrected to Integer.
1353 "s6_any_unwanted_sexual_experience",
1354 Integer,
1355 permitted_value_checker=ZERO_TO_TWO_CHECKER,
1356 comment="Any unwanted sexual experiences (0 no - 2 yes)",
1357 )
1358 s6_unwanted_intercourse = CamcopsColumn(
1359 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave
1360 # TINYINT(1), which can store -128 to 128. Corrected to Integer.
1361 "s6_unwanted_intercourse",
1362 Integer,
1363 permitted_value_checker=ZERO_TO_TWO_CHECKER,
1364 comment="Unwanted intercourse before 17yo (0 no - 2 yes)",
1365 )
1366 s6_upsetting_sexual_adult_authority = CamcopsColumn(
1367 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave
1368 # TINYINT(1), which can store -128 to 128. Corrected to Integer.
1369 "s6_upsetting_sexual_adult_authority",
1370 Integer,
1371 permitted_value_checker=ZERO_TO_TWO_CHECKER,
1372 comment="Upsetting sexual experiences under 17yo with "
1373 "related adult or someone in authority (0 no - 2 yes)",
1374 )
1375 s6_first_age = CamcopsColumn(
1376 "s6_first_age",
1377 Float,
1378 permitted_value_checker=MIN_ZERO_CHECKER,
1379 comment="Sexual abuse, first experience, age it began",
1380 )
1381 s6_other_age = CamcopsColumn(
1382 "s6_other_age",
1383 Float,
1384 permitted_value_checker=MIN_ZERO_CHECKER,
1385 comment="Sexual abuse, other experience, age it began",
1386 )
1387 s6_first_person_known = CamcopsColumn(
1388 "s6_first_person_known",
1389 Boolean,
1390 permitted_value_checker=BIT_CHECKER,
1391 comment="Sexual abuse, first experience, knew the person?",
1392 )
1393 s6_other_person_known = CamcopsColumn(
1394 "s6_other_person_known",
1395 Boolean,
1396 permitted_value_checker=BIT_CHECKER,
1397 comment="Sexual abuse, other experience, knew the person?",
1398 )
1399 s6_first_relative = CamcopsColumn(
1400 "s6_first_relative",
1401 Boolean,
1402 permitted_value_checker=BIT_CHECKER,
1403 comment="Sexual abuse, first experience, person was a relative?",
1404 )
1405 s6_other_relative = CamcopsColumn(
1406 "s6_other_relative",
1407 Boolean,
1408 permitted_value_checker=BIT_CHECKER,
1409 comment="Sexual abuse, other experience, person was a relative?",
1410 )
1411 s6_first_in_household = CamcopsColumn(
1412 "s6_first_in_household",
1413 Boolean,
1414 permitted_value_checker=BIT_CHECKER,
1415 comment="Sexual abuse, first experience, person lived in household?",
1416 )
1417 s6_other_in_household = CamcopsColumn(
1418 "s6_other_in_household",
1419 Boolean,
1420 permitted_value_checker=BIT_CHECKER,
1421 comment="Sexual abuse, other experience, person lived in household?",
1422 )
1423 s6_first_more_than_once = CamcopsColumn(
1424 "s6_first_more_than_once",
1425 Boolean,
1426 permitted_value_checker=BIT_CHECKER,
1427 comment="Sexual abuse, first experience, happened more than once?",
1428 )
1429 s6_other_more_than_once = CamcopsColumn(
1430 "s6_other_more_than_once",
1431 Boolean,
1432 permitted_value_checker=BIT_CHECKER,
1433 comment="Sexual abuse, other experience, happened more than once?",
1434 )
1435 s6_first_touch_privates_subject = CamcopsColumn(
1436 "s6_first_touch_privates_subject",
1437 Boolean,
1438 permitted_value_checker=BIT_CHECKER,
1439 comment="Sexual abuse, first experience, touched your private parts?",
1440 )
1441 s6_other_touch_privates_subject = CamcopsColumn(
1442 "s6_other_touch_privates_subject",
1443 Boolean,
1444 permitted_value_checker=BIT_CHECKER,
1445 comment="Sexual abuse, other experience, touched your private parts?",
1446 )
1447 s6_first_touch_privates_other = CamcopsColumn(
1448 "s6_first_touch_privates_other",
1449 Boolean,
1450 permitted_value_checker=BIT_CHECKER,
1451 comment="Sexual abuse, first experience, touched their private parts?",
1452 )
1453 s6_other_touch_privates_other = CamcopsColumn(
1454 "s6_other_touch_privates_other",
1455 Boolean,
1456 permitted_value_checker=BIT_CHECKER,
1457 comment="Sexual abuse, other experience, touched their private parts?",
1458 )
1459 s6_first_intercourse = CamcopsColumn(
1460 "s6_first_intercourse",
1461 Boolean,
1462 permitted_value_checker=BIT_CHECKER,
1463 comment="Sexual abuse, first experience, sexual intercourse?",
1464 )
1465 s6_other_intercourse = CamcopsColumn(
1466 "s6_other_intercourse",
1467 Boolean,
1468 permitted_value_checker=BIT_CHECKER,
1469 comment="Sexual abuse, other experience, sexual intercourse?",
1470 )
1471 s6_unwanted_sexual_description = Column(
1472 "s6_unwanted_sexual_description",
1473 UnicodeText,
1474 comment="Sexual abuse, description",
1475 )
1477 # -------------------------------------------------------------------------
1478 # Final
1479 # -------------------------------------------------------------------------
1480 any_other_comments = CamcopsColumn(
1481 "any_other_comments", UnicodeText, comment="Any other comments"
1482 )
1484 @staticmethod
1485 def longname(req: "CamcopsRequest") -> str:
1486 _ = req.gettext
1487 return _("Childhood Experience of Care and Abuse Questionnaire")
1489 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]:
1490 return self.standard_task_summary_fields() + [
1491 SummaryElement(
1492 name="parental_loss_risk",
1493 coltype=Boolean(),
1494 value=self.parental_loss_risk(),
1495 comment="Parental loss risk factor?",
1496 ),
1497 SummaryElement(
1498 name="parental_loss_high_risk",
1499 coltype=Boolean(),
1500 value=self.parental_loss_high_risk(),
1501 comment="Parental loss higher risk factor?",
1502 ),
1503 SummaryElement(
1504 name="mother_antipathy",
1505 coltype=Integer(),
1506 value=self.mother_antipathy(),
1507 comment="Maternal antipathy score (8-40)",
1508 ),
1509 SummaryElement(
1510 name="mother_neglect",
1511 coltype=Integer(),
1512 value=self.mother_neglect(),
1513 comment="Maternal neglect score (8-40)",
1514 ),
1515 SummaryElement(
1516 name="mother_psychological_abuse",
1517 coltype=Integer(),
1518 value=self.mother_psychological_abuse(),
1519 comment="Maternal psychological abuse score (0-85)",
1520 ),
1521 SummaryElement(
1522 name="father_antipathy",
1523 coltype=Integer(),
1524 value=self.father_antipathy(),
1525 comment="Paternal antipathy score (8-40)",
1526 ),
1527 SummaryElement(
1528 name="father_neglect",
1529 coltype=Integer(),
1530 value=self.father_neglect(),
1531 comment="Paternal neglect score (8-40)",
1532 ),
1533 SummaryElement(
1534 name="father_psychological_abuse",
1535 coltype=Integer(),
1536 value=self.father_psychological_abuse(),
1537 comment="Paternal psychological abuse score (0-85)",
1538 ),
1539 SummaryElement(
1540 name="role_reversal",
1541 coltype=Integer(),
1542 value=self.role_reversal(),
1543 comment="Role reversal score (17-85)",
1544 ),
1545 SummaryElement(
1546 name="physical_abuse_screen",
1547 coltype=Integer(),
1548 value=self.physical_abuse_screen(),
1549 comment="Physical abuse screen (0-1)",
1550 ),
1551 SummaryElement(
1552 name="physical_abuse_severity_mother",
1553 coltype=Integer(),
1554 value=self.physical_abuse_severity_mother(),
1555 comment="Maternal physical abuse severity score (0-4)",
1556 ),
1557 SummaryElement(
1558 name="physical_abuse_severity_father",
1559 coltype=Integer(),
1560 value=self.physical_abuse_severity_father(),
1561 comment="Paternal physical abuse severity score (0-4)",
1562 ),
1563 SummaryElement(
1564 name="sexual_abuse_screen",
1565 coltype=Integer(),
1566 value=self.sexual_abuse_screen(),
1567 comment="Sexual abuse screen (0-3)",
1568 ),
1569 SummaryElement(
1570 name="sexual_abuse_score_first",
1571 coltype=Integer(),
1572 value=self.sexual_abuse_score_first(),
1573 comment="First sexual abuse severity score (0-7)",
1574 ),
1575 SummaryElement(
1576 name="sexual_abuse_score_other",
1577 coltype=Integer(),
1578 value=self.sexual_abuse_score_other(),
1579 comment="Other sexual abuse severity score (0-7)",
1580 ),
1581 ]
1583 # -------------------------------------------------------------------------
1584 # Complete?
1585 # -------------------------------------------------------------------------
1587 def is_complete(self) -> bool:
1588 return (
1589 self.complete_1a()
1590 and self.complete_1b()
1591 and self.complete_1c()
1592 and self.complete_2a()
1593 and self.complete_2b()
1594 and self.complete_3a()
1595 and self.complete_3b()
1596 and self.complete_3c()
1597 and self.complete_4a()
1598 and self.complete_4b()
1599 and self.complete_4c()
1600 and self.complete_5()
1601 and self.complete_6()
1602 and self.field_contents_valid()
1603 )
1605 def is_at_least_one_field_true(self, fields: List[str]) -> bool:
1606 for f in fields:
1607 if getattr(self, f):
1608 return True
1609 return True
1611 def complete_1a(self) -> bool:
1612 if not self.is_at_least_one_field_true(
1613 [
1614 "s1a_motherfigure_birthmother",
1615 "s1a_motherfigure_stepmother",
1616 "s1a_motherfigure_femalerelative",
1617 "s1a_motherfigure_familyfriend",
1618 "s1a_motherfigure_fostermother",
1619 "s1a_motherfigure_adoptivemother",
1620 "s1a_motherfigure_other",
1621 "s1a_fatherfigure_birthfather",
1622 "s1a_fatherfigure_stepfather",
1623 "s1a_fatherfigure_malerelative",
1624 "s1a_fatherfigure_familyfriend",
1625 "s1a_fatherfigure_fosterfather",
1626 "s1a_fatherfigure_adoptivefather",
1627 "s1a_fatherfigure_other",
1628 ]
1629 ):
1630 return False
1631 if (
1632 self.s1a_motherfigure_other
1633 and not self.s1a_motherfigure_other_detail
1634 ):
1635 return False
1636 if (
1637 self.s1a_motherfigure_femalerelative
1638 and not self.s1a_motherfigure_femalerelative_detail
1639 ):
1640 return False
1641 if (
1642 self.s1a_fatherfigure_other
1643 and not self.s1a_fatherfigure_other_detail
1644 ):
1645 return False
1646 if (
1647 self.s1a_fatherfigure_malerelative
1648 and not self.s1a_fatherfigure_malerelative_detail
1649 ):
1650 return False
1651 return True
1653 def complete_1b(self) -> bool:
1654 if self.s1b_institution is None:
1655 return False
1656 if self.s1b_institution and self.s1b_institution_time_years is None:
1657 return False
1658 return True
1660 def complete_1c(self) -> bool:
1661 if self.s1c_mother_died is None or self.s1c_father_died is None:
1662 return False
1663 if self.s1c_mother_died and self.s1c_mother_died_subject_aged is None:
1664 return False
1665 if self.s1c_father_died and self.s1c_father_died_subject_aged is None:
1666 return False
1667 if (
1668 self.s1c_separated_from_mother is None
1669 or self.s1c_separated_from_father is None
1670 ):
1671 return False
1672 if self.s1c_separated_from_mother:
1673 if self.any_fields_none(
1674 [
1675 "s1c_first_separated_from_mother_aged",
1676 "s1c_mother_how_long_first_separation_years", # noqa
1677 "s1c_mother_separation_reason",
1678 ]
1679 ):
1680 return False
1681 if self.s1c_separated_from_father:
1682 if self.any_fields_none(
1683 [
1684 "s1c_first_separated_from_father_aged",
1685 "s1c_father_how_long_first_separation_years", # noqa
1686 "s1c_father_separation_reason",
1687 ]
1688 ):
1689 return False
1690 return True
1692 def complete_2a(self) -> bool:
1693 if self.s2a_which_mother_figure is None:
1694 return False
1695 if self.s2a_which_mother_figure == 0:
1696 return True
1697 if (
1698 self.s2a_which_mother_figure == 5
1699 and self.s2a_which_mother_figure_other_detail is None
1700 ):
1701 return False
1702 for i in range(1, 16): # not q16 (siblings)
1703 if getattr(self, "s2a_q" + str(i)) is None:
1704 return False
1705 return True
1707 def complete_2b(self) -> bool:
1708 abuse = False
1709 if self.s2a_which_mother_figure == 0:
1710 return True
1711 for i in range(1, 18):
1712 if getattr(self, "s2b_q" + str(i)) is None:
1713 return False
1714 if getattr(self, "s2b_q" + str(i)) != 0:
1715 abuse = True
1716 if getattr(self, "s2b_q" + str(i) + "_frequency") is None:
1717 return False
1718 if abuse and self.s2b_age_began is None:
1719 return False
1720 return True
1722 def complete_3a(self):
1723 if self.s3a_which_father_figure is None:
1724 return False
1725 if self.s3a_which_father_figure == 0:
1726 return True
1727 if (
1728 self.s3a_which_father_figure == 5
1729 and self.s3a_which_father_figure_other_detail is None
1730 ):
1731 return False
1732 for i in range(1, 16): # not q16 (siblings)
1733 if getattr(self, "s3a_q" + str(i)) is None:
1734 return False
1735 return True
1737 def complete_3b(self) -> bool:
1738 abuse = False
1739 if self.s3a_which_father_figure == 0:
1740 return True
1741 for i in range(1, 18):
1742 if getattr(self, "s3b_q" + str(i)) is None:
1743 return False
1744 if getattr(self, "s3b_q" + str(i)) != 0:
1745 abuse = True
1746 if getattr(self, "s3b_q" + str(i) + "_frequency") is None:
1747 return False
1748 if abuse and self.s3b_age_began is None:
1749 return False
1750 return True
1752 def complete_3c(self) -> bool:
1753 return self.all_fields_not_none(
1754 [
1755 "s3c_q1",
1756 "s3c_q2",
1757 "s3c_q3",
1758 "s3c_q4",
1759 "s3c_q5",
1760 "s3c_q6",
1761 "s3c_q7",
1762 "s3c_q8",
1763 "s3c_q9",
1764 "s3c_q10",
1765 "s3c_q11",
1766 "s3c_q12",
1767 "s3c_q13",
1768 "s3c_q14",
1769 "s3c_q15",
1770 "s3c_q16",
1771 "s3c_q17",
1772 "s3c_which_parent_cared_for",
1773 "s3c_parent_mental_problem",
1774 "s3c_parent_physical_problem",
1775 ]
1776 )
1778 def complete_4a(self) -> bool:
1779 if self.s4a_adultconfidant is None:
1780 return False
1781 if not self.s4a_adultconfidant:
1782 return True
1783 if not self.is_at_least_one_field_true(
1784 [
1785 "s4a_adultconfidant_mother",
1786 "s4a_adultconfidant_father",
1787 "s4a_adultconfidant_otherrelative",
1788 "s4a_adultconfidant_familyfriend",
1789 "s4a_adultconfidant_responsibleadult",
1790 "s4a_adultconfidant_other",
1791 ]
1792 ):
1793 return False
1794 if (
1795 self.s4a_adultconfidant_other
1796 and not self.s4a_adultconfidant_other_detail
1797 ):
1798 return False
1799 return True
1801 def complete_4b(self) -> bool:
1802 if self.s4b_childconfidant is None:
1803 return False
1804 if not self.s4b_childconfidant:
1805 return True
1806 if not self.is_at_least_one_field_true(
1807 [
1808 "s4b_childconfidant_sister",
1809 "s4b_childconfidant_brother",
1810 "s4b_childconfidant_otherrelative",
1811 "s4b_childconfidant_closefriend",
1812 "s4b_childconfidant_otherfriend",
1813 "s4b_childconfidant_other",
1814 ]
1815 ):
1816 return False
1817 if (
1818 self.s4b_childconfidant_other
1819 and not self.s4b_childconfidant_other_detail
1820 ):
1821 return False
1822 return True
1824 def complete_4c(self) -> bool:
1825 n = 0
1826 if self.s4c_closest_mother:
1827 n += 1
1828 if self.s4c_closest_father:
1829 n += 1
1830 if self.s4c_closest_sibling:
1831 n += 1
1832 if self.s4c_closest_otherrelative:
1833 n += 1
1834 if self.s4c_closest_adultfriend:
1835 n += 1
1836 if self.s4c_closest_childfriend:
1837 n += 1
1838 if self.s4c_closest_other:
1839 n += 1
1840 if n < 2:
1841 return False
1842 if self.s4c_closest_other and not self.s4c_closest_other_detail:
1843 return False
1844 return True
1846 def complete_5(self) -> bool:
1847 if self.s5c_physicalabuse is None:
1848 return False
1849 if self.s5c_physicalabuse == 0:
1850 return True
1851 if (
1852 self.s5c_abused_by_mother is None
1853 or self.s5c_abused_by_father is None
1854 or self.s5c_abuse_by_nonparent is None
1855 ):
1856 return False
1857 if self.s5c_abused_by_mother:
1858 if self.any_fields_none(
1859 [
1860 "s5c_mother_abuse_age_began",
1861 "s5c_mother_hit_more_than_once",
1862 "s5c_mother_hit_how",
1863 "s5c_mother_injured",
1864 "s5c_mother_out_of_control",
1865 ]
1866 ):
1867 return False
1868 if self.s5c_abused_by_father:
1869 if self.any_fields_none(
1870 [
1871 "s5c_father_abuse_age_began",
1872 "s5c_father_hit_more_than_once",
1873 "s5c_father_hit_how",
1874 "s5c_father_injured",
1875 "s5c_father_out_of_control",
1876 ]
1877 ):
1878 return False
1879 if (
1880 self.s5c_abuse_by_nonparent
1881 and not self.s5c_nonparent_abuse_description
1882 ):
1883 return False
1884 return True
1886 def complete_6(self) -> bool:
1887 if (
1888 self.s6_any_unwanted_sexual_experience is None
1889 or self.s6_unwanted_intercourse is None
1890 or self.s6_upsetting_sexual_adult_authority is None
1891 ):
1892 return False
1893 if (
1894 self.s6_any_unwanted_sexual_experience == 0
1895 and self.s6_unwanted_intercourse == 0
1896 and self.s6_upsetting_sexual_adult_authority == 0
1897 ):
1898 return True
1899 if self.any_fields_none(
1900 [
1901 "s6_first_age",
1902 "s6_first_person_known",
1903 "s6_first_relative",
1904 "s6_first_in_household",
1905 "s6_first_more_than_once",
1906 "s6_first_touch_privates_subject",
1907 "s6_first_touch_privates_other",
1908 "s6_first_intercourse",
1909 ]
1910 ):
1911 return False
1912 # no checks for "other experience"
1913 return True
1915 # -------------------------------------------------------------------------
1916 # Scoring
1917 # -------------------------------------------------------------------------
1919 def total_sum_abort_if_none(self, fields: List[str]) -> Optional[int]:
1920 total = 0
1921 for field in fields:
1922 value = getattr(self, field)
1923 if value is None:
1924 return None
1925 total += value
1926 return total
1928 def total_nonzero_scores_1_abort_if_none(
1929 self, fields: Sequence[str]
1930 ) -> Optional[int]:
1931 total = 0
1932 for field in fields:
1933 value = getattr(self, field)
1934 if value is None:
1935 return None
1936 if value:
1937 total += 1
1938 return total
1940 def parental_loss_risk(self) -> bool:
1941 return bool(
1942 self.s1c_mother_died
1943 or self.s1c_father_died
1944 or self.s1c_separated_from_mother
1945 or self.s1c_separated_from_father
1946 )
1948 def parental_loss_high_risk(self) -> bool:
1949 return bool(
1950 self.s1c_separated_from_mother
1951 and (
1952 self.s1c_mother_separation_reason == 5
1953 or self.s1c_mother_separation_reason == 6
1954 )
1955 or self.s1c_separated_from_father
1956 and (
1957 self.s1c_father_separation_reason == 5
1958 or self.s1c_father_separation_reason == 6
1959 )
1960 )
1962 def mother_antipathy(self) -> Optional[int]:
1963 if self.s2a_which_mother_figure == 0:
1964 return None
1965 total = 0
1966 for i in (1, 4, 6, 8, 9, 10, 11, 16):
1967 score = getattr(self, "s2a_q" + str(i))
1968 if i == 16 and score is None:
1969 # Q16 is allowed to be blank (if no siblings)
1970 score = 0
1971 if score is None:
1972 return None
1973 if i in (8, 11):
1974 score = 6 - score # reverse
1975 total += score
1976 return total
1978 def father_antipathy(self) -> Optional[int]:
1979 if self.s3a_which_father_figure == 0:
1980 return None
1981 total = 0
1982 for i in (1, 4, 6, 8, 9, 10, 11, 16):
1983 score = getattr(self, "s3a_q" + str(i))
1984 if i == 16 and score is None:
1985 # Q16 is allowed to be blank (if no siblings)
1986 score = 0
1987 if score is None:
1988 return None
1989 if i in (8, 11):
1990 score = 6 - score # reverse
1991 total += score
1992 return total
1994 def mother_neglect(self) -> Optional[int]:
1995 if self.s2a_which_mother_figure == 0:
1996 return None
1997 total = 0
1998 for i in (2, 3, 5, 7, 12, 13, 14, 15):
1999 score = getattr(self, "s2a_q" + str(i))
2000 if score is None:
2001 return None
2002 if i in (2, 3, 5, 12, 13, 14):
2003 score = 6 - score # reverse
2004 total += score
2005 return total
2007 def father_neglect(self) -> Optional[int]:
2008 if self.s3a_which_father_figure == 0:
2009 return None
2010 total = 0
2011 for i in (2, 3, 5, 7, 12, 13, 14, 15):
2012 score = getattr(self, "s3a_q" + str(i))
2013 if score is None:
2014 return None
2015 if i in (2, 3, 5, 12, 13, 14):
2016 score = 6 - score # reverse
2017 total += score
2018 return total
2020 def mother_psychological_abuse(self) -> Optional[int]:
2021 if self.s2a_which_mother_figure == 0:
2022 return None
2023 total = 0
2024 for i in range(1, 18):
2025 score = getattr(self, "s2b_q" + str(i))
2026 if score is None:
2027 return None
2028 total += score
2029 freqscore = getattr(self, "s2b_q" + str(i) + "_frequency")
2030 if score != 0 and freqscore is None:
2031 return None
2032 if freqscore is not None:
2033 total += freqscore
2034 return total
2036 def father_psychological_abuse(self) -> Optional[int]:
2037 if self.s3a_which_father_figure == 0:
2038 return None
2039 total = 0
2040 for i in range(1, 18):
2041 score = getattr(self, "s3b_q" + str(i))
2042 if score is None:
2043 return None
2044 total += score
2045 freqscore = getattr(self, "s3b_q" + str(i) + "_frequency")
2046 if score != 0 and freqscore is None:
2047 return None
2048 if freqscore is not None:
2049 total += freqscore
2050 return total
2052 def role_reversal(self) -> Optional[int]:
2053 total = 0
2054 for i in range(1, 18):
2055 score = getattr(self, "s3c_q" + str(i))
2056 if score is None:
2057 return None
2058 total += score
2059 return total
2061 def physical_abuse_screen(self) -> Optional[int]:
2062 fields = (
2063 "s5c_physicalabuse",
2064 ) # tuple of length 1 -- requires the comma
2065 return self.total_nonzero_scores_1_abort_if_none(fields)
2067 def physical_abuse_severity_mother(self) -> Optional[int]:
2068 if self.physical_abuse_screen() == 0:
2069 return 0
2070 if self.s5c_abused_by_mother == 0:
2071 return 0
2072 mainfields = (
2073 "s5c_mother_hit_more_than_once",
2074 "s5c_mother_injured",
2075 "s5c_mother_out_of_control",
2076 )
2077 total = self.total_nonzero_scores_1_abort_if_none(mainfields)
2078 if total is None:
2079 return None
2080 if self.s5c_mother_hit_how is None:
2081 return None
2082 if self.s5c_mother_hit_how == 1 or self.s5c_mother_hit_how == 2:
2083 total += 1
2084 return total
2086 def physical_abuse_severity_father(self) -> Optional[int]:
2087 if self.physical_abuse_screen() == 0:
2088 return 0
2089 if self.s5c_abused_by_father == 0:
2090 return 0
2091 mainfields = (
2092 "s5c_father_hit_more_than_once",
2093 "s5c_father_injured",
2094 "s5c_father_out_of_control",
2095 )
2096 total = self.total_nonzero_scores_1_abort_if_none(mainfields)
2097 if total is None:
2098 return None
2099 if self.s5c_father_hit_how is None:
2100 return None
2101 if self.s5c_father_hit_how == 1 or self.s5c_father_hit_how == 2:
2102 total += 1
2103 return total
2105 def sexual_abuse_screen(self) -> Optional[int]:
2106 fields = (
2107 "s6_any_unwanted_sexual_experience",
2108 "s6_unwanted_intercourse",
2109 "s6_upsetting_sexual_adult_authority",
2110 )
2111 return self.total_nonzero_scores_1_abort_if_none(fields)
2113 def sexual_abuse_score_first(self) -> Optional[int]:
2114 if self.sexual_abuse_screen() == 0:
2115 return 0
2116 fields = (
2117 "s6_first_person_known",
2118 "s6_first_relative",
2119 "s6_first_in_household",
2120 "s6_first_more_than_once",
2121 "s6_first_touch_privates_subject",
2122 "s6_first_touch_privates_other",
2123 "s6_first_intercourse",
2124 )
2125 return self.total_nonzero_scores_1_abort_if_none(fields)
2127 def sexual_abuse_score_other(self) -> Optional[int]:
2128 if self.sexual_abuse_screen() == 0:
2129 return 0
2130 fields = (
2131 "s6_other_person_known",
2132 "s6_other_relative",
2133 "s6_other_in_household",
2134 "s6_other_more_than_once",
2135 "s6_other_touch_privates_subject",
2136 "s6_other_touch_privates_other",
2137 "s6_other_intercourse",
2138 )
2139 return self.total_nonzero_scores_1_abort_if_none(fields)
2141 # -------------------------------------------------------------------------
2142 # HTML
2143 # -------------------------------------------------------------------------
2145 def get_task_html(self, req: CamcopsRequest) -> str:
2146 def wxstring(wstringname: str) -> str:
2147 return self.wxstring(req, wstringname)
2149 def subheading_from_wstring(wstringname: str) -> str:
2150 return subheading_from_string(self.wxstring(req, wstringname))
2152 def subsubheading_from_wstring(wstringname: str) -> str:
2153 return subsubheading_from_string(self.wxstring(req, wstringname))
2155 def wstring_boolean(wstring: str, value: Any) -> str:
2156 return string_boolean_(req, self.wxstring(req, wstring), value)
2158 def wstring_numeric(wstring: str, value: Any) -> str:
2159 return string_numeric(self.wxstring(req, wstring), value)
2161 def wstring_string(wstring: str, value: str) -> str:
2162 return string_string(self.wxstring(req, wstring), value)
2164 def wstring_dict(wstring: str, value: Any, d: Dict) -> str:
2165 return string_dict(self.wxstring(req, wstring), value, d)
2167 def string_boolean(string: str, value: Any) -> str:
2168 return string_boolean_(req, string, value)
2170 separation_map = {
2171 None: None,
2172 1: "1 — " + wxstring("1c_separation_reason1"),
2173 2: "2 — " + wxstring("1c_separation_reason2"),
2174 3: "3 — " + wxstring("1c_separation_reason3"),
2175 4: "4 — " + wxstring("1c_separation_reason4"),
2176 5: "5 — " + wxstring("1c_separation_reason5"),
2177 6: "6 — " + wxstring("1c_separation_reason6"),
2178 }
2179 motherfigure_map = {
2180 None: None,
2181 0: "0 — " + wxstring("2a_which_option0"),
2182 1: "1 — " + wxstring("2a_which_option1"),
2183 2: "2 — " + wxstring("2a_which_option2"),
2184 3: "3 — " + wxstring("2a_which_option3"),
2185 4: "4 — " + wxstring("2a_which_option4"),
2186 5: "5 — " + wxstring("2a_which_option5"),
2187 }
2188 fatherfigure_map = {
2189 None: None,
2190 0: "0 — " + wxstring("3a_which_option0"),
2191 1: "1 — " + wxstring("3a_which_option1"),
2192 2: "2 — " + wxstring("3a_which_option2"),
2193 3: "3 — " + wxstring("3a_which_option3"),
2194 4: "4 — " + wxstring("3a_which_option4"),
2195 5: "5 — " + wxstring("3a_which_option5"),
2196 }
2197 no_yes_5way_map = {
2198 None: None,
2199 1: "1 — " + wxstring("options5way_notoyes_1"),
2200 2: "2 — (between not-at-all and unsure)",
2201 3: "3 — " + wxstring("options5way_notoyes_3"),
2202 4: "4 — (between unsure and yes-definitely)",
2203 5: "5 — " + wxstring("options5way_notoyes_5"),
2204 }
2205 no_yes_3way_map = {
2206 None: None,
2207 0: "0 — " + wxstring("options3way_noto_yes_0"),
2208 1: "1 — " + wxstring("options3way_noto_yes_1"),
2209 2: "2 — " + wxstring("options3way_noto_yes_2"),
2210 }
2211 frequency_map = {
2212 None: None,
2213 0: "0 — " + wxstring("optionsfrequency0"),
2214 1: "1 — " + wxstring("optionsfrequency1"),
2215 2: "2 — " + wxstring("optionsfrequency2"),
2216 3: "3 — " + wxstring("optionsfrequency3"),
2217 }
2218 parent_cared_for_map = {
2219 None: None,
2220 0: "0 — " + wxstring("3c_whichparentcaredfor_option0"),
2221 1: "1 — " + wxstring("3c_whichparentcaredfor_option1"),
2222 2: "2 — " + wxstring("3c_whichparentcaredfor_option2"),
2223 3: "3 — " + wxstring("3c_whichparentcaredfor_option3"),
2224 4: "4 — " + wxstring("3c_whichparentcaredfor_option4"),
2225 }
2226 hitting_map = {
2227 None: None,
2228 1: "1 — " + wxstring("5_hit_option_1"),
2229 2: "2 — " + wxstring("5_hit_option_2"),
2230 3: "3 — " + wxstring("5_hit_option_3"),
2231 4: "4 — " + wxstring("5_hit_option_4"),
2232 }
2233 html = (
2234 f"""
2235 <div class="{CssClass.SUMMARY}">
2236 <table class="{CssClass.SUMMARY}">
2237 """
2238 + self.get_is_complete_tr(req)
2239 + tr_qa(
2240 "Parental loss risk factor? <sup>[1]</sup>",
2241 get_yes_no(req, self.parental_loss_risk()),
2242 )
2243 + tr_qa(
2244 "Parental loss higher risk factor? <sup>[2]</sup>",
2245 get_yes_no(req, self.parental_loss_high_risk()),
2246 )
2247 + tr_qa(
2248 "Maternal antipathy score (8–40) <sup>[3]</sup>",
2249 self.mother_antipathy(),
2250 )
2251 + tr_qa(
2252 "Maternal neglect score (8–40) <sup>[3]</sup>",
2253 self.mother_neglect(),
2254 )
2255 + tr_qa(
2256 "Maternal psychological abuse score (0–85) <sup>[4]</sup>",
2257 self.mother_psychological_abuse(),
2258 )
2259 + tr_qa(
2260 "Paternal antipathy score (8–40) <sup>[3]</sup>",
2261 self.father_antipathy(),
2262 )
2263 + tr_qa(
2264 "Paternal neglect score (8–40) <sup>[3]</sup>",
2265 self.father_neglect(),
2266 )
2267 + tr_qa(
2268 "Paternal psychological abuse score (0–85) <sup>[4]</sup>",
2269 self.father_psychological_abuse(),
2270 )
2271 + tr_qa(
2272 "Role reversal score (17–85) <sup>[5]</sup>",
2273 self.role_reversal(),
2274 )
2275 + tr_qa(
2276 "Physical abuse screen (0–1) <sup>[6]</sup>",
2277 self.physical_abuse_screen(),
2278 )
2279 + tr_qa(
2280 "Maternal physical abuse severity score (0–4) "
2281 "<sup>[6]</sup>",
2282 self.physical_abuse_severity_mother(),
2283 )
2284 + tr_qa(
2285 "Paternal physical abuse severity score (0–4) "
2286 "<sup>[6]</sup>",
2287 self.physical_abuse_severity_father(),
2288 )
2289 + tr_qa(
2290 "Sexual abuse screen (0–3) <sup>[7]</sup>",
2291 self.sexual_abuse_screen(),
2292 )
2293 + tr_qa(
2294 "First sexual abuse severity score (0–7) <sup>[7]</sup>",
2295 self.sexual_abuse_score_first(),
2296 )
2297 + tr_qa(
2298 "Other sexual abuse severity score (0–7) <sup>[7]</sup>",
2299 self.sexual_abuse_score_other(),
2300 )
2301 + f"""
2302 </table>
2303 </div>
2304 <table class="{CssClass.TASKDETAIL}">
2305 """
2306 + subheading_spanning_two_columns("1A: " + wxstring("1a_q"))
2307 + subsubheading_from_wstring("1a_motherfigures")
2308 + wstring_boolean(
2309 "1a_mf_birthmother", self.s1a_motherfigure_birthmother
2310 )
2311 + wstring_boolean(
2312 "1a_mf_stepmother", self.s1a_motherfigure_stepmother
2313 )
2314 + wstring_boolean(
2315 "1a_mf_femalerelative", self.s1a_motherfigure_femalerelative
2316 )
2317 + string_string(
2318 "(Female relative details)",
2319 self.s1a_motherfigure_femalerelative_detail,
2320 )
2321 + wstring_boolean(
2322 "1a_mf_familyfriend", self.s1a_motherfigure_familyfriend
2323 )
2324 + wstring_boolean(
2325 "1a_mf_fostermother", self.s1a_motherfigure_fostermother
2326 )
2327 + wstring_boolean(
2328 "1a_mf_adoptivemother", self.s1a_motherfigure_adoptivemother
2329 )
2330 + wstring_boolean("other", self.s1a_motherfigure_other)
2331 + string_string(
2332 "(Other, details)", self.s1a_motherfigure_other_detail
2333 )
2334 + subsubheading_from_wstring("1a_fatherfigures")
2335 + wstring_boolean(
2336 "1a_ff_birthfather", self.s1a_fatherfigure_birthfather
2337 )
2338 + wstring_boolean(
2339 "1a_ff_stepfather", self.s1a_fatherfigure_stepfather
2340 )
2341 + wstring_boolean(
2342 "1a_ff_malerelative", self.s1a_fatherfigure_malerelative
2343 )
2344 + string_string(
2345 "(Male relative details)",
2346 self.s1a_fatherfigure_malerelative_detail,
2347 )
2348 + wstring_boolean(
2349 "1a_ff_familyfriend", self.s1a_fatherfigure_familyfriend
2350 )
2351 + wstring_boolean(
2352 "1a_ff_fosterfather", self.s1a_fatherfigure_fosterfather
2353 )
2354 + wstring_boolean(
2355 "1a_ff_adoptivefather", self.s1a_fatherfigure_adoptivefather
2356 )
2357 + wstring_boolean("other", self.s1a_fatherfigure_other)
2358 + string_string(
2359 "(Other, details)", self.s1a_fatherfigure_other_detail
2360 )
2361 + subheading_from_string("1B: " + wxstring("1b_q"))
2362 + wstring_boolean("1b_q", self.s1b_institution)
2363 + wstring_numeric("1b_q_how_long", self.s1b_institution_time_years)
2364 + subheading_from_string("1C: " + wxstring("1c_heading"))
2365 + subsubheading_from_wstring("mother")
2366 + string_boolean("Mother died before age 17", self.s1c_mother_died)
2367 + wstring_numeric(
2368 "1c_parentdiedage", self.s1c_mother_died_subject_aged
2369 )
2370 + string_boolean(
2371 "Separated from mother for >1y", self.s1c_separated_from_mother
2372 )
2373 + wstring_numeric(
2374 "1c_age_first_separated",
2375 self.s1c_first_separated_from_mother_aged,
2376 )
2377 + wstring_numeric(
2378 "1c_how_long_separation",
2379 self.s1c_mother_how_long_first_separation_years,
2380 )
2381 + wstring_dict(
2382 "1c_separation_reason",
2383 self.s1c_mother_separation_reason,
2384 separation_map,
2385 )
2386 + subsubheading_from_wstring("father")
2387 + string_boolean("Father died before age 17", self.s1c_father_died)
2388 + wstring_numeric(
2389 "1c_parentdiedage", self.s1c_father_died_subject_aged
2390 )
2391 + string_boolean(
2392 "Separated from father for >1y", self.s1c_separated_from_father
2393 )
2394 + wstring_numeric(
2395 "1c_age_first_separated",
2396 self.s1c_first_separated_from_father_aged,
2397 )
2398 + wstring_numeric(
2399 "1c_how_long_separation",
2400 self.s1c_father_how_long_first_separation_years,
2401 )
2402 + wstring_dict(
2403 "1c_separation_reason",
2404 self.s1c_father_separation_reason,
2405 separation_map,
2406 )
2407 + wstring_string(
2408 "please_describe_experience", self.s1c_describe_experience
2409 )
2410 + subheading_from_string("2A: " + wxstring("2a_heading"))
2411 + wstring_dict(
2412 "2a_which", self.s2a_which_mother_figure, motherfigure_map
2413 )
2414 + wstring_string(
2415 "rnc_if_other_describe",
2416 self.s2a_which_mother_figure_other_detail,
2417 )
2418 )
2419 for i in range(1, 17):
2420 html += string_dict(
2421 str(i) + ". " + wxstring("2a_q" + str(i)),
2422 getattr(self, "s2a_q" + str(i)),
2423 no_yes_5way_map,
2424 )
2425 html += wstring_string(
2426 "2a_add_anything", self.s2a_extra
2427 ) + subheading_from_string("2B: " + wxstring("2b_heading"))
2428 for i in range(1, 18):
2429 html += tr(
2430 str(i) + ". " + wxstring("2b_q" + str(i)),
2431 answer(
2432 get_from_dict(
2433 no_yes_3way_map, getattr(self, "s2b_q" + str(i))
2434 )
2435 )
2436 + " ("
2437 + answer(
2438 get_from_dict(
2439 frequency_map,
2440 getattr(self, "s2b_q" + str(i) + "_frequency"),
2441 )
2442 )
2443 + ")",
2444 )
2445 html += (
2446 wstring_boolean("if_any_what_age", self.s2b_age_began)
2447 + wstring_string("is_there_more_you_want_to_say", self.s2b_extra)
2448 + subheading_from_string("3A: " + wxstring("3a_heading"))
2449 + wstring_dict(
2450 "2a_which", self.s3a_which_father_figure, fatherfigure_map
2451 )
2452 + wstring_string(
2453 "rnc_if_other_describe",
2454 self.s3a_which_father_figure_other_detail,
2455 )
2456 )
2457 for i in range(1, 17):
2458 html += string_dict(
2459 str(i) + ". " + wxstring("3a_q" + str(i)),
2460 getattr(self, "s3a_q" + str(i)),
2461 no_yes_5way_map,
2462 )
2463 html += wstring_string(
2464 "3a_add_anything", self.s3a_extra
2465 ) + subheading_from_string("3B: " + wxstring("3b_heading"))
2466 for i in range(1, 18):
2467 html += tr(
2468 str(i) + ". " + wxstring("3b_q" + str(i)),
2469 answer(
2470 get_from_dict(
2471 no_yes_3way_map, getattr(self, "s3b_q" + str(i))
2472 )
2473 )
2474 + " ("
2475 + answer(
2476 get_from_dict(
2477 frequency_map,
2478 getattr(self, "s3b_q" + str(i) + "_frequency"),
2479 )
2480 )
2481 + ")",
2482 )
2483 html += (
2484 wstring_boolean("if_any_what_age", self.s3b_age_began)
2485 + wstring_string("is_there_more_you_want_to_say", self.s3b_extra)
2486 + subheading_from_string("3C: " + wxstring("3c_heading"))
2487 )
2488 for i in range(1, 18):
2489 html += string_dict(
2490 str(i) + ". " + wxstring("3c_q" + str(i)),
2491 getattr(self, "s3c_q" + str(i)),
2492 no_yes_5way_map,
2493 )
2494 html += (
2495 wstring_dict(
2496 "3c_which_parent_cared_for",
2497 self.s3c_which_parent_cared_for,
2498 parent_cared_for_map,
2499 )
2500 + wstring_boolean(
2501 "3c_parent_mental_problem", self.s3c_parent_mental_problem
2502 )
2503 + wstring_boolean(
2504 "3c_parent_physical_problem", self.s3c_parent_physical_problem
2505 )
2506 + subheading_from_string("4: " + wxstring("4_heading"))
2507 + subsubheading_from_string("(Adult confidant)")
2508 + wstring_boolean("4a_q", self.s4a_adultconfidant)
2509 + subsubheading_from_wstring("4_if_so_who")
2510 + wstring_boolean(
2511 "4a_option_mother", self.s4a_adultconfidant_mother
2512 )
2513 + wstring_boolean(
2514 "4a_option_father", self.s4a_adultconfidant_father
2515 )
2516 + wstring_boolean(
2517 "4a_option_relative", self.s4a_adultconfidant_otherrelative
2518 )
2519 + wstring_boolean(
2520 "4a_option_friend", self.s4a_adultconfidant_familyfriend
2521 )
2522 + wstring_boolean(
2523 "4a_option_responsibleadult",
2524 self.s4a_adultconfidant_responsibleadult,
2525 )
2526 + wstring_boolean("4a_option_other", self.s4a_adultconfidant_other)
2527 + string_string(
2528 "(Other, details)", self.s4a_adultconfidant_other_detail
2529 )
2530 + wstring_string(
2531 "4_note_anything", self.s4a_adultconfidant_additional
2532 )
2533 + subsubheading_from_string("(Child confidant)")
2534 + wstring_boolean("4b_q", self.s4b_childconfidant)
2535 + subsubheading_from_wstring("4_if_so_who")
2536 + wstring_boolean(
2537 "4b_option_sister", self.s4b_childconfidant_sister
2538 )
2539 + wstring_boolean(
2540 "4b_option_brother", self.s4b_childconfidant_brother
2541 )
2542 + wstring_boolean(
2543 "4b_option_relative", self.s4b_childconfidant_otherrelative
2544 )
2545 + wstring_boolean(
2546 "4b_option_closefriend", self.s4b_childconfidant_closefriend
2547 )
2548 + wstring_boolean(
2549 "4b_option_otherfriend", self.s4b_childconfidant_otherfriend
2550 )
2551 + wstring_boolean("4b_option_other", self.s4b_childconfidant_other)
2552 + string_string(
2553 "(Other, details)", self.s4b_childconfidant_other_detail
2554 )
2555 + wstring_string(
2556 "4_note_anything", self.s4b_childconfidant_additional
2557 )
2558 + subsubheading_from_wstring("4c_q")
2559 + wstring_boolean("4c_option_mother", self.s4c_closest_mother)
2560 + wstring_boolean("4c_option_father", self.s4c_closest_father)
2561 + string_boolean("4c_option_sibling", self.s4c_closest_sibling)
2562 + wstring_boolean(
2563 "4c_option_relative", self.s4c_closest_otherrelative
2564 )
2565 + wstring_boolean(
2566 "4c_option_adultfriend", self.s4c_closest_adultfriend
2567 )
2568 + wstring_boolean(
2569 "4c_option_youngfriend", self.s4c_closest_childfriend
2570 )
2571 + wstring_boolean("4c_option_other", self.s4c_closest_other)
2572 + string_string("(Other, details)", self.s4c_closest_other_detail)
2573 + wstring_string("4_note_anything", self.s4c_closest_additional)
2574 + subheading_from_string("4: " + wxstring("5_heading"))
2575 + wstring_boolean("5_mainq", self.s5c_physicalabuse)
2576 + subsubheading_from_wstring("5_motherfigure")
2577 + wstring_boolean(
2578 "5_did_this_person_hurt_you", self.s5c_abused_by_mother
2579 )
2580 + wstring_numeric("5_how_old", self.s5c_mother_abuse_age_began)
2581 + wstring_boolean(
2582 "5_hit_more_than_once", self.s5c_mother_hit_more_than_once
2583 )
2584 + wstring_dict("5_how_hit", self.s5c_mother_hit_how, hitting_map)
2585 + wstring_boolean("5_injured", self.s5c_mother_injured)
2586 + wstring_boolean("5_outofcontrol", self.s5c_mother_out_of_control)
2587 + subsubheading_from_wstring("5_fatherfigure")
2588 + wstring_boolean(
2589 "5_did_this_person_hurt_you", self.s5c_abused_by_father
2590 )
2591 + wstring_numeric("5_how_old", self.s5c_father_abuse_age_began)
2592 + wstring_boolean(
2593 "5_hit_more_than_once", self.s5c_father_hit_more_than_once
2594 )
2595 + wstring_dict("5_how_hit", self.s5c_father_hit_how, hitting_map)
2596 + wstring_boolean("5_injured", self.s5c_father_injured)
2597 + wstring_boolean("5_outofcontrol", self.s5c_father_out_of_control)
2598 + wstring_string(
2599 "5_can_you_describe_1", self.s5c_parental_abuse_description
2600 )
2601 + subsubheading_from_string("(Other in household)")
2602 + wstring_boolean("5_anyone_else", self.s5c_abuse_by_nonparent)
2603 + wstring_string(
2604 "5_can_you_describe_2", self.s5c_nonparent_abuse_description
2605 )
2606 + subheading_from_string("6: " + wxstring("6_heading"))
2607 + wstring_dict(
2608 "6_any_unwanted",
2609 self.s6_any_unwanted_sexual_experience,
2610 no_yes_3way_map,
2611 )
2612 + wstring_dict(
2613 "6_intercourse", self.s6_unwanted_intercourse, no_yes_3way_map
2614 )
2615 + wstring_dict(
2616 "6_upset_adult_authority",
2617 self.s6_upsetting_sexual_adult_authority,
2618 no_yes_3way_map,
2619 )
2620 + subsubheading_from_wstring("6_first_experience")
2621 + wstring_numeric("6_q1", self.s6_first_age)
2622 + wstring_boolean("6_q2", self.s6_first_person_known)
2623 + wstring_boolean("6_q3", self.s6_first_relative)
2624 + wstring_boolean("6_q4", self.s6_first_in_household)
2625 + wstring_boolean("6_q5", self.s6_first_more_than_once)
2626 + wstring_boolean("6_q6", self.s6_first_touch_privates_subject)
2627 + wstring_boolean("6_q7", self.s6_first_touch_privates_other)
2628 + wstring_boolean("6_q8", self.s6_first_intercourse)
2629 + subsubheading_from_wstring("6_other_experience")
2630 + wstring_numeric("6_q1", self.s6_other_age)
2631 + wstring_boolean("6_q2", self.s6_other_person_known)
2632 + wstring_boolean("6_q3", self.s6_other_relative)
2633 + wstring_boolean("6_q4", self.s6_other_in_household)
2634 + wstring_boolean("6_q5", self.s6_other_more_than_once)
2635 + wstring_boolean("6_q6", self.s6_other_touch_privates_subject)
2636 + wstring_boolean("6_q7", self.s6_other_touch_privates_other)
2637 + wstring_boolean("6_q8", self.s6_other_intercourse)
2638 + wstring_string(
2639 "5_can_you_describe_1", self.s6_unwanted_sexual_description
2640 )
2641 + subheading_from_wstring("any_other_comments")
2642 + wstring_string("any_other_comments", self.any_other_comments)
2643 + f"""
2644 </table>
2645 <div class="{CssClass.FOOTNOTES}">
2646 [1] Death of mother/father before age 17 or continuous
2647 separation of ≥1 year.
2648 [2] Reason for loss ‘abandonment’ or ‘other’.
2649 [3] Section 2A and 3A contain antipathy and neglect scales.
2650 Antipathy scales: reverse items 8, 11;
2651 then sum 1, 4, 6, 8–11, 16.
2652 Neglect scales: reverse items 2, 3, 5, 12–14;
2653 then sum 2, 3, 5, 7, 12–15.
2654 [4] Psychological abuse scores (sections 2B, 3B):
2655 sum of items 1–17 (yes=2, unsure=1, no=0) with
2656 frequencies (never=0, once=1, rarely=2, often=3).
2657 Any score >1 is a risk indicator.
2658 [5] Role reversal: sum of scores from section 3C.
2659 [6] Physical abuse (section 4): first question (screen
2660 item) is scored 0/1. For each parent, score 1 for
2661 {{>1 occasion, {{belt/stick/punch/kick}}, injured,
2662 out-of-control}}.
2663 [7] Sexual abuse (section 6): no=0, unsure=1, yes=1.
2664 First three questions are the screen.
2665 </div>
2666 """
2667 )
2668 return html
2671# =============================================================================
2672# More helper functions
2673# =============================================================================
2676def subheading_from_string(s: str) -> str:
2677 return subheading_spanning_two_columns(s)
2680def subsubheading_from_string(s: str) -> str:
2681 return f'<tr><td></td><td class="{CssClass.SUBHEADING}">{s}</td></tr>'
2684def row(label: str, value: Any, default: str = "") -> str:
2685 return tr_qa(label, value, default=default)
2688def string_boolean_(req: CamcopsRequest, string: str, value: Any) -> str:
2689 return row(string, get_yes_no_none(req, value))
2692def string_numeric(string: str, value: Any) -> str:
2693 return row(string, value)
2696def string_string(string: str, value: str) -> str:
2697 return row(string, ws.webify(value))
2700def string_dict(string: str, value: Any, d: Dict) -> str:
2701 return row(string, get_from_dict(d, value))