Coverage for tasks/ceca.py: 46%

616 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-15 14:23 +0100

1""" 

2camcops_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 

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

29 

30import cardinal_pythonlib.rnc_web as ws 

31from sqlalchemy.orm import Mapped, mapped_column 

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

33 

34from camcops_server.cc_modules.cc_constants import CssClass 

35from camcops_server.cc_modules.cc_html import ( 

36 answer, 

37 get_yes_no, 

38 get_yes_no_none, 

39 subheading_spanning_two_columns, 

40 tr, 

41 tr_qa, 

42) 

43from camcops_server.cc_modules.cc_request import CamcopsRequest 

44from camcops_server.cc_modules.cc_sqla_coltypes import ( 

45 BIT_CHECKER, 

46 mapped_camcops_column, 

47 MIN_ZERO_CHECKER, 

48 ONE_TO_FOUR_CHECKER, 

49 ONE_TO_FIVE_CHECKER, 

50 PermittedValueChecker, 

51 ZERO_TO_TWO_CHECKER, 

52 ZERO_TO_THREE_CHECKER, 

53 ZERO_TO_FOUR_CHECKER, 

54 ZERO_TO_FIVE_CHECKER, 

55) 

56from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

57from camcops_server.cc_modules.cc_task import ( 

58 get_from_dict, 

59 Task, 

60 TaskHasPatientMixin, 

61) 

62 

63 

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

65# CECA-Q3 

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

67 

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

69 

70 

71class 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 

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

2347 return subheading_spanning_two_columns(s) 

2348 

2349 

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

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

2352 

2353 

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

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

2356 

2357 

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

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

2360 

2361 

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

2363 return row(string, value) 

2364 

2365 

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

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

2368 

2369 

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

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