Coverage for tasks/ceca.py: 46%

617 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-08 23:14 +0000

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/ceca.py 

5 

6=============================================================================== 

7 

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

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

10 

11 This file is part of CamCOPS. 

12 

13 CamCOPS is free software: you can redistribute it and/or modify 

14 it under the terms of the GNU General Public License as published by 

15 the Free Software Foundation, either version 3 of the License, or 

16 (at your option) any later version. 

17 

18 CamCOPS is distributed in the hope that it will be useful, 

19 but WITHOUT ANY WARRANTY; without even the implied warranty of 

20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

21 GNU General Public License for more details. 

22 

23 You should have received a copy of the GNU General Public License 

24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

25 

26=============================================================================== 

27 

28""" 

29 

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

31 

32import cardinal_pythonlib.rnc_web as ws 

33from sqlalchemy.sql.schema import Column 

34from sqlalchemy.sql.sqltypes import Boolean, Float, Integer, UnicodeText 

35 

36from camcops_server.cc_modules.cc_constants import CssClass 

37from camcops_server.cc_modules.cc_html import ( 

38 answer, 

39 get_yes_no, 

40 get_yes_no_none, 

41 subheading_spanning_two_columns, 

42 tr, 

43 tr_qa, 

44) 

45from camcops_server.cc_modules.cc_request import CamcopsRequest 

46from camcops_server.cc_modules.cc_sqla_coltypes import ( 

47 BIT_CHECKER, 

48 CamcopsColumn, 

49 MIN_ZERO_CHECKER, 

50 ONE_TO_FOUR_CHECKER, 

51 ONE_TO_FIVE_CHECKER, 

52 PermittedValueChecker, 

53 ZERO_TO_TWO_CHECKER, 

54 ZERO_TO_THREE_CHECKER, 

55 ZERO_TO_FOUR_CHECKER, 

56 ZERO_TO_FIVE_CHECKER, 

57) 

58from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

59from camcops_server.cc_modules.cc_task import ( 

60 get_from_dict, 

61 Task, 

62 TaskHasPatientMixin, 

63) 

64 

65 

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

67# CECA-Q3 

68# ============================================================================= 

69 

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

71 

72 

73class CecaQ3(TaskHasPatientMixin, Task): 

74 """ 

75 Server implementation of the CECA-Q3 task. 

