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