Coverage for tasks/ceca.py : 46%

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