76 """ 

77 

78 __tablename__ = "cecaq3" 

79 shortname = "CECA-Q3" 

80 

81 # ------------------------------------------------------------------------- 

82 # Section 1(A) 

83 # ------------------------------------------------------------------------- 

84 s1a_motherfigure_birthmother = CamcopsColumn( 

85 "s1a_motherfigure_birthmother", 

86 Boolean, 

87 permitted_value_checker=BIT_CHECKER, 

88 comment="Raised by, maternal, birth mother?", 

89 ) 

90 s1a_motherfigure_stepmother = CamcopsColumn( 

91 "s1a_motherfigure_stepmother", 

92 Boolean, 

93 permitted_value_checker=BIT_CHECKER, 

94 comment="Raised by, maternal, stepmother?", 

95 ) 

96 s1a_motherfigure_femalerelative = CamcopsColumn( 

97 "s1a_motherfigure_femalerelative", 

98 Boolean, 

99 permitted_value_checker=BIT_CHECKER, 

100 comment="Raised by, maternal, female relative?", 

101 ) 

102 s1a_motherfigure_femalerelative_detail = Column( 

103 "s1a_motherfigure_femalerelative_detail", 

104 UnicodeText, 

105 comment="Raised by, maternal, female relative, detail", 

106 ) 

107 s1a_motherfigure_familyfriend = CamcopsColumn( 

108 "s1a_motherfigure_familyfriend", 

109 Boolean, 

110 permitted_value_checker=BIT_CHECKER, 

111 comment="Raised by, maternal, family friend?", 

112 ) 

113 s1a_motherfigure_fostermother = CamcopsColumn( 

114 "s1a_motherfigure_fostermother", 

115 Boolean, 

116 permitted_value_checker=BIT_CHECKER, 

117 comment="Raised by, maternal, foster mother?", 

118 ) 

119 s1a_motherfigure_adoptivemother = CamcopsColumn( 

120 "s1a_motherfigure_adoptivemother", 

121 Boolean, 

122 permitted_value_checker=BIT_CHECKER, 

123 comment="Raised by, maternal, adoptive mother?", 

124 ) 

125 s1a_motherfigure_other = CamcopsColumn( 

126 "s1a_motherfigure_other", 

127 Boolean, 

128 permitted_value_checker=BIT_CHECKER, 

129 comment="Raised by, maternal, other?", 

130 ) 

131 s1a_motherfigure_other_detail = Column( 

132 "s1a_motherfigure_other_detail", 

133 UnicodeText, 

134 comment="Raised by, maternal, other, detail", 

135 ) 

136 s1a_fatherfigure_birthfather = CamcopsColumn( 

137 "s1a_fatherfigure_birthfather", 

138 Boolean, 

139 permitted_value_checker=BIT_CHECKER, 

140 comment="Raised by, paternal, birth father?", 

141 ) 

142 s1a_fatherfigure_stepfather = CamcopsColumn( 

143 "s1a_fatherfigure_stepfather", 

144 Boolean, 

145 permitted_value_checker=BIT_CHECKER, 

146 comment="Raised by, paternal, stepfather?", 

147 ) 

148 s1a_fatherfigure_malerelative = CamcopsColumn( 

149 "s1a_fatherfigure_malerelative", 

150 Boolean, 

151 permitted_value_checker=BIT_CHECKER, 

152 comment="Raised by, paternal, male relative?", 

153 ) 

154 s1a_fatherfigure_malerelative_detail = Column( 

155 "s1a_fatherfigure_malerelative_detail", 

156 UnicodeText, 

157 comment="Raised by, paternal, male relative, detail", 

158 ) 

159 s1a_fatherfigure_familyfriend = CamcopsColumn( 

160 "s1a_fatherfigure_familyfriend", 

161 Boolean, 

162 permitted_value_checker=BIT_CHECKER, 

163 comment="Raised by, paternal, family friend?", 

164 ) 

165 s1a_fatherfigure_fosterfather = CamcopsColumn( 

166 "s1a_fatherfigure_fosterfather", 

167 Boolean, 

168 permitted_value_checker=BIT_CHECKER, 

169 comment="Raised by, paternal, foster father?", 

170 ) 

171 s1a_fatherfigure_adoptivefather = CamcopsColumn( 

172 "s1a_fatherfigure_adoptivefather", 

173 Boolean, 

174 permitted_value_checker=BIT_CHECKER, 

175 comment="Raised by, paternal, adoptive father?", 

176 ) 

177 s1a_fatherfigure_other = CamcopsColumn( 

178 "s1a_fatherfigure_other", 

179 Boolean, 

180 permitted_value_checker=BIT_CHECKER, 

181 comment="Raised by, paternal, other?", 

182 ) 

183 s1a_fatherfigure_other_detail = Column( 

184 "s1a_fatherfigure_other_detail", 

185 UnicodeText, 

186 comment="Raised by, paternal, other, detail", 

187 ) 

188 

189 # ------------------------------------------------------------------------- 

190 # Section 1(B) 

191 # ------------------------------------------------------------------------- 

192 s1b_institution = CamcopsColumn( 

193 "s1b_institution", 

194 Boolean, 

195 permitted_value_checker=BIT_CHECKER, 

196 comment="In institution before 17?", 

197 ) 

198 s1b_institution_time_years = CamcopsColumn( 

199 "s1b_institution_time_years", 

200 Float, 

201 permitted_value_checker=MIN_ZERO_CHECKER, 

202 comment="In institution, time (years)", 

203 ) 

204 

205 # ------------------------------------------------------------------------- 

206 # Section 1(C) 

207 # ------------------------------------------------------------------------- 

208 s1c_mother_died = CamcopsColumn( 

209 "s1c_mother_died", 

210 Boolean, 

211 permitted_value_checker=BIT_CHECKER, 

212 comment="Mother died before 17?", 

213 ) 

214 s1c_father_died = CamcopsColumn( 

215 "s1c_father_died", 

216 Boolean, 

217 permitted_value_checker=BIT_CHECKER, 

218 comment="Father died before 17?", 

219 ) 

220 s1c_mother_died_subject_aged = CamcopsColumn( 

221 "s1c_mother_died_subject_aged", 

222 Float, 

223 permitted_value_checker=MIN_ZERO_CHECKER, 

224 comment="Age when mother died (years)", 

225 ) 

226 s1c_father_died_subject_aged = CamcopsColumn( 

227 "s1c_father_died_subject_aged", 

228 Float, 

229 permitted_value_checker=MIN_ZERO_CHECKER, 

230 comment="Age when father died (years)", 

231 ) 

232 s1c_separated_from_mother = CamcopsColumn( 

233 "s1c_separated_from_mother", 

234 Boolean, 

235 permitted_value_checker=BIT_CHECKER, 

236 comment="Separated from mother for >=1y before 17?", 

237 ) 

238 s1c_separated_from_father = CamcopsColumn( 

239 "s1c_separated_from_father", 

240 Boolean, 

241 permitted_value_checker=BIT_CHECKER, 

242 comment="Separated from father for >=1y before 17?", 

243 ) 

244 s1c_first_separated_from_mother_aged = CamcopsColumn( 

245 "s1c_first_separated_from_mother_aged", 

246 Float, 

247 permitted_value_checker=MIN_ZERO_CHECKER, 

248 comment="Maternal separation, age (years)", 

249 ) 

250 s1c_first_separated_from_father_aged = CamcopsColumn( 

251 "s1c_first_separated_from_father_aged", 

252 Float, 

253 permitted_value_checker=MIN_ZERO_CHECKER, 

254 comment="Paternal separation, age (years)", 

255 ) 

256 s1c_mother_how_long_first_separation_years = CamcopsColumn( 

257 "s1c_mother_how_long_first_separation_years", 

258 Float, 

259 permitted_value_checker=MIN_ZERO_CHECKER, 

260 comment="Maternal separation, how long first separation (y)", 

261 ) 

262 s1c_father_how_long_first_separation_years = CamcopsColumn( 

263 "s1c_father_how_long_first_separation_years", 

264 Float, 

265 permitted_value_checker=MIN_ZERO_CHECKER, 

266 comment="Paternal separation, how long first separation (y)", 

267 ) 

268 s1c_mother_separation_reason = CamcopsColumn( 

269 "s1c_mother_separation_reason", 

270 Integer, 

271 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6), 

272 comment="Maternal separation, reason " 

273 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, " 

274 "5 abandoned, 6 other)", 

275 ) 

276 s1c_father_separation_reason = CamcopsColumn( 

277 "s1c_father_separation_reason", 

278 Integer, 

279 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=6), 

280 comment="Paternal separation, reason " 

281 "(1 illness, 2 work, 3 divorce/separation, 4 never knew, " 

282 "5 abandoned, 6 other)", 

283 ) 

284 s1c_describe_experience = Column( 

285 "s1c_describe_experience", 

286 UnicodeText, 

287 comment="Loss of/separation from parent, description", 

288 ) 

289 

290 # ------------------------------------------------------------------------- 

291 # Section 2(A) 

292 # ------------------------------------------------------------------------- 

293 s2a_which_mother_figure = CamcopsColumn( 

294 "s2a_which_mother_figure", 

295 Integer, 

296 permitted_value_checker=PermittedValueChecker(minimum=0, maximum=5), 

297 comment="Mother figure, which one (0 none/skip, 1 birth mother, " 

298 "2 stepmother, 3 other relative, 4 other non-relative, " 

299 "5 other)", 

300 ) 

301 s2a_which_mother_figure_other_detail = Column( 

302 "s2a_which_mother_figure_other_detail", 

303 UnicodeText, 

304 comment="Mother figure, other, detail", 

305 ) 

306 s2a_q1 = CamcopsColumn( 

307 "s2a_q1", 

308 Integer, 

309 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

310 comment="Mother figure, difficult to please (1 no - 5 yes)", 

311 ) 

312 s2a_q2 = CamcopsColumn( 

313 "s2a_q2", 

314 Integer, 

315 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

316 comment="Mother figure, concerned re my worries (1 no - 5 yes)", 

317 ) 

318 s2a_q3 = CamcopsColumn( 

319 "s2a_q3", 

320 Integer, 

321 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

322 comment="Mother figure, interested re school (1 no - 5 yes)", 

323 ) 

324 s2a_q4 = CamcopsColumn( 

325 "s2a_q4", 

326 Integer, 

327 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

328 comment="Mother figure, made me feel unwanted (1 no - 5 yes)", 

329 ) 

330 s2a_q5 = CamcopsColumn( 

331 "s2a_q5", 

332 Integer, 

333 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

334 comment="Mother figure, better when upset (1 no - 5 yes)", 

335 ) 

336 s2a_q6 = CamcopsColumn( 

337 "s2a_q6", 

338 Integer, 

339 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

340 comment="Mother figure, critical (1 no - 5 yes)", 

341 ) 

342 s2a_q7 = CamcopsColumn( 

343 "s2a_q7", 

344 Integer, 

345 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

346 comment="Mother figure, unsupervised <10y (1 no - 5 yes)", 

347 ) 

348 s2a_q8 = CamcopsColumn( 

349 "s2a_q8", 

350 Integer, 

351 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

352 comment="Mother figure, time to talk (1 no - 5 yes)", 

353 ) 

354 s2a_q9 = CamcopsColumn( 

355 "s2a_q9", 

356 Integer, 

357 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

358 comment="Mother figure, nuisance (1 no - 5 yes)", 

359 ) 

360 s2a_q10 = CamcopsColumn( 

361 "s2a_q10", 

362 Integer, 

363 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

364 comment="Mother figure, picked on unfairly (1 no - 5 yes)", 

365 ) 

366 s2a_q11 = CamcopsColumn( 

367 "s2a_q11", 

368 Integer, 

369 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

370 comment="Mother figure, there if needed (1 no - 5 yes)", 

371 ) 

372 s2a_q12 = CamcopsColumn( 

373 "s2a_q12", 

374 Integer, 

375 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

376 comment="Mother figure, interested in friends (1 no - 5 yes)", 

377 ) 

378 s2a_q13 = CamcopsColumn( 

379 "s2a_q13", 

380 Integer, 

381 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

382 comment="Mother figure, concerned re whereabouts (1 no - 5 yes)", 

383 ) 

384 s2a_q14 = CamcopsColumn( 

385 "s2a_q14", 

386 Integer, 

387 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

388 comment="Mother figure, cared when ill (1 no - 5 yes)", 

389 ) 

390 s2a_q15 = CamcopsColumn( 

391 "s2a_q15", 

392 Integer, 

393 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

394 comment="Mother figure, neglected basic needs (1 no - 5 yes)", 

395 ) 

396 s2a_q16 = CamcopsColumn( 

397 "s2a_q16", 

398 Integer, 

399 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

400 comment="Mother figure, preferred siblings (1 no - 5 yes)", 

401 ) 

402 s2a_extra = Column( 

403 "s2a_extra", UnicodeText, comment="Mother figure, extra detail" 

404 ) 

405 

406 # ------------------------------------------------------------------------- 

407 # Section 2(B) 

408 # ------------------------------------------------------------------------- 

409 s2b_q1 = CamcopsColumn( 

410 "s2b_q1", 

411 Integer, 

412 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

413 comment="Mother figure, tease me (0 no - 2 yes)", 

414 ) 

415 s2b_q2 = CamcopsColumn( 

416 "s2b_q2", 

417 Integer, 

418 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

419 comment="Mother figure, made me keep secrets (0 no - 2 yes)", 

420 ) 

421 s2b_q3 = CamcopsColumn( 

422 "s2b_q3", 

423 Integer, 

424 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

425 comment="Mother figure, undermined confidence (0 no - 2 yes)", 

426 ) 

427 s2b_q4 = CamcopsColumn( 

428 "s2b_q4", 

429 Integer, 

430 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

431 comment="Mother figure, contradictory (0 no - 2 yes)", 

432 ) 

433 s2b_q5 = CamcopsColumn( 

434 "s2b_q5", 

435 Integer, 

436 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

437 comment="Mother figure, played on fears (0 no - 2 yes)", 

438 ) 

439 s2b_q6 = CamcopsColumn( 

440 "s2b_q6", 

441 Integer, 

442 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

443 comment="Mother figure, liked to see me suffer (0 no - 2 yes)", 

444 ) 

445 s2b_q7 = CamcopsColumn( 

446 "s2b_q7", 

447 Integer, 

448 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

449 comment="Mother figure, humiliated me (0 no - 2 yes)", 

450 ) 

451 s2b_q8 = CamcopsColumn( 

452 "s2b_q8", 

453 Integer, 

454 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

455 comment="Mother figure, shamed me before others (0 no - 2 yes)", 

456 ) 

457 s2b_q9 = CamcopsColumn( 

458 "s2b_q9", 

459 Integer, 

460 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

461 comment="Mother figure, rejecting (0 no - 2 yes)", 

462 ) 

463 s2b_q10 = CamcopsColumn( 

464 "s2b_q10", 

465 Integer, 

466 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

467 comment="Mother figure, took things I cherished (0 no - 2 yes)", 

468 ) 

469 s2b_q11 = CamcopsColumn( 

470 "s2b_q11", 

471 Integer, 

472 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

473 comment="Mother figure, eat disliked until sick (0 no - 2 yes)", 

474 ) 

475 s2b_q12 = CamcopsColumn( 

476 "s2b_q12", 

477 Integer, 

478 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

479 comment="Mother figure, deprived light/food/company (0 no - 2 yes)", 

480 ) 

481 s2b_q13 = CamcopsColumn( 

482 "s2b_q13", 

483 Integer, 

484 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

485 comment="Mother figure, wouldn't let me mix (0 no - 2 yes)", 

486 ) 

487 s2b_q14 = CamcopsColumn( 

488 "s2b_q14", 

489 Integer, 

490 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

491 comment="Mother figure, obedience through guilt (0 no - 2 yes)", 

492 ) 

493 s2b_q15 = CamcopsColumn( 

494 "s2b_q15", 

495 Integer, 

496 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

497 comment="Mother figure, threatened to hurt people dear to me " 

498 "(0 no - 2 yes)", 

499 ) 

500 s2b_q16 = CamcopsColumn( 

501 "s2b_q16", 

502 Integer, 

503 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

504 comment="Mother figure, forced to break law (0 no - 2 yes)", 

505 ) 

506 s2b_q17 = CamcopsColumn( 

507 "s2b_q17", 

508 Integer, 

509 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

510 comment="Mother figure, said wanted me dead (0 no - 2 yes)", 

511 ) 

512 s2b_q1_frequency = CamcopsColumn( 

513 "s2b_q1_frequency", 

514 Integer, 

515 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

516 comment=FREQUENCY_COMMENT, 

517 ) 

518 s2b_q2_frequency = CamcopsColumn( 

519 "s2b_q2_frequency", 

520 Integer, 

521 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

522 comment=FREQUENCY_COMMENT, 

523 ) 

524 s2b_q3_frequency = CamcopsColumn( 

525 "s2b_q3_frequency", 

526 Integer, 

527 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

528 comment=FREQUENCY_COMMENT, 

529 ) 

530 s2b_q4_frequency = CamcopsColumn( 

531 "s2b_q4_frequency", 

532 Integer, 

533 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

534 comment=FREQUENCY_COMMENT, 

535 ) 

536 s2b_q5_frequency = CamcopsColumn( 

537 "s2b_q5_frequency", 

538 Integer, 

539 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

540 comment=FREQUENCY_COMMENT, 

541 ) 

542 s2b_q6_frequency = CamcopsColumn( 

543 "s2b_q6_frequency", 

544 Integer, 

545 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

546 comment=FREQUENCY_COMMENT, 

547 ) 

548 s2b_q7_frequency = CamcopsColumn( 

549 "s2b_q7_frequency", 

550 Integer, 

551 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

552 comment=FREQUENCY_COMMENT, 

553 ) 

554 s2b_q8_frequency = CamcopsColumn( 

555 "s2b_q8_frequency", 

556 Integer, 

557 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

558 comment=FREQUENCY_COMMENT, 

559 ) 

560 s2b_q9_frequency = CamcopsColumn( 

561 "s2b_q9_frequency", 

562 Integer, 

563 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

564 comment=FREQUENCY_COMMENT, 

565 ) 

566 s2b_q10_frequency = CamcopsColumn( 

567 "s2b_q10_frequency", 

568 Integer, 

569 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

570 comment=FREQUENCY_COMMENT, 

571 ) 

572 s2b_q11_frequency = CamcopsColumn( 

573 "s2b_q11_frequency", 

574 Integer, 

575 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

576 comment=FREQUENCY_COMMENT, 

577 ) 

578 s2b_q12_frequency = CamcopsColumn( 

579 "s2b_q12_frequency", 

580 Integer, 

581 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

582 comment=FREQUENCY_COMMENT, 

583 ) 

584 s2b_q13_frequency = CamcopsColumn( 

585 "s2b_q13_frequency", 

586 Integer, 

587 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

588 comment=FREQUENCY_COMMENT, 

589 ) 

590 s2b_q14_frequency = CamcopsColumn( 

591 "s2b_q14_frequency", 

592 Integer, 

593 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

594 comment=FREQUENCY_COMMENT, 

595 ) 

596 s2b_q15_frequency = CamcopsColumn( 

597 "s2b_q15_frequency", 

598 Integer, 

599 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

600 comment=FREQUENCY_COMMENT, 

601 ) 

602 s2b_q16_frequency = CamcopsColumn( 

603 "s2b_q16_frequency", 

604 Integer, 

605 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

606 comment=FREQUENCY_COMMENT, 

607 ) 

608 s2b_q17_frequency = CamcopsColumn( 

609 "s2b_q17_frequency", 

610 Integer, 

611 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

612 comment=FREQUENCY_COMMENT, 

613 ) 

614 s2b_age_began = CamcopsColumn( 

615 "s2b_age_began", 

616 Float, 

617 permitted_value_checker=MIN_ZERO_CHECKER, 

618 comment="Age these experienced began (years)", 

619 ) 

620 s2b_extra = Column("s2b_extra", UnicodeText, comment="Extra detail") 

621 

622 # ------------------------------------------------------------------------- 

623 # Section 3(A) 

624 # ------------------------------------------------------------------------- 

625 s3a_which_father_figure = CamcopsColumn( 

626 "s3a_which_father_figure", 

627 Integer, 

628 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

629 comment="Father figure, which one (0 none/skip, 1 birth father, " 

630 "2 stepfather, 3 other relative, 4 other non-relative, " 

631 "5 other)", 

632 ) 

633 s3a_which_father_figure_other_detail = Column( 

634 "s3a_which_father_figure_other_detail", 

635 UnicodeText, 

636 comment="Father figure, other, detail", 

637 ) 

638 s3a_q1 = CamcopsColumn( 

639 "s3a_q1", 

640 Integer, 

641 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

642 comment="Father figure, difficult to please (1 no - 5 yes)", 

643 ) 

644 s3a_q2 = CamcopsColumn( 

645 "s3a_q2", 

646 Integer, 

647 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

648 comment="Father figure, concerned re my worries (1 no - 5 yes)", 

649 ) 

650 s3a_q3 = CamcopsColumn( 

651 "s3a_q3", 

652 Integer, 

653 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

654 comment="Father figure, interested re school (1 no - 5 yes)", 

655 ) 

656 s3a_q4 = CamcopsColumn( 

657 "s3a_q4", 

658 Integer, 

659 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

660 comment="Father figure, made me feel unwanted (1 no - 5 yes)", 

661 ) 

662 s3a_q5 = CamcopsColumn( 

663 "s3a_q5", 

664 Integer, 

665 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

666 comment="Father figure, better when upset (1 no - 5 yes)", 

667 ) 

668 s3a_q6 = CamcopsColumn( 

669 "s3a_q6", 

670 Integer, 

671 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

672 comment="Father figure, critical (1 no - 5 yes)", 

673 ) 

674 s3a_q7 = CamcopsColumn( 

675 "s3a_q7", 

676 Integer, 

677 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

678 comment="Father figure, unsupervised <10y (1 no - 5 yes)", 

679 ) 

680 s3a_q8 = CamcopsColumn( 

681 "s3a_q8", 

682 Integer, 

683 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

684 comment="Father figure, time to talk (1 no - 5 yes)", 

685 ) 

686 s3a_q9 = CamcopsColumn( 

687 "s3a_q9", 

688 Integer, 

689 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

690 comment="Father figure, nuisance (1 no - 5 yes)", 

691 ) 

692 s3a_q10 = CamcopsColumn( 

693 "s3a_q10", 

694 Integer, 

695 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

696 comment="Father figure, picked on unfairly (1 no - 5 yes)", 

697 ) 

698 s3a_q11 = CamcopsColumn( 

699 "s3a_q11", 

700 Integer, 

701 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

702 comment="Father figure, there if needed (1 no - 5 yes)", 

703 ) 

704 s3a_q12 = CamcopsColumn( 

705 "s3a_q12", 

706 Integer, 

707 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

708 comment="Father figure, interested in friends (1 no - 5 yes)", 

709 ) 

710 s3a_q13 = CamcopsColumn( 

711 "s3a_q13", 

712 Integer, 

713 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

714 comment="Father figure, concerned re whereabouts (1 no - 5 yes)", 

715 ) 

716 s3a_q14 = CamcopsColumn( 

717 "s3a_q14", 

718 Integer, 

719 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

720 comment="Father figure, cared when ill (1 no - 5 yes)", 

721 ) 

722 s3a_q15 = CamcopsColumn( 

723 "s3a_q15", 

724 Integer, 

725 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

726 comment="Father figure, neglected basic needs (1 no - 5 yes)", 

727 ) 

728 s3a_q16 = CamcopsColumn( 

729 "s3a_q16", 

730 Integer, 

731 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

732 comment="Father figure, preferred siblings (1 no - 5 yes)", 

733 ) 

734 s3a_extra = Column( 

735 "s3a_extra", UnicodeText, comment="Father figure, extra detail" 

736 ) 

737 

738 # ------------------------------------------------------------------------- 

739 # Section 3(B) 

740 # ------------------------------------------------------------------------- 

741 s3b_q1 = CamcopsColumn( 

742 "s3b_q1", 

743 Integer, 

744 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

745 comment="Father figure, tease me (0 no - 2 yes)", 

746 ) 

747 s3b_q2 = CamcopsColumn( 

748 "s3b_q2", 

749 Integer, 

750 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

751 comment="Father figure, made me keep secrets (0 no - 2 yes)", 

752 ) 

753 s3b_q3 = CamcopsColumn( 

754 "s3b_q3", 

755 Integer, 

756 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

757 comment="Father figure, undermined confidence (0 no - 2 yes)", 

758 ) 

759 s3b_q4 = CamcopsColumn( 

760 "s3b_q4", 

761 Integer, 

762 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

763 comment="Father figure, contradictory (0 no - 2 yes)", 

764 ) 

765 s3b_q5 = CamcopsColumn( 

766 "s3b_q5", 

767 Integer, 

768 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

769 comment="Father figure, played on fears (0 no - 2 yes)", 

770 ) 

771 s3b_q6 = CamcopsColumn( 

772 "s3b_q6", 

773 Integer, 

774 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

775 comment="Father figure, liked to see me suffer (0 no - 2 yes)", 

776 ) 

777 s3b_q7 = CamcopsColumn( 

778 "s3b_q7", 

779 Integer, 

780 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

781 comment="Father figure, humiliated me (0 no - 2 yes)", 

782 ) 

783 s3b_q8 = CamcopsColumn( 

784 "s3b_q8", 

785 Integer, 

786 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

787 comment="Father figure, shamed me before others (0 no - 2 yes)", 

788 ) 

789 s3b_q9 = CamcopsColumn( 

790 "s3b_q9", 

791 Integer, 

792 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

793 comment="Father figure, rejecting (0 no - 2 yes)", 

794 ) 

795 s3b_q10 = CamcopsColumn( 

796 "s3b_q10", 

797 Integer, 

798 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

799 comment="Father figure, took things I cherished (0 no - 2 yes)", 

800 ) 

801 s3b_q11 = CamcopsColumn( 

802 "s3b_q11", 

803 Integer, 

804 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

805 comment="Father figure, eat disliked until sick (0 no - 2 yes)", 

806 ) 

807 s3b_q12 = CamcopsColumn( 

808 "s3b_q12", 

809 Integer, 

810 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

811 comment="Father figure, deprived light/food/company (0 no - 2 yes)", 

812 ) 

813 s3b_q13 = CamcopsColumn( 

814 "s3b_q13", 

815 Integer, 

816 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

817 comment="Father figure, wouldn't let me mix (0 no - 2 yes)", 

818 ) 

819 s3b_q14 = CamcopsColumn( 

820 "s3b_q14", 

821 Integer, 

822 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

823 comment="Father figure, obedience through guilt (0 no - 2 yes)", 

824 ) 

825 s3b_q15 = CamcopsColumn( 

826 "s3b_q15", 

827 Integer, 

828 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

829 comment="Father figure, threatened to hurt people dear to me " 

830 "(0 no - 2 yes)", 

831 ) 

832 s3b_q16 = CamcopsColumn( 

833 "s3b_q16", 

834 Integer, 

835 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

836 comment="Father figure, forced to break law (0 no - 2 yes)", 

837 ) 

838 s3b_q17 = CamcopsColumn( 

839 "s3b_q17", 

840 Integer, 

841 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

842 comment="Father figure, said wanted me dead (0 no - 2 yes)", 

843 ) 

844 s3b_q1_frequency = CamcopsColumn( 

845 "s3b_q1_frequency", 

846 Integer, 

847 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

848 comment=FREQUENCY_COMMENT, 

849 ) 

850 s3b_q2_frequency = CamcopsColumn( 

851 "s3b_q2_frequency", 

852 Integer, 

853 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

854 comment=FREQUENCY_COMMENT, 

855 ) 

856 s3b_q3_frequency = CamcopsColumn( 

857 "s3b_q3_frequency", 

858 Integer, 

859 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

860 comment=FREQUENCY_COMMENT, 

861 ) 

862 s3b_q4_frequency = CamcopsColumn( 

863 "s3b_q4_frequency", 

864 Integer, 

865 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

866 comment=FREQUENCY_COMMENT, 

867 ) 

868 s3b_q5_frequency = CamcopsColumn( 

869 "s3b_q5_frequency", 

870 Integer, 

871 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

872 comment=FREQUENCY_COMMENT, 

873 ) 

874 s3b_q6_frequency = CamcopsColumn( 

875 "s3b_q6_frequency", 

876 Integer, 

877 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

878 comment=FREQUENCY_COMMENT, 

879 ) 

880 s3b_q7_frequency = CamcopsColumn( 

881 "s3b_q7_frequency", 

882 Integer, 

883 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

884 comment=FREQUENCY_COMMENT, 

885 ) 

886 s3b_q8_frequency = CamcopsColumn( 

887 "s3b_q8_frequency", 

888 Integer, 

889 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

890 comment=FREQUENCY_COMMENT, 

891 ) 

892 s3b_q9_frequency = CamcopsColumn( 

893 "s3b_q9_frequency", 

894 Integer, 

895 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

896 comment=FREQUENCY_COMMENT, 

897 ) 

898 s3b_q10_frequency = CamcopsColumn( 

899 "s3b_q10_frequency", 

900 Integer, 

901 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

902 comment=FREQUENCY_COMMENT, 

903 ) 

904 s3b_q11_frequency = CamcopsColumn( 

905 "s3b_q11_frequency", 

906 Integer, 

907 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

908 comment=FREQUENCY_COMMENT, 

909 ) 

910 s3b_q12_frequency = CamcopsColumn( 

911 "s3b_q12_frequency", 

912 Integer, 

913 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

914 comment=FREQUENCY_COMMENT, 

915 ) 

916 s3b_q13_frequency = CamcopsColumn( 

917 "s3b_q13_frequency", 

918 Integer, 

919 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

920 comment=FREQUENCY_COMMENT, 

921 ) 

922 s3b_q14_frequency = CamcopsColumn( 

923 "s3b_q14_frequency", 

924 Integer, 

925 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

926 comment=FREQUENCY_COMMENT, 

927 ) 

928 s3b_q15_frequency = CamcopsColumn( 

929 "s3b_q15_frequency", 

930 Integer, 

931 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

932 comment=FREQUENCY_COMMENT, 

933 ) 

934 s3b_q16_frequency = CamcopsColumn( 

935 "s3b_q16_frequency", 

936 Integer, 

937 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

938 comment=FREQUENCY_COMMENT, 

939 ) 

940 s3b_q17_frequency = CamcopsColumn( 

941 "s3b_q17_frequency", 

942 Integer, 

943 permitted_value_checker=ZERO_TO_THREE_CHECKER, 

944 comment=FREQUENCY_COMMENT, 

945 ) 

946 s3b_age_began = CamcopsColumn( 

947 "s3b_age_began", 

948 Float, 

949 permitted_value_checker=MIN_ZERO_CHECKER, 

950 comment="Age these experienced began (years)", 

951 ) 

952 s3b_extra = Column("s3b_extra", UnicodeText, comment="Extra detail") 

953 

954 # ------------------------------------------------------------------------- 

955 # Section 3(C) 

956 # ------------------------------------------------------------------------- 

957 s3c_q1 = CamcopsColumn( 

958 "s3c_q1", 

959 Integer, 

960 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

961 comment="Responsibility (1 no - 5 yes)", 

962 ) 

963 s3c_q2 = CamcopsColumn( 

964 "s3c_q2", 

965 Integer, 

966 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

967 comment="Housework (1 no - 5 yes)", 

968 ) 

969 s3c_q3 = CamcopsColumn( 

970 "s3c_q3", 

971 Integer, 

972 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

973 comment="Look after young siblings (1 no - 5 yes)", 

974 ) 

975 s3c_q4 = CamcopsColumn( 

976 "s3c_q4", 

977 Integer, 

978 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

979 comment="Cooking/cleaning (1 no - 5 yes)", 

980 ) 

981 s3c_q5 = CamcopsColumn( 

982 "s3c_q5", 

983 Integer, 

984 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

985 comment="Miss school for domestic responsibilities (1 no - 5 yes)", 

986 ) 

987 s3c_q6 = CamcopsColumn( 

988 "s3c_q6", 

989 Integer, 

990 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

991 comment="Miss seeing friends for domestic responsibilities " 

992 "(1 no - 5 yes)", 

993 ) 

994 s3c_q7 = CamcopsColumn( 

995 "s3c_q7", 

996 Integer, 

997 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

998 comment="Parents said they couldn't cope (1 no - 5 yes)", 

999 ) 

1000 s3c_q8 = CamcopsColumn( 

1001 "s3c_q8", 

1002 Integer, 

1003 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1004 comment="Parents looked to you for help (1 no - 5 yes)", 

1005 ) 

1006 s3c_q9 = CamcopsColumn( 

1007 "s3c_q9", 

1008 Integer, 

1009 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1010 comment="Parents coped if you were hurt/ill (1 no - 5 yes)", 

1011 ) 

1012 s3c_q10 = CamcopsColumn( 

1013 "s3c_q10", 

1014 Integer, 

1015 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1016 comment="Parents confided their problems (1 no - 5 yes)", 

1017 ) 

1018 s3c_q11 = CamcopsColumn( 

1019 "s3c_q11", 

1020 Integer, 

1021 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1022 comment="Parents relied on you for emotional support (1 no - 5 yes)", 

1023 ) 

1024 s3c_q12 = CamcopsColumn( 

1025 "s3c_q12", 

1026 Integer, 

1027 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1028 comment="Parents cried in front of you (1 no - 5 yes)", 

1029 ) 

1030 s3c_q13 = CamcopsColumn( 

1031 "s3c_q13", 

1032 Integer, 

1033 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1034 comment="Concerned/worried re parent (1 no - 5 yes)", 

1035 ) 

1036 s3c_q14 = CamcopsColumn( 

1037 "s3c_q14", 

1038 Integer, 

1039 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1040 comment="Tried to support/care for parent (1 no - 5 yes)", 

1041 ) 

1042 s3c_q15 = CamcopsColumn( 

1043 "s3c_q15", 

1044 Integer, 

1045 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1046 comment="Try to make parent smile when upset (1 no - 5 yes)", 

1047 ) 

1048 s3c_q16 = CamcopsColumn( 

1049 "s3c_q16", 

1050 Integer, 

1051 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1052 comment="Parents made you feel guilty for their sacrifices " 

1053 "(1 no - 5 yes)", 

1054 ) 

1055 s3c_q17 = CamcopsColumn( 

1056 "s3c_q17", 

1057 Integer, 

1058 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

1059 comment="Had to keep secrets for parent (1 no - 5 yes)", 

1060 ) 

1061 s3c_which_parent_cared_for = CamcopsColumn( 

1062 "s3c_which_parent_cared_for", 

1063 Integer, 

1064 permitted_value_checker=ZERO_TO_FOUR_CHECKER, 

1065 comment="Which parent did you have to provide care for (0 none, " 

1066 "1 mother, 2 father, 3 both, 4 other)", 

1067 ) 

1068 s3c_parent_mental_problem = CamcopsColumn( 

1069 "s3c_parent_mental_problem", 

1070 Integer, 

1071 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1072 comment="Parent/s had emotional/mental health problems (0 no - 2 yes)", 

1073 ) 

1074 s3c_parent_physical_problem = CamcopsColumn( 

1075 "s3c_parent_physical_problem", 

1076 Integer, 

1077 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1078 comment="Parent/s had disability/physical illness (0 no - 2 yes)", 

1079 ) 

1080 

1081 # ------------------------------------------------------------------------- 

1082 # Section 4(A) 

1083 # ------------------------------------------------------------------------- 

1084 s4a_adultconfidant = CamcopsColumn( 

1085 "s4a_adultconfidant", 

1086 Boolean, 

1087 permitted_value_checker=BIT_CHECKER, 

1088 comment="Adult confidant?", 

1089 ) 

1090 s4a_adultconfidant_mother = CamcopsColumn( 

1091 "s4a_adultconfidant_mother", 

1092 Boolean, 

1093 permitted_value_checker=BIT_CHECKER, 

1094 comment="Adult confidant, mother?", 

1095 ) 

1096 s4a_adultconfidant_father = CamcopsColumn( 

1097 "s4a_adultconfidant_father", 

1098 Boolean, 

1099 permitted_value_checker=BIT_CHECKER, 

1100 comment="Adult confidant, father?", 

1101 ) 

1102 s4a_adultconfidant_otherrelative = CamcopsColumn( 

1103 "s4a_adultconfidant_otherrelative", 

1104 Boolean, 

1105 permitted_value_checker=BIT_CHECKER, 

1106 comment="Adult confidant, other relative?", 

1107 ) 

1108 s4a_adultconfidant_familyfriend = CamcopsColumn( 

1109 "s4a_adultconfidant_familyfriend", 

1110 Boolean, 

1111 permitted_value_checker=BIT_CHECKER, 

1112 comment="Adult confidant, family friend?", 

1113 ) 

1114 s4a_adultconfidant_responsibleadult = CamcopsColumn( 

1115 "s4a_adultconfidant_responsibleadult", 

1116 Boolean, 

1117 permitted_value_checker=BIT_CHECKER, 

1118 comment="Adult confidant, teacher/vicar/etc.?", 

1119 ) 

1120 s4a_adultconfidant_other = CamcopsColumn( 

1121 "s4a_adultconfidant_other", 

1122 Boolean, 

1123 permitted_value_checker=BIT_CHECKER, 

1124 comment="Adult confidant, other?", 

1125 ) 

1126 s4a_adultconfidant_other_detail = Column( 

1127 "s4a_adultconfidant_other_detail", 

1128 UnicodeText, 

1129 comment="Adult confidant, other, detail", 

1130 ) 

1131 s4a_adultconfidant_additional = Column( 

1132 "s4a_adultconfidant_additional", 

1133 UnicodeText, 

1134 comment="Adult confidant, additional notes", 

1135 ) 

1136 

1137 # ------------------------------------------------------------------------- 

1138 # Section 4(B) 

1139 # ------------------------------------------------------------------------- 

1140 s4b_childconfidant = CamcopsColumn( 

1141 "s4b_childconfidant", 

1142 Boolean, 

1143 permitted_value_checker=BIT_CHECKER, 

1144 comment="Child confidant?", 

1145 ) 

1146 s4b_childconfidant_sister = CamcopsColumn( 

1147 "s4b_childconfidant_sister", 

1148 Boolean, 

1149 permitted_value_checker=BIT_CHECKER, 

1150 comment="Child confidant, sister?", 

1151 ) 

1152 s4b_childconfidant_brother = CamcopsColumn( 

1153 "s4b_childconfidant_brother", 

1154 Boolean, 

1155 permitted_value_checker=BIT_CHECKER, 

1156 comment="Child confidant, brother?", 

1157 ) 

1158 s4b_childconfidant_otherrelative = CamcopsColumn( 

1159 "s4b_childconfidant_otherrelative", 

1160 Boolean, 

1161 permitted_value_checker=BIT_CHECKER, 

1162 comment="Child confidant, other relative?", 

1163 ) 

1164 s4b_childconfidant_closefriend = CamcopsColumn( 

1165 "s4b_childconfidant_closefriend", 

1166 Boolean, 

1167 permitted_value_checker=BIT_CHECKER, 

1168 comment="Child confidant, close friend?", 

1169 ) 

1170 s4b_childconfidant_otherfriend = CamcopsColumn( 

1171 "s4b_childconfidant_otherfriend", 

1172 Boolean, 

1173 permitted_value_checker=BIT_CHECKER, 

1174 comment="Child confidant, other less close friend(s)?", 

1175 ) 

1176 s4b_childconfidant_other = CamcopsColumn( 

1177 "s4b_childconfidant_other", 

1178 Boolean, 

1179 permitted_value_checker=BIT_CHECKER, 

1180 comment="Child confidant, other person?", 

1181 ) 

1182 s4b_childconfidant_other_detail = Column( 

1183 "s4b_childconfidant_other_detail", 

1184 UnicodeText, 

1185 comment="Child confidant, other person, detail", 

1186 ) 

1187 s4b_childconfidant_additional = Column( 

1188 "s4b_childconfidant_additional", 

1189 UnicodeText, 

1190 comment="Child confidant, additional notes", 

1191 ) 

1192 

1193 # ------------------------------------------------------------------------- 

1194 # Section 4(C) 

1195 # ------------------------------------------------------------------------- 

1196 s4c_closest_mother = CamcopsColumn( 

1197 "s4c_closest_mother", 

1198 Boolean, 

1199 permitted_value_checker=BIT_CHECKER, 

1200 comment="Two closest people include: mother?", 

1201 ) 

1202 s4c_closest_father = CamcopsColumn( 

1203 "s4c_closest_father", 

1204 Boolean, 

1205 permitted_value_checker=BIT_CHECKER, 

1206 comment="Two closest people include: father?", 

1207 ) 

1208 s4c_closest_sibling = CamcopsColumn( 

1209 "s4c_closest_sibling", 

1210 Boolean, 

1211 permitted_value_checker=BIT_CHECKER, 

1212 comment="Two closest people include: sibling?", 

1213 ) 

1214 s4c_closest_otherrelative = CamcopsColumn( 

1215 "s4c_closest_otherrelative", 

1216 Boolean, 

1217 permitted_value_checker=BIT_CHECKER, 

1218 comment="Two closest people include: other relative?", 

1219 ) 

1220 s4c_closest_adultfriend = CamcopsColumn( 

1221 "s4c_closest_adultfriend", 

1222 Boolean, 

1223 permitted_value_checker=BIT_CHECKER, 

1224 comment="Two closest people include: adult family friend?", 

1225 ) 

1226 s4c_closest_childfriend = CamcopsColumn( 

1227 "s4c_closest_childfriend", 

1228 Boolean, 

1229 permitted_value_checker=BIT_CHECKER, 

1230 comment="Two closest people include: friend your age?", 

1231 ) 

1232 s4c_closest_other = CamcopsColumn( 

1233 "s4c_closest_other", 

1234 Boolean, 

1235 permitted_value_checker=BIT_CHECKER, 

1236 comment="Two closest people include: other?", 

1237 ) 

1238 s4c_closest_other_detail = Column( 

1239 "s4c_closest_other_detail", 

1240 UnicodeText, 

1241 comment="Two closest people include: other, detail", 

1242 ) 

1243 s4c_closest_additional = Column( 

1244 "s4c_closest_additional", 

1245 UnicodeText, 

1246 comment="Two closest people include: additional notes", 

1247 ) 

1248 

1249 # ------------------------------------------------------------------------- 

1250 # Section 5(C) 

1251 # ------------------------------------------------------------------------- 

1252 s5c_physicalabuse = CamcopsColumn( 

1253 "s5c_physicalabuse", 

1254 Boolean, 

1255 permitted_value_checker=BIT_CHECKER, 

1256 comment="Physical abuse?", 

1257 ) 

1258 s5c_abused_by_mother = CamcopsColumn( 

1259 "s5c_abused_by_mother", 

1260 Boolean, 

1261 permitted_value_checker=BIT_CHECKER, 

1262 comment="Physical abuse, by mother?", 

1263 ) 

1264 s5c_abused_by_father = CamcopsColumn( 

1265 "s5c_abused_by_father", 

1266 Boolean, 

1267 permitted_value_checker=BIT_CHECKER, 

1268 comment="Physical abuse, by father?", 

1269 ) 

1270 s5c_mother_abuse_age_began = CamcopsColumn( 

1271 "s5c_mother_abuse_age_began", 

1272 Float, 

1273 comment="Physical abuse, by mother, age began (y)", 

1274 ) 

1275 s5c_father_abuse_age_began = CamcopsColumn( 

1276 "s5c_father_abuse_age_began", 

1277 Float, 

1278 comment="Physical abuse, by father, age began (y)", 

1279 ) 

1280 s5c_mother_hit_more_than_once = CamcopsColumn( 

1281 "s5c_mother_hit_more_than_once", 

1282 Boolean, 

1283 permitted_value_checker=BIT_CHECKER, 

1284 comment="Physical abuse, by mother, hit on >1 occasion", 

1285 ) 

1286 s5c_father_hit_more_than_once = CamcopsColumn( 

1287 "s5c_father_hit_more_than_once", 

1288 Boolean, 

1289 permitted_value_checker=BIT_CHECKER, 

1290 comment="Physical abuse, by father, hit on >1 occasion", 

1291 ) 

1292 s5c_mother_hit_how = CamcopsColumn( 

1293 "s5c_mother_hit_how", 

1294 Integer, 

1295 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

1296 comment="Physical abuse, by mother, hit how (1 belt/stick, " 

1297 "2 punched/kicked, 3 hit with hand, 4 other)", 

1298 ) 

1299 s5c_father_hit_how = CamcopsColumn( 

1300 "s5c_father_hit_how", 

1301 Integer, 

1302 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

1303 comment="Physical abuse, by father, hit how (1 belt/stick, " 

1304 "2 punched/kicked, 3 hit with hand, 4 other)", 

1305 ) 

1306 s5c_mother_injured = CamcopsColumn( 

1307 "s5c_mother_injured", 

1308 Boolean, 

1309 permitted_value_checker=BIT_CHECKER, 

1310 comment="Physical abuse, by mother, injured?", 

1311 ) 

1312 s5c_father_injured = CamcopsColumn( 

1313 "s5c_father_injured", 

1314 Boolean, 

1315 permitted_value_checker=BIT_CHECKER, 

1316 comment="Physical abuse, by father, injured?", 

1317 ) 

1318 s5c_mother_out_of_control = CamcopsColumn( 

1319 "s5c_mother_out_of_control", 

1320 Boolean, 

1321 permitted_value_checker=BIT_CHECKER, 

1322 comment="Physical abuse, by mother, out of control?", 

1323 ) 

1324 s5c_father_out_of_control = CamcopsColumn( 

1325 "s5c_father_out_of_control", 

1326 Boolean, 

1327 permitted_value_checker=BIT_CHECKER, 

1328 comment="Physical abuse, by father, out of control?", 

1329 ) 

1330 s5c_parental_abuse_description = Column( 

1331 "s5c_parental_abuse_description", 

1332 UnicodeText, 

1333 comment="Physical abuse, description", 

1334 ) 

1335 s5c_abuse_by_nonparent = CamcopsColumn( 

1336 "s5c_abuse_by_nonparent", 

1337 Boolean, 

1338 permitted_value_checker=BIT_CHECKER, 

1339 comment="Physical abuse, by anyone else in household?", 

1340 ) 

1341 s5c_nonparent_abuse_description = Column( 

1342 "s5c_nonparent_abuse_description", 

1343 UnicodeText, 

1344 comment="Physical abuse, nonparent, description", 

1345 ) 

1346 

1347 # ------------------------------------------------------------------------- 

1348 # Section 6 

1349 # ------------------------------------------------------------------------- 

1350 s6_any_unwanted_sexual_experience = CamcopsColumn( 

1351 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1352 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1353 "s6_any_unwanted_sexual_experience", 

1354 Integer, 

1355 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1356 comment="Any unwanted sexual experiences (0 no - 2 yes)", 

1357 ) 

1358 s6_unwanted_intercourse = CamcopsColumn( 

1359 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1360 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1361 "s6_unwanted_intercourse", 

1362 Integer, 

1363 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1364 comment="Unwanted intercourse before 17yo (0 no - 2 yes)", 

1365 ) 

1366 s6_upsetting_sexual_adult_authority = CamcopsColumn( 

1367 # Prior to 2.1.0: was cctype="BOOL" on the server, but this gave 

1368 # TINYINT(1), which can store -128 to 128. Corrected to Integer. 

1369 "s6_upsetting_sexual_adult_authority", 

1370 Integer, 

1371 permitted_value_checker=ZERO_TO_TWO_CHECKER, 

1372 comment="Upsetting sexual experiences under 17yo with " 

1373 "related adult or someone in authority (0 no - 2 yes)", 

1374 ) 

1375 s6_first_age = CamcopsColumn( 

1376 "s6_first_age", 

1377 Float, 

1378 permitted_value_checker=MIN_ZERO_CHECKER, 

1379 comment="Sexual abuse, first experience, age it began", 

1380 ) 

1381 s6_other_age = CamcopsColumn( 

1382 "s6_other_age", 

1383 Float, 

1384 permitted_value_checker=MIN_ZERO_CHECKER, 

1385 comment="Sexual abuse, other experience, age it began", 

1386 ) 

1387 s6_first_person_known = CamcopsColumn( 

1388 "s6_first_person_known", 

1389 Boolean, 

1390 permitted_value_checker=BIT_CHECKER, 

1391 comment="Sexual abuse, first experience, knew the person?", 

1392 ) 

1393 s6_other_person_known = CamcopsColumn( 

1394 "s6_other_person_known", 

1395 Boolean, 

1396 permitted_value_checker=BIT_CHECKER, 

1397 comment="Sexual abuse, other experience, knew the person?", 

1398 ) 

1399 s6_first_relative = CamcopsColumn( 

1400 "s6_first_relative", 

1401 Boolean, 

1402 permitted_value_checker=BIT_CHECKER, 

1403 comment="Sexual abuse, first experience, person was a relative?", 

1404 ) 

1405 s6_other_relative = CamcopsColumn( 

1406 "s6_other_relative", 

1407 Boolean, 

1408 permitted_value_checker=BIT_CHECKER, 

1409 comment="Sexual abuse, other experience, person was a relative?", 

1410 ) 

1411 s6_first_in_household = CamcopsColumn( 

1412 "s6_first_in_household", 

1413 Boolean, 

1414 permitted_value_checker=BIT_CHECKER, 

1415 comment="Sexual abuse, first experience, person lived in household?", 

1416 ) 

1417 s6_other_in_household = CamcopsColumn( 

1418 "s6_other_in_household", 

1419 Boolean, 

1420 permitted_value_checker=BIT_CHECKER, 

1421 comment="Sexual abuse, other experience, person lived in household?", 

1422 ) 

1423 s6_first_more_than_once = CamcopsColumn( 

1424 "s6_first_more_than_once", 

1425 Boolean, 

1426 permitted_value_checker=BIT_CHECKER, 

1427 comment="Sexual abuse, first experience, happened more than once?", 

1428 ) 

1429 s6_other_more_than_once = CamcopsColumn( 

1430 "s6_other_more_than_once", 

1431 Boolean, 

1432 permitted_value_checker=BIT_CHECKER, 

1433 comment="Sexual abuse, other experience, happened more than once?", 

1434 ) 

1435 s6_first_touch_privates_subject = CamcopsColumn( 

1436 "s6_first_touch_privates_subject", 

1437 Boolean, 

1438 permitted_value_checker=BIT_CHECKER, 

1439 comment="Sexual abuse, first experience, touched your private parts?", 

1440 ) 

1441 s6_other_touch_privates_subject = CamcopsColumn( 

1442 "s6_other_touch_privates_subject", 

1443 Boolean, 

1444 permitted_value_checker=BIT_CHECKER, 

1445 comment="Sexual abuse, other experience, touched your private parts?", 

1446 ) 

1447 s6_first_touch_privates_other = CamcopsColumn( 

1448 "s6_first_touch_privates_other", 

1449 Boolean, 

1450 permitted_value_checker=BIT_CHECKER, 

1451 comment="Sexual abuse, first experience, touched their private parts?", 

1452 ) 

1453 s6_other_touch_privates_other = CamcopsColumn( 

1454 "s6_other_touch_privates_other", 

1455 Boolean, 

1456 permitted_value_checker=BIT_CHECKER, 

1457 comment="Sexual abuse, other experience, touched their private parts?", 

1458 ) 

1459 s6_first_intercourse = CamcopsColumn( 

1460 "s6_first_intercourse", 

1461 Boolean, 

1462 permitted_value_checker=BIT_CHECKER, 

1463 comment="Sexual abuse, first experience, sexual intercourse?", 

1464 ) 

1465 s6_other_intercourse = CamcopsColumn( 

1466 "s6_other_intercourse", 

1467 Boolean, 

1468 permitted_value_checker=BIT_CHECKER, 

1469 comment="Sexual abuse, other experience, sexual intercourse?", 

1470 ) 

1471 s6_unwanted_sexual_description = Column( 

1472 "s6_unwanted_sexual_description", 

1473 UnicodeText, 

1474 comment="Sexual abuse, description", 

1475 ) 

1476 

1477 # ------------------------------------------------------------------------- 

1478 # Final 

1479 # ------------------------------------------------------------------------- 

1480 any_other_comments = CamcopsColumn( 

1481 "any_other_comments", UnicodeText, comment="Any other comments" 

1482 ) 

1483 

1484 @staticmethod 

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

1486 _ = req.gettext 

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

1488 

1489 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]: 

1490 return self.standard_task_summary_fields() + [ 

1491 SummaryElement( 

1492 name="parental_loss_risk", 

1493 coltype=Boolean(), 

1494 value=self.parental_loss_risk(), 

1495 comment="Parental loss risk factor?", 

1496 ), 

1497 SummaryElement( 

1498 name="parental_loss_high_risk", 

1499 coltype=Boolean(), 

1500 value=self.parental_loss_high_risk(), 

1501 comment="Parental loss higher risk factor?", 

1502 ), 

1503 SummaryElement( 

1504 name="mother_antipathy", 

1505 coltype=Integer(), 

1506 value=self.mother_antipathy(), 

1507 comment="Maternal antipathy score (8-40)", 

1508 ), 

1509 SummaryElement( 

1510 name="mother_neglect", 

1511 coltype=Integer(), 

1512 value=self.mother_neglect(), 

1513 comment="Maternal neglect score (8-40)", 

1514 ), 

1515 SummaryElement( 

1516 name="mother_psychological_abuse", 

1517 coltype=Integer(), 

1518 value=self.mother_psychological_abuse(), 

1519 comment="Maternal psychological abuse score (0-85)", 

1520 ), 

1521 SummaryElement( 

1522 name="father_antipathy", 

1523 coltype=Integer(), 

1524 value=self.father_antipathy(), 

1525 comment="Paternal antipathy score (8-40)", 

1526 ), 

1527 SummaryElement( 

1528 name="father_neglect", 

1529 coltype=Integer(), 

1530 value=self.father_neglect(), 

1531 comment="Paternal neglect score (8-40)", 

1532 ), 

1533 SummaryElement( 

1534 name="father_psychological_abuse", 

1535 coltype=Integer(), 

1536 value=self.father_psychological_abuse(), 

1537 comment="Paternal psychological abuse score (0-85)", 

1538 ), 

1539 SummaryElement( 

1540 name="role_reversal", 

1541 coltype=Integer(), 

1542 value=self.role_reversal(), 

1543 comment="Role reversal score (17-85)", 

1544 ), 

1545 SummaryElement( 

1546 name="physical_abuse_screen", 

1547 coltype=Integer(), 

1548 value=self.physical_abuse_screen(), 

1549 comment="Physical abuse screen (0-1)", 

1550 ), 

1551 SummaryElement( 

1552 name="physical_abuse_severity_mother", 

1553 coltype=Integer(), 

1554 value=self.physical_abuse_severity_mother(), 

1555 comment="Maternal physical abuse severity score (0-4)", 

1556 ), 

1557 SummaryElement( 

1558 name="physical_abuse_severity_father", 

1559 coltype=Integer(), 

1560 value=self.physical_abuse_severity_father(), 

1561 comment="Paternal physical abuse severity score (0-4)", 

1562 ), 

1563 SummaryElement( 

1564 name="sexual_abuse_screen", 

1565 coltype=Integer(), 

1566 value=self.sexual_abuse_screen(), 

1567 comment="Sexual abuse screen (0-3)", 

1568 ), 

1569 SummaryElement( 

1570 name="sexual_abuse_score_first", 

1571 coltype=Integer(), 

1572 value=self.sexual_abuse_score_first(), 

1573 comment="First sexual abuse severity score (0-7)", 

1574 ), 

1575 SummaryElement( 

1576 name="sexual_abuse_score_other", 

1577 coltype=Integer(), 

1578 value=self.sexual_abuse_score_other(), 

1579 comment="Other sexual abuse severity score (0-7)", 

1580 ), 

1581 ] 

1582 

1583 # ------------------------------------------------------------------------- 

1584 # Complete? 

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

1586 

1587 def is_complete(self) -> bool: 

1588 return ( 

1589 self.complete_1a() 

1590 and self.complete_1b() 

1591 and self.complete_1c() 

1592 and self.complete_2a() 

1593 and self.complete_2b() 

1594 and self.complete_3a() 

1595 and self.complete_3b() 

1596 and self.complete_3c() 

1597 and self.complete_4a() 

1598 and self.complete_4b() 

1599 and self.complete_4c() 

1600 and self.complete_5() 

1601 and self.complete_6() 

1602 and self.field_contents_valid() 

1603 ) 

1604 

1605 def is_at_least_one_field_true(self, fields: List[str]) -> bool: 

1606 for f in fields: 

1607 if getattr(self, f): 

1608 return True 

1609 return True 

1610 

1611 def complete_1a(self) -> bool: 

1612 if not self.is_at_least_one_field_true( 

1613 [ 

1614 "s1a_motherfigure_birthmother", 

1615 "s1a_motherfigure_stepmother", 

1616 "s1a_motherfigure_femalerelative", 

1617 "s1a_motherfigure_familyfriend", 

1618 "s1a_motherfigure_fostermother", 

1619 "s1a_motherfigure_adoptivemother", 

1620 "s1a_motherfigure_other", 

1621 "s1a_fatherfigure_birthfather", 

1622 "s1a_fatherfigure_stepfather", 

1623 "s1a_fatherfigure_malerelative", 

1624 "s1a_fatherfigure_familyfriend", 

1625 "s1a_fatherfigure_fosterfather", 

1626 "s1a_fatherfigure_adoptivefather", 

1627 "s1a_fatherfigure_other", 

1628 ] 

1629 ): 

1630 return False 

1631 if ( 

1632 self.s1a_motherfigure_other 

1633 and not self.s1a_motherfigure_other_detail 

1634 ): 

1635 return False 

1636 if ( 

1637 self.s1a_motherfigure_femalerelative 

1638 and not self.s1a_motherfigure_femalerelative_detail 

1639 ): 

1640 return False 

1641 if ( 

1642 self.s1a_fatherfigure_other 

1643 and not self.s1a_fatherfigure_other_detail 

1644 ): 

1645 return False 

1646 if ( 

1647 self.s1a_fatherfigure_malerelative 

1648 and not self.s1a_fatherfigure_malerelative_detail 

1649 ): 

1650 return False 

1651 return True 

1652 

1653 def complete_1b(self) -> bool: 

1654 if self.s1b_institution is None: 

1655 return False 

1656 if self.s1b_institution and self.s1b_institution_time_years is None: 

1657 return False 

1658 return True 

1659 

1660 def complete_1c(self) -> bool: 

1661 if self.s1c_mother_died is None or self.s1c_father_died is None: 

1662 return False 

1663 if self.s1c_mother_died and self.s1c_mother_died_subject_aged is None: 

1664 return False 

1665 if self.s1c_father_died and self.s1c_father_died_subject_aged is None: 

1666 return False 

1667 if ( 

1668 self.s1c_separated_from_mother is None 

1669 or self.s1c_separated_from_father is None 

1670 ): 

1671 return False 

1672 if self.s1c_separated_from_mother: 

1673 if self.any_fields_none( 

1674 [ 

1675 "s1c_first_separated_from_mother_aged", 

1676 "s1c_mother_how_long_first_separation_years", # noqa 

1677 "s1c_mother_separation_reason", 

1678 ] 

1679 ): 

1680 return False 

1681 if self.s1c_separated_from_father: 

1682 if self.any_fields_none( 

1683 [ 

1684 "s1c_first_separated_from_father_aged", 

1685 "s1c_father_how_long_first_separation_years", # noqa 

1686 "s1c_father_separation_reason", 

1687 ] 

1688 ): 

1689 return False 

1690 return True 

1691 

1692 def complete_2a(self) -> bool: 

1693 if self.s2a_which_mother_figure is None: 

1694 return False 

1695 if self.s2a_which_mother_figure == 0: 

1696 return True 

1697 if ( 

1698 self.s2a_which_mother_figure == 5 

1699 and self.s2a_which_mother_figure_other_detail is None 

1700 ): 

1701 return False 

1702 for i in range(1, 16): # not q16 (siblings) 

1703 if getattr(self, "s2a_q" + str(i)) is None: 

1704 return False 

1705 return True 

1706 

1707 def complete_2b(self) -> bool: 

1708 abuse = False 

1709 if self.s2a_which_mother_figure == 0: 

1710 return True 

1711 for i in range(1, 18): 

1712 if getattr(self, "s2b_q" + str(i)) is None: 

1713 return False 

1714 if getattr(self, "s2b_q" + str(i)) != 0: 

1715 abuse = True 

1716 if getattr(self, "s2b_q" + str(i) + "_frequency") is None: 

1717 return False 

1718 if abuse and self.s2b_age_began is None: 

1719 return False 

1720 return True 

1721 

1722 def complete_3a(self): 

1723 if self.s3a_which_father_figure is None: 

1724 return False 

1725 if self.s3a_which_father_figure == 0: 

1726 return True 

1727 if ( 

1728 self.s3a_which_father_figure == 5 

1729 and self.s3a_which_father_figure_other_detail is None 

1730 ): 

1731 return False 

1732 for i in range(1, 16): # not q16 (siblings) 

1733 if getattr(self, "s3a_q" + str(i)) is None: 

1734 return False 

1735 return True 

1736 

1737 def complete_3b(self) -> bool: 

1738 abuse = False 

1739 if self.s3a_which_father_figure == 0: 

1740 return True 

1741 for i in range(1, 18): 

1742 if getattr(self, "s3b_q" + str(i)) is None: 

1743 return False 

1744 if getattr(self, "s3b_q" + str(i)) != 0: 

1745 abuse = True 

1746 if getattr(self, "s3b_q" + str(i) + "_frequency") is None: 

1747 return False 

1748 if abuse and self.s3b_age_began is None: 

1749 return False 

1750 return True 

1751 

1752 def complete_3c(self) -> bool: 

1753 return self.all_fields_not_none( 

1754 [ 

1755 "s3c_q1", 

1756 "s3c_q2", 

1757 "s3c_q3", 

1758 "s3c_q4", 

1759 "s3c_q5", 

1760 "s3c_q6", 

1761 "s3c_q7", 

1762 "s3c_q8", 

1763 "s3c_q9", 

1764 "s3c_q10", 

1765 "s3c_q11", 

1766 "s3c_q12", 

1767 "s3c_q13", 

1768 "s3c_q14", 

1769 "s3c_q15", 

1770 "s3c_q16", 

1771 "s3c_q17", 

1772 "s3c_which_parent_cared_for", 

1773 "s3c_parent_mental_problem", 

1774 "s3c_parent_physical_problem", 

1775 ] 

1776 ) 

1777 

1778 def complete_4a(self) -> bool: 

1779 if self.s4a_adultconfidant is None: 

1780 return False 

1781 if not self.s4a_adultconfidant: 

1782 return True 

1783 if not self.is_at_least_one_field_true( 

1784 [ 

1785 "s4a_adultconfidant_mother", 

1786 "s4a_adultconfidant_father", 

1787 "s4a_adultconfidant_otherrelative", 

1788 "s4a_adultconfidant_familyfriend", 

1789 "s4a_adultconfidant_responsibleadult", 

1790 "s4a_adultconfidant_other", 

1791 ] 

1792 ): 

1793 return False 

1794 if ( 

1795 self.s4a_adultconfidant_other 

1796 and not self.s4a_adultconfidant_other_detail 

1797 ): 

1798 return False 

1799 return True 

1800 

1801 def complete_4b(self) -> bool: 

1802 if self.s4b_childconfidant is None: 

1803 return False 

1804 if not self.s4b_childconfidant: 

1805 return True 

1806 if not self.is_at_least_one_field_true( 

1807 [ 

1808 "s4b_childconfidant_sister", 

1809 "s4b_childconfidant_brother", 

1810 "s4b_childconfidant_otherrelative", 

1811 "s4b_childconfidant_closefriend", 

1812 "s4b_childconfidant_otherfriend", 

1813 "s4b_childconfidant_other", 

1814 ] 

1815 ): 

1816 return False 

1817 if ( 

1818 self.s4b_childconfidant_other 

1819 and not self.s4b_childconfidant_other_detail 

1820 ): 

1821 return False 

1822 return True 

1823 

1824 def complete_4c(self) -> bool: 

1825 n = 0 

1826 if self.s4c_closest_mother: 

1827 n += 1 

1828 if self.s4c_closest_father: 

1829 n += 1 

1830 if self.s4c_closest_sibling: 

1831 n += 1 

1832 if self.s4c_closest_otherrelative: 

1833 n += 1 

1834 if self.s4c_closest_adultfriend: 

1835 n += 1 

1836 if self.s4c_closest_childfriend: 

1837 n += 1 

1838 if self.s4c_closest_other: 

1839 n += 1 

1840 if n < 2: 

1841 return False 

1842 if self.s4c_closest_other and not self.s4c_closest_other_detail: 

1843 return False 

1844 return True 

1845 

1846 def complete_5(self) -> bool: 

1847 if self.s5c_physicalabuse is None: 

1848 return False 

1849 if self.s5c_physicalabuse == 0: 

1850 return True 

1851 if ( 

1852 self.s5c_abused_by_mother is None 

1853 or self.s5c_abused_by_father is None 

1854 or self.s5c_abuse_by_nonparent is None 

1855 ): 

1856 return False 

1857 if self.s5c_abused_by_mother: 

1858 if self.any_fields_none( 

1859 [ 

1860 "s5c_mother_abuse_age_began", 

1861 "s5c_mother_hit_more_than_once", 

1862 "s5c_mother_hit_how", 

1863 "s5c_mother_injured", 

1864 "s5c_mother_out_of_control", 

1865 ] 

1866 ): 

1867 return False 

1868 if self.s5c_abused_by_father: 

1869 if self.any_fields_none( 

1870 [ 

1871 "s5c_father_abuse_age_began", 

1872 "s5c_father_hit_more_than_once", 

1873 "s5c_father_hit_how", 

1874 "s5c_father_injured", 

1875 "s5c_father_out_of_control", 

1876 ] 

1877 ): 

1878 return False 

1879 if ( 

1880 self.s5c_abuse_by_nonparent 

1881 and not self.s5c_nonparent_abuse_description 

1882 ): 

1883 return False 

1884 return True 

1885 

1886 def complete_6(self) -> bool: 

1887 if ( 

1888 self.s6_any_unwanted_sexual_experience is None 

1889 or self.s6_unwanted_intercourse is None 

1890 or self.s6_upsetting_sexual_adult_authority is None 

1891 ): 

1892 return False 

1893 if ( 

1894 self.s6_any_unwanted_sexual_experience == 0 

1895 and self.s6_unwanted_intercourse == 0 

1896 and self.s6_upsetting_sexual_adult_authority == 0 

1897 ): 

1898 return True 

1899 if self.any_fields_none( 

1900 [ 

1901 "s6_first_age", 

1902 "s6_first_person_known", 

1903 "s6_first_relative", 

1904 "s6_first_in_household", 

1905 "s6_first_more_than_once", 

1906 "s6_first_touch_privates_subject", 

1907 "s6_first_touch_privates_other", 

1908 "s6_first_intercourse", 

1909 ] 

1910 ): 

1911 return False 

1912 # no checks for "other experience" 

1913 return True 

1914 

1915 # ------------------------------------------------------------------------- 

1916 # Scoring 

1917 # ------------------------------------------------------------------------- 

1918 

1919 def total_sum_abort_if_none(self, fields: List[str]) -> Optional[int]: 

1920 total = 0 

1921 for field in fields: 

1922 value = getattr(self, field) 

1923 if value is None: 

1924 return None 

1925 total += value 

1926 return total 

1927 

1928 def total_nonzero_scores_1_abort_if_none( 

1929 self, fields: Sequence[str] 

1930 ) -> Optional[int]: 

1931 total = 0 

1932 for field in fields: 

1933 value = getattr(self, field) 

1934 if value is None: 

1935 return None 

1936 if value: 

1937 total += 1 

1938 return total 

1939 

1940 def parental_loss_risk(self) -> bool: 

1941 return bool( 

1942 self.s1c_mother_died 

1943 or self.s1c_father_died 

1944 or self.s1c_separated_from_mother 

1945 or self.s1c_separated_from_father 

1946 ) 

1947 

1948 def parental_loss_high_risk(self) -> bool: 

1949 return bool( 

1950 self.s1c_separated_from_mother 

1951 and ( 

1952 self.s1c_mother_separation_reason == 5 

1953 or self.s1c_mother_separation_reason == 6 

1954 ) 

1955 or self.s1c_separated_from_father 

1956 and ( 

1957 self.s1c_father_separation_reason == 5 

1958 or self.s1c_father_separation_reason == 6 

1959 ) 

1960 ) 

1961 

1962 def mother_antipathy(self) -> Optional[int]: 

1963 if self.s2a_which_mother_figure == 0: 

1964 return None 

1965 total = 0 

1966 for i in (1, 4, 6, 8, 9, 10, 11, 16): 

1967 score = getattr(self, "s2a_q" + str(i)) 

1968 if i == 16 and score is None: 

1969 # Q16 is allowed to be blank (if no siblings) 

1970 score = 0 

1971 if score is None: 

1972 return None 

1973 if i in (8, 11): 

1974 score = 6 - score # reverse 

1975 total += score 

1976 return total 

1977 

1978 def father_antipathy(self) -> Optional[int]: 

1979 if self.s3a_which_father_figure == 0: 

1980 return None 

1981 total = 0 

1982 for i in (1, 4, 6, 8, 9, 10, 11, 16): 

1983 score = getattr(self, "s3a_q" + str(i)) 

1984 if i == 16 and score is None: 

1985 # Q16 is allowed to be blank (if no siblings) 

1986 score = 0 

1987 if score is None: 

1988 return None 

1989 if i in (8, 11): 

1990 score = 6 - score # reverse 

1991 total += score 

1992 return total 

1993 

1994 def mother_neglect(self) -> Optional[int]: 

1995 if self.s2a_which_mother_figure == 0: 

1996 return None 

1997 total = 0 

1998 for i in (2, 3, 5, 7, 12, 13, 14, 15): 

1999 score = getattr(self, "s2a_q" + str(i)) 

2000 if score is None: 

2001 return None 

2002 if i in (2, 3, 5, 12, 13, 14): 

2003 score = 6 - score # reverse 

2004 total += score 

2005 return total 

2006 

2007 def father_neglect(self) -> Optional[int]: 

2008 if self.s3a_which_father_figure == 0: 

2009 return None 

2010 total = 0 

2011 for i in (2, 3, 5, 7, 12, 13, 14, 15): 

2012 score = getattr(self, "s3a_q" + str(i)) 

2013 if score is None: 

2014 return None 

2015 if i in (2, 3, 5, 12, 13, 14): 

2016 score = 6 - score # reverse 

2017 total += score 

2018 return total 

2019 

2020 def mother_psychological_abuse(self) -> Optional[int]: 

2021 if self.s2a_which_mother_figure == 0: 

2022 return None 

2023 total = 0 

2024 for i in range(1, 18): 

2025 score = getattr(self, "s2b_q" + str(i)) 

2026 if score is None: 

2027 return None 

2028 total += score 

2029 freqscore = getattr(self, "s2b_q" + str(i) + "_frequency") 

2030 if score != 0 and freqscore is None: 

2031 return None 

2032 if freqscore is not None: 

2033 total += freqscore 

2034 return total 

2035 

2036 def father_psychological_abuse(self) -> Optional[int]: 

2037 if self.s3a_which_father_figure == 0: 

2038 return None 

2039 total = 0 

2040 for i in range(1, 18): 

2041 score = getattr(self, "s3b_q" + str(i)) 

2042 if score is None: 

2043 return None 

2044 total += score 

2045 freqscore = getattr(self, "s3b_q" + str(i) + "_frequency") 

2046 if score != 0 and freqscore is None: 

2047 return None 

2048 if freqscore is not None: 

2049 total += freqscore 

2050 return total 

2051 

2052 def role_reversal(self) -> Optional[int]: 

2053 total = 0 

2054 for i in range(1, 18): 

2055 score = getattr(self, "s3c_q" + str(i)) 

2056 if score is None: 

2057 return None 

2058 total += score 

2059 return total 

2060 

2061 def physical_abuse_screen(self) -> Optional[int]: 

2062 fields = ( 

2063 "s5c_physicalabuse", 

2064 ) # tuple of length 1 -- requires the comma 

2065 return self.total_nonzero_scores_1_abort_if_none(fields) 

2066 

2067 def physical_abuse_severity_mother(self) -> Optional[int]: 

2068 if self.physical_abuse_screen() == 0: 

2069 return 0 

2070 if self.s5c_abused_by_mother == 0: 

2071 return 0 

2072 mainfields = ( 

2073 "s5c_mother_hit_more_than_once", 

2074 "s5c_mother_injured", 

2075 "s5c_mother_out_of_control", 

2076 ) 

2077 total = self.total_nonzero_scores_1_abort_if_none(mainfields) 

2078 if total is None: 

2079 return None 

2080 if self.s5c_mother_hit_how is None: 

2081 return None 

2082 if self.s5c_mother_hit_how == 1 or self.s5c_mother_hit_how == 2: 

2083 total += 1 

2084 return total 

2085 

2086 def physical_abuse_severity_father(self) -> Optional[int]: 

2087 if self.physical_abuse_screen() == 0: 

2088 return 0 

2089 if self.s5c_abused_by_father == 0: 

2090 return 0 

2091 mainfields = ( 

2092 "s5c_father_hit_more_than_once", 

2093 "s5c_father_injured", 

2094 "s5c_father_out_of_control", 

2095 ) 

2096 total = self.total_nonzero_scores_1_abort_if_none(mainfields) 

2097 if total is None: 

2098 return None 

2099 if self.s5c_father_hit_how is None: 

2100 return None 

2101 if self.s5c_father_hit_how == 1 or self.s5c_father_hit_how == 2: 

2102 total += 1 

2103 return total 

2104 

2105 def sexual_abuse_screen(self) -> Optional[int]: 

2106 fields = ( 

2107 "s6_any_unwanted_sexual_experience", 

2108 "s6_unwanted_intercourse", 

2109 "s6_upsetting_sexual_adult_authority", 

2110 ) 

2111 return self.total_nonzero_scores_1_abort_if_none(fields) 

2112 

2113 def sexual_abuse_score_first(self) -> Optional[int]: 

2114 if self.sexual_abuse_screen() == 0: 

2115 return 0 

2116 fields = ( 

2117 "s6_first_person_known", 

2118 "s6_first_relative", 

2119 "s6_first_in_household", 

2120 "s6_first_more_than_once", 

2121 "s6_first_touch_privates_subject", 

2122 "s6_first_touch_privates_other", 

2123 "s6_first_intercourse", 

2124 ) 

2125 return self.total_nonzero_scores_1_abort_if_none(fields) 

2126 

2127 def sexual_abuse_score_other(self) -> Optional[int]: 

2128 if self.sexual_abuse_screen() == 0: 

2129 return 0 

2130 fields = ( 

2131 "s6_other_person_known", 

2132 "s6_other_relative", 

2133 "s6_other_in_household", 

2134 "s6_other_more_than_once", 

2135 "s6_other_touch_privates_subject", 

2136 "s6_other_touch_privates_other", 

2137 "s6_other_intercourse", 

2138 ) 

2139 return self.total_nonzero_scores_1_abort_if_none(fields) 

2140 

2141 # ------------------------------------------------------------------------- 

2142 # HTML 

2143 # ------------------------------------------------------------------------- 

2144 

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

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

2147 return self.wxstring(req, wstringname) 

2148 

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

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

2151 

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

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

2154 

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

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

2157 

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

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

2160 

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

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

2163 

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

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

2166 

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

2168 return string_boolean_(req, string, value) 

2169 

2170 separation_map = { 

2171 None: None, 

2172 1: "1 — " + wxstring("1c_separation_reason1"), 

2173 2: "2 — " + wxstring("1c_separation_reason2"), 

2174 3: "3 — " + wxstring("1c_separation_reason3"), 

2175 4: "4 — " + wxstring("1c_separation_reason4"), 

2176 5: "5 — " + wxstring("1c_separation_reason5"), 

2177 6: "6 — " + wxstring("1c_separation_reason6"), 

2178 } 

2179 motherfigure_map = { 

2180 None: None, 

2181 0: "0 — " + wxstring("2a_which_option0"), 

2182 1: "1 — " + wxstring("2a_which_option1"), 

2183 2: "2 — " + wxstring("2a_which_option2"), 

2184 3: "3 — " + wxstring("2a_which_option3"), 

2185 4: "4 — " + wxstring("2a_which_option4"), 

2186 5: "5 — " + wxstring("2a_which_option5"), 

2187 } 

2188 fatherfigure_map = { 

2189 None: None, 

2190 0: "0 — " + wxstring("3a_which_option0"), 

2191 1: "1 — " + wxstring("3a_which_option1"), 

2192 2: "2 — " + wxstring("3a_which_option2"), 

2193 3: "3 — " + wxstring("3a_which_option3"), 

2194 4: "4 — " + wxstring("3a_which_option4"), 

2195 5: "5 — " + wxstring("3a_which_option5"), 

2196 } 

2197 no_yes_5way_map = { 

2198 None: None, 

2199 1: "1 — " + wxstring("options5way_notoyes_1"), 

2200 2: "2 — (between not-at-all and unsure)", 

2201 3: "3 — " + wxstring("options5way_notoyes_3"), 

2202 4: "4 — (between unsure and yes-definitely)", 

2203 5: "5 — " + wxstring("options5way_notoyes_5"), 

2204 } 

2205 no_yes_3way_map = { 

2206 None: None, 

2207 0: "0 — " + wxstring("options3way_noto_yes_0"), 

2208 1: "1 — " + wxstring("options3way_noto_yes_1"), 

2209 2: "2 — " + wxstring("options3way_noto_yes_2"), 

2210 } 

2211 frequency_map = { 

2212 None: None, 

2213 0: "0 — " + wxstring("optionsfrequency0"), 

2214 1: "1 — " + wxstring("optionsfrequency1"), 

2215 2: "2 — " + wxstring("optionsfrequency2"), 

2216 3: "3 — " + wxstring("optionsfrequency3"), 

2217 } 

2218 parent_cared_for_map = { 

2219 None: None, 

2220 0: "0 — " + wxstring("3c_whichparentcaredfor_option0"), 

2221 1: "1 — " + wxstring("3c_whichparentcaredfor_option1"), 

2222 2: "2 — " + wxstring("3c_whichparentcaredfor_option2"), 

2223 3: "3 — " + wxstring("3c_whichparentcaredfor_option3"), 

2224 4: "4 — " + wxstring("3c_whichparentcaredfor_option4"), 

2225 } 

2226 hitting_map = { 

2227 None: None, 

2228 1: "1 — " + wxstring("5_hit_option_1"), 

2229 2: "2 — " + wxstring("5_hit_option_2"), 

2230 3: "3 — " + wxstring("5_hit_option_3"), 

2231 4: "4 — " + wxstring("5_hit_option_4"), 

2232 } 

2233 html = ( 

2234 f""" 

