Coverage for tasks/ceca.py: 46%

1"""

2 camcops_server/tasks/ceca.py

3

4===============================================================================

5

6 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.

7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

8

9 This file is part of CamCOPS.

10

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.

15

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.

20

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/>.

23

24===============================================================================

25

26"""

27

28 from typing import Any, Dict, List, Optional, Sequence

29

30 import cardinal_pythonlib.rnc_web as ws

31 from sqlalchemy.orm import Mapped, mapped_column

32 from sqlalchemy.sql.sqltypes import Boolean, Integer, UnicodeText

33

34 from camcops_server.cc_modules.cc_constants import CssClass

35 from 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)

43 from camcops_server.cc_modules.cc_request import CamcopsRequest

44 from 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)

56 from camcops_server.cc_modules.cc_summaryelement import SummaryElement

57 from camcops_server.cc_modules.cc_task import (

58 get_from_dict,

59 Task,

60 TaskHasPatientMixin,

61)

62

63

64# =============================================================================

65# CECA-Q3

66# =============================================================================

67

68 FREQUENCY_COMMENT = "Frequency (0 never - 3 often)"

69

70

71 class CecaQ3(TaskHasPatientMixin, Task): # type: ignore[misc]

72 """

73 Server implementation of the CECA-Q3 task.

74 """

75

76 __tablename__ = "cecaq3"

77 shortname = "CECA-Q3"

78

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 )

182

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 )

196

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 )

276

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 )

359

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 )

507

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 )

590

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 )

738

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 )

825

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 )

871

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 )

917

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 )

957

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 )

1033

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 )

1146

1147 # -------------------------------------------------------------------------

1148 # Final

1149 # -------------------------------------------------------------------------

1150 any_other_comments: Mapped[Optional[str]] = mapped_camcops_column(

1151 UnicodeText, comment="Any other comments"

1152 )

1153

1154 @staticmethod

1155 def longname(req: "CamcopsRequest") -> str:

1156 _ = req.gettext

1157 return _("Childhood Experience of Care and Abuse Questionnaire")

1158

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 ]

1252

1253 # -------------------------------------------------------------------------

1254 # Complete?

1255 # -------------------------------------------------------------------------

1256

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 )

1274

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

1280

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

1322

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

1329

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

1361

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

1376

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

1391

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

1406

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

1421

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 )

1447

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

1470

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

1493

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

1515

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

1555

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

1584

1585 # -------------------------------------------------------------------------

1586 # Scoring

1587 # -------------------------------------------------------------------------

1588

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

1597

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

1609

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 )

1617

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 )

1631

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

1647

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

1663

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

1676

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

1689

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

1705

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

1721

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

1730

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)

1736

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

1755

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

1774

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)

1782

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)

1796

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)

1810

1811 # -------------------------------------------------------------------------

1812 # HTML

1813 # -------------------------------------------------------------------------

1814

1815 def get_task_html(self, req: CamcopsRequest) -> str:

1816 def wxstring(wstringname: str) -> str:

1817 return self.wxstring(req, wstringname)

1818

1819 def subheading_from_wstring(wstringname: str) -> str:

1820 return subheading_from_string(self.wxstring(req, wstringname))

1821

1822 def subsubheading_from_wstring(wstringname: str) -> str:

1823 return subsubheading_from_string(self.wxstring(req, wstringname))

1824

1825 def wstring_boolean(wstring: str, value: Any) -> str:

1826 return string_boolean_(req, self.wxstring(req, wstring), value)

1827

1828 def wstring_numeric(wstring: str, value: Any) -> str:

1829 return string_numeric(self.wxstring(req, wstring), value)

1830

1831 def wstring_string(wstring: str, value: str) -> str:

1832 return string_string(self.wxstring(req, wstring), value)

1833

1834 def wstring_dict(wstring: str, value: Any, d: Dict) -> str:

1835 return string_dict(self.wxstring(req, wstring), value, d)

1836

1837 def string_boolean(string: str, value: Any) -> str:

1838 return string_boolean_(req, string, value)

1839

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 &gt;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 {{&gt;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

2339

2340

2341# =============================================================================

2342# More helper functions

2343# =============================================================================

2344

2345

2346 def subheading_from_string(s: str) -> str:

2347 return subheading_spanning_two_columns(s)

2348

2349

2350 def subsubheading_from_string(s: str) -> str:

2351 return f'<tr><td></td><td class="{CssClass.SUBHEADING}">{s}</td></tr>'

2352

2353

2354 def row(label: str, value: Any, default: str = "") -> str:

2355 return tr_qa(label, value, default=default)

2356

2357

2358 def string_boolean_(req: CamcopsRequest, string: str, value: Any) -> str:

2359 return row(string, get_yes_no_none(req, value))

2360

2361

2362 def string_numeric(string: str, value: Any) -> str:

2363 return row(string, value)

2364

2365

2366 def string_string(string: str, value: str) -> str:

2367 return row(string, ws.webify(value))

2368

2369

2370 def string_dict(string: str, value: Any, d: Dict) -> str:

2371 return row(string, get_from_dict(d, value))