2235 <div class="{CssClass.SUMMARY}"> 

2236 <table class="{CssClass.SUMMARY}"> 

2237 """ 

2238 + self.get_is_complete_tr(req) 

2239 + tr_qa( 

2240 "Parental loss risk factor? <sup>[1]</sup>", 

2241 get_yes_no(req, self.parental_loss_risk()), 

2242 ) 

2243 + tr_qa( 

2244 "Parental loss higher risk factor? <sup>[2]</sup>", 

2245 get_yes_no(req, self.parental_loss_high_risk()), 

2246 ) 

2247 + tr_qa( 

2248 "Maternal antipathy score (8–40) <sup>[3]</sup>", 

2249 self.mother_antipathy(), 

2250 ) 

2251 + tr_qa( 

2252 "Maternal neglect score (8–40) <sup>[3]</sup>", 

2253 self.mother_neglect(), 

2254 ) 

2255 + tr_qa( 

2256 "Maternal psychological abuse score (0–85) <sup>[4]</sup>", 

2257 self.mother_psychological_abuse(), 

2258 ) 

2259 + tr_qa( 

2260 "Paternal antipathy score (8–40) <sup>[3]</sup>", 

2261 self.father_antipathy(), 

2262 ) 

2263 + tr_qa( 

2264 "Paternal neglect score (8–40) <sup>[3]</sup>", 

2265 self.father_neglect(), 

2266 ) 

2267 + tr_qa( 

2268 "Paternal psychological abuse score (0–85) <sup>[4]</sup>", 

2269 self.father_psychological_abuse(), 

2270 ) 

2271 + tr_qa( 

2272 "Role reversal score (17–85) <sup>[5]</sup>", 

2273 self.role_reversal(), 

2274 ) 

2275 + tr_qa( 

2276 "Physical abuse screen (0–1) <sup>[6]</sup>", 

2277 self.physical_abuse_screen(), 

2278 ) 

2279 + tr_qa( 

2280 "Maternal physical abuse severity score (0–4) " 

2281 "<sup>[6]</sup>", 

2282 self.physical_abuse_severity_mother(), 

2283 ) 

2284 + tr_qa( 

2285 "Paternal physical abuse severity score (0–4) " 

2286 "<sup>[6]</sup>", 

2287 self.physical_abuse_severity_father(), 

2288 ) 

2289 + tr_qa( 

2290 "Sexual abuse screen (0–3) <sup>[7]</sup>", 

2291 self.sexual_abuse_screen(), 

2292 ) 

2293 + tr_qa( 

2294 "First sexual abuse severity score (0–7) <sup>[7]</sup>", 

2295 self.sexual_abuse_score_first(), 

2296 ) 

2297 + tr_qa( 

2298 "Other sexual abuse severity score (0–7) <sup>[7]</sup>", 

2299 self.sexual_abuse_score_other(), 

2300 ) 

2301 + f""" 

2302 </table> 

2303 </div> 

2304 <table class="{CssClass.TASKDETAIL}"> 

2305 """ 

2306 + subheading_spanning_two_columns("1A: " + wxstring("1a_q")) 

2307 + subsubheading_from_wstring("1a_motherfigures") 

2308 + wstring_boolean( 

2309 "1a_mf_birthmother", self.s1a_motherfigure_birthmother 

2310 ) 

2311 + wstring_boolean( 

2312 "1a_mf_stepmother", self.s1a_motherfigure_stepmother 

2313 ) 

2314 + wstring_boolean( 

2315 "1a_mf_femalerelative", self.s1a_motherfigure_femalerelative 

2316 ) 

2317 + string_string( 

2318 "(Female relative details)", 

2319 self.s1a_motherfigure_femalerelative_detail, 

2320 ) 

2321 + wstring_boolean( 

2322 "1a_mf_familyfriend", self.s1a_motherfigure_familyfriend 

2323 ) 

2324 + wstring_boolean( 

2325 "1a_mf_fostermother", self.s1a_motherfigure_fostermother 

2326 ) 

2327 + wstring_boolean( 

2328 "1a_mf_adoptivemother", self.s1a_motherfigure_adoptivemother 

2329 ) 

2330 + wstring_boolean("other", self.s1a_motherfigure_other) 

2331 + string_string( 

2332 "(Other, details)", self.s1a_motherfigure_other_detail 

2333 ) 

2334 + subsubheading_from_wstring("1a_fatherfigures") 

2335 + wstring_boolean( 

2336 "1a_ff_birthfather", self.s1a_fatherfigure_birthfather 

2337 ) 

2338 + wstring_boolean( 

2339 "1a_ff_stepfather", self.s1a_fatherfigure_stepfather 

2340 ) 

2341 + wstring_boolean( 

2342 "1a_ff_malerelative", self.s1a_fatherfigure_malerelative 

2343 ) 

2344 + string_string( 

2345 "(Male relative details)", 

2346 self.s1a_fatherfigure_malerelative_detail, 

2347 ) 

2348 + wstring_boolean( 

2349 "1a_ff_familyfriend", self.s1a_fatherfigure_familyfriend 

2350 ) 

2351 + wstring_boolean( 

2352 "1a_ff_fosterfather", self.s1a_fatherfigure_fosterfather 

2353 ) 

2354 + wstring_boolean( 

2355 "1a_ff_adoptivefather", self.s1a_fatherfigure_adoptivefather 

2356 ) 

2357 + wstring_boolean("other", self.s1a_fatherfigure_other) 

2358 + string_string( 

2359 "(Other, details)", self.s1a_fatherfigure_other_detail 

2360 ) 

2361 + subheading_from_string("1B: " + wxstring("1b_q")) 

2362 + wstring_boolean("1b_q", self.s1b_institution) 

2363 + wstring_numeric("1b_q_how_long", self.s1b_institution_time_years) 

2364 + subheading_from_string("1C: " + wxstring("1c_heading")) 

2365 + subsubheading_from_wstring("mother") 

2366 + string_boolean("Mother died before age 17", self.s1c_mother_died) 

2367 + wstring_numeric( 

2368 "1c_parentdiedage", self.s1c_mother_died_subject_aged 

2369 ) 

2370 + string_boolean( 

2371 "Separated from mother for >1y", self.s1c_separated_from_mother 

2372 ) 

2373 + wstring_numeric( 

2374 "1c_age_first_separated", 

2375 self.s1c_first_separated_from_mother_aged, 

2376 ) 

2377 + wstring_numeric( 

2378 "1c_how_long_separation", 

2379 self.s1c_mother_how_long_first_separation_years, 

2380 ) 

2381 + wstring_dict( 

2382 "1c_separation_reason", 

2383 self.s1c_mother_separation_reason, 

2384 separation_map, 

2385 ) 

2386 + subsubheading_from_wstring("father") 

2387 + string_boolean("Father died before age 17", self.s1c_father_died) 

2388 + wstring_numeric( 

2389 "1c_parentdiedage", self.s1c_father_died_subject_aged 

2390 ) 

2391 + string_boolean( 

2392 "Separated from father for >1y", self.s1c_separated_from_father 

2393 ) 

2394 + wstring_numeric( 

2395 "1c_age_first_separated", 

2396 self.s1c_first_separated_from_father_aged, 

2397 ) 

2398 + wstring_numeric( 

2399 "1c_how_long_separation", 

2400 self.s1c_father_how_long_first_separation_years, 

2401 ) 

2402 + wstring_dict( 

2403 "1c_separation_reason", 

2404 self.s1c_father_separation_reason, 

2405 separation_map, 

2406 ) 

2407 + wstring_string( 

2408 "please_describe_experience", self.s1c_describe_experience 

2409 ) 

2410 + subheading_from_string("2A: " + wxstring("2a_heading")) 

2411 + wstring_dict( 

2412 "2a_which", self.s2a_which_mother_figure, motherfigure_map 

2413 ) 

2414 + wstring_string( 

2415 "rnc_if_other_describe", 

2416 self.s2a_which_mother_figure_other_detail, 

2417 ) 

2418 ) 

2419 for i in range(1, 17): 

2420 html += string_dict( 

2421 str(i) + ". " + wxstring("2a_q" + str(i)), 

2422 getattr(self, "s2a_q" + str(i)), 

2423 no_yes_5way_map, 

2424 ) 

2425 html += wstring_string( 

2426 "2a_add_anything", self.s2a_extra 

2427 ) + subheading_from_string("2B: " + wxstring("2b_heading")) 

2428 for i in range(1, 18): 

2429 html += tr( 

2430 str(i) + ". " + wxstring("2b_q" + str(i)), 

2431 answer( 

2432 get_from_dict( 

2433 no_yes_3way_map, getattr(self, "s2b_q" + str(i)) 

2434 ) 

2435 ) 

2436 + " (" 

2437 + answer( 

2438 get_from_dict( 

2439 frequency_map, 

2440 getattr(self, "s2b_q" + str(i) + "_frequency"), 

2441 ) 

2442 ) 

2443 + ")", 

2444 ) 

2445 html += ( 

2446 wstring_boolean("if_any_what_age", self.s2b_age_began) 

2447 + wstring_string("is_there_more_you_want_to_say", self.s2b_extra) 

2448 + subheading_from_string("3A: " + wxstring("3a_heading")) 

2449 + wstring_dict( 

2450 "2a_which", self.s3a_which_father_figure, fatherfigure_map 

2451 ) 

2452 + wstring_string( 

2453 "rnc_if_other_describe", 

2454 self.s3a_which_father_figure_other_detail, 

2455 ) 

2456 ) 

2457 for i in range(1, 17): 

2458 html += string_dict( 

2459 str(i) + ". " + wxstring("3a_q" + str(i)), 

2460 getattr(self, "s3a_q" + str(i)), 

2461 no_yes_5way_map, 

2462 ) 

2463 html += wstring_string( 

2464 "3a_add_anything", self.s3a_extra 

2465 ) + subheading_from_string("3B: " + wxstring("3b_heading")) 

2466 for i in range(1, 18): 

2467 html += tr( 

2468 str(i) + ". " + wxstring("3b_q" + str(i)), 

2469 answer( 

2470 get_from_dict( 

2471 no_yes_3way_map, getattr(self, "s3b_q" + str(i)) 

2472 ) 

2473 ) 

2474 + " (" 

2475 + answer( 

2476 get_from_dict( 

2477 frequency_map, 

2478 getattr(self, "s3b_q" + str(i) + "_frequency"), 

2479 ) 

2480 ) 

2481 + ")", 

2482 ) 

2483 html += ( 

2484 wstring_boolean("if_any_what_age", self.s3b_age_began) 

2485 + wstring_string("is_there_more_you_want_to_say", self.s3b_extra) 

2486 + subheading_from_string("3C: " + wxstring("3c_heading")) 

2487 ) 

2488 for i in range(1, 18): 

2489 html += string_dict( 

2490 str(i) + ". " + wxstring("3c_q" + str(i)), 

2491 getattr(self, "s3c_q" + str(i)), 

2492 no_yes_5way_map, 

2493 ) 

2494 html += ( 

2495 wstring_dict( 

2496 "3c_which_parent_cared_for", 

2497 self.s3c_which_parent_cared_for, 

2498 parent_cared_for_map, 

2499 ) 

2500 + wstring_boolean( 

2501 "3c_parent_mental_problem", self.s3c_parent_mental_problem 

2502 ) 

2503 + wstring_boolean( 

2504 "3c_parent_physical_problem", self.s3c_parent_physical_problem 

2505 ) 

2506 + subheading_from_string("4: " + wxstring("4_heading")) 

2507 + subsubheading_from_string("(Adult confidant)") 

2508 + wstring_boolean("4a_q", self.s4a_adultconfidant) 

2509 + subsubheading_from_wstring("4_if_so_who") 

2510 + wstring_boolean( 

2511 "4a_option_mother", self.s4a_adultconfidant_mother 

2512 ) 

2513 + wstring_boolean( 

2514 "4a_option_father", self.s4a_adultconfidant_father 

2515 ) 

2516 + wstring_boolean( 

2517 "4a_option_relative", self.s4a_adultconfidant_otherrelative 

2518 ) 

2519 + wstring_boolean( 

2520 "4a_option_friend", self.s4a_adultconfidant_familyfriend 

2521 ) 

2522 + wstring_boolean( 

2523 "4a_option_responsibleadult", 

2524 self.s4a_adultconfidant_responsibleadult, 

2525 ) 

2526 + wstring_boolean("4a_option_other", self.s4a_adultconfidant_other) 

2527 + string_string( 

2528 "(Other, details)", self.s4a_adultconfidant_other_detail 

2529 ) 

2530 + wstring_string( 

2531 "4_note_anything", self.s4a_adultconfidant_additional 

2532 ) 

2533 + subsubheading_from_string("(Child confidant)") 

2534 + wstring_boolean("4b_q", self.s4b_childconfidant) 

2535 + subsubheading_from_wstring("4_if_so_who") 

2536 + wstring_boolean( 

2537 "4b_option_sister", self.s4b_childconfidant_sister 

2538 ) 

2539 + wstring_boolean( 

2540 "4b_option_brother", self.s4b_childconfidant_brother 

2541 ) 

2542 + wstring_boolean( 

2543 "4b_option_relative", self.s4b_childconfidant_otherrelative 

2544 ) 

2545 + wstring_boolean( 

2546 "4b_option_closefriend", self.s4b_childconfidant_closefriend 

2547 ) 

2548 + wstring_boolean( 

2549 "4b_option_otherfriend", self.s4b_childconfidant_otherfriend 

2550 ) 

2551 + wstring_boolean("4b_option_other", self.s4b_childconfidant_other) 

2552 + string_string( 

2553 "(Other, details)", self.s4b_childconfidant_other_detail 

2554 ) 

2555 + wstring_string( 

2556 "4_note_anything", self.s4b_childconfidant_additional 

2557 ) 

2558 + subsubheading_from_wstring("4c_q") 

2559 + wstring_boolean("4c_option_mother", self.s4c_closest_mother) 

2560 + wstring_boolean("4c_option_father", self.s4c_closest_father) 

2561 + string_boolean("4c_option_sibling", self.s4c_closest_sibling) 

2562 + wstring_boolean( 

2563 "4c_option_relative", self.s4c_closest_otherrelative 

2564 ) 

2565 + wstring_boolean( 

2566 "4c_option_adultfriend", self.s4c_closest_adultfriend 

2567 ) 

2568 + wstring_boolean( 

2569 "4c_option_youngfriend", self.s4c_closest_childfriend 

2570 ) 

2571 + wstring_boolean("4c_option_other", self.s4c_closest_other) 

2572 + string_string("(Other, details)", self.s4c_closest_other_detail) 

2573 + wstring_string("4_note_anything", self.s4c_closest_additional) 

2574 + subheading_from_string("4: " + wxstring("5_heading")) 

2575 + wstring_boolean("5_mainq", self.s5c_physicalabuse) 

2576 + subsubheading_from_wstring("5_motherfigure") 

2577 + wstring_boolean( 

2578 "5_did_this_person_hurt_you", self.s5c_abused_by_mother 

2579 ) 

2580 + wstring_numeric("5_how_old", self.s5c_mother_abuse_age_began) 

2581 + wstring_boolean( 

2582 "5_hit_more_than_once", self.s5c_mother_hit_more_than_once 

2583 ) 

2584 + wstring_dict("5_how_hit", self.s5c_mother_hit_how, hitting_map) 

2585 + wstring_boolean("5_injured", self.s5c_mother_injured) 

2586 + wstring_boolean("5_outofcontrol", self.s5c_mother_out_of_control) 

2587 + subsubheading_from_wstring("5_fatherfigure") 

2588 + wstring_boolean( 

2589 "5_did_this_person_hurt_you", self.s5c_abused_by_father 

2590 ) 

2591 + wstring_numeric("5_how_old", self.s5c_father_abuse_age_began) 

2592 + wstring_boolean( 

2593 "5_hit_more_than_once", self.s5c_father_hit_more_than_once 

2594 ) 

2595 + wstring_dict("5_how_hit", self.s5c_father_hit_how, hitting_map) 

2596 + wstring_boolean("5_injured", self.s5c_father_injured) 

2597 + wstring_boolean("5_outofcontrol", self.s5c_father_out_of_control) 

2598 + wstring_string( 

2599 "5_can_you_describe_1", self.s5c_parental_abuse_description 

2600 ) 

2601 + subsubheading_from_string("(Other in household)") 

2602 + wstring_boolean("5_anyone_else", self.s5c_abuse_by_nonparent) 

2603 + wstring_string( 

2604 "5_can_you_describe_2", self.s5c_nonparent_abuse_description 

2605 ) 

2606 + subheading_from_string("6: " + wxstring("6_heading")) 

2607 + wstring_dict( 

2608 "6_any_unwanted", 

2609 self.s6_any_unwanted_sexual_experience, 

2610 no_yes_3way_map, 

2611 ) 

2612 + wstring_dict( 

2613 "6_intercourse", self.s6_unwanted_intercourse, no_yes_3way_map 

2614 ) 

2615 + wstring_dict( 

2616 "6_upset_adult_authority", 

2617 self.s6_upsetting_sexual_adult_authority, 

2618 no_yes_3way_map, 

2619 ) 

2620 + subsubheading_from_wstring("6_first_experience") 

2621 + wstring_numeric("6_q1", self.s6_first_age) 

2622 + wstring_boolean("6_q2", self.s6_first_person_known) 

2623 + wstring_boolean("6_q3", self.s6_first_relative) 

2624 + wstring_boolean("6_q4", self.s6_first_in_household) 

2625 + wstring_boolean("6_q5", self.s6_first_more_than_once) 

2626 + wstring_boolean("6_q6", self.s6_first_touch_privates_subject) 

2627 + wstring_boolean("6_q7", self.s6_first_touch_privates_other) 

2628 + wstring_boolean("6_q8", self.s6_first_intercourse) 

2629 + subsubheading_from_wstring("6_other_experience") 

2630 + wstring_numeric("6_q1", self.s6_other_age) 

2631 + wstring_boolean("6_q2", self.s6_other_person_known) 

2632 + wstring_boolean("6_q3", self.s6_other_relative) 

2633 + wstring_boolean("6_q4", self.s6_other_in_household) 

2634 + wstring_boolean("6_q5", self.s6_other_more_than_once) 

2635 + wstring_boolean("6_q6", self.s6_other_touch_privates_subject) 

2636 + wstring_boolean("6_q7", self.s6_other_touch_privates_other) 

2637 + wstring_boolean("6_q8", self.s6_other_intercourse) 

2638 + wstring_string( 

2639 "5_can_you_describe_1", self.s6_unwanted_sexual_description 

2640 ) 

2641 + subheading_from_wstring("any_other_comments") 

2642 + wstring_string("any_other_comments", self.any_other_comments) 

2643 + f""" 

2644 </table> 

2645 <div class="{CssClass.FOOTNOTES}"> 

2646 [1] Death of mother/father before age 17 or continuous 

2647 separation of ≥1 year. 

2648 [2] Reason for loss ‘abandonment’ or ‘other’. 

2649 [3] Section 2A and 3A contain antipathy and neglect scales. 

2650 Antipathy scales: reverse items 8, 11; 

2651 then sum 1, 4, 6, 8–11, 16. 

2652 Neglect scales: reverse items 2, 3, 5, 12–14; 

2653 then sum 2, 3, 5, 7, 12–15. 

2654 [4] Psychological abuse scores (sections 2B, 3B): 

2655 sum of items 1–17 (yes=2, unsure=1, no=0) with 

2656 frequencies (never=0, once=1, rarely=2, often=3). 

2657 Any score &gt;1 is a risk indicator. 

2658 [5] Role reversal: sum of scores from section 3C. 

2659 [6] Physical abuse (section 4): first question (screen 

2660 item) is scored 0/1. For each parent, score 1 for 

2661 {{&gt;1 occasion, {{belt/stick/punch/kick}}, injured, 

2662 out-of-control}}. 

2663 [7] Sexual abuse (section 6): no=0, unsure=1, yes=1. 

2664 First three questions are the screen. 

2665 </div> 

2666 """ 

2667 ) 

2668 return html 

2669 

2670 

2671# ============================================================================= 

2672# More helper functions 

2673# ============================================================================= 

2674 

2675 

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

2677 return subheading_spanning_two_columns(s) 

2678 

2679 

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

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

2682 

2683 

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

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

2686 

2687 

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

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

2690 

2691 

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

2693 return row(string, value) 

2694 

2695 

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

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

2698 

2699 

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

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