Coverage for tasks/cisr.py: 42%

1970 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/cisr.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 enum import Enum 

31import logging 

32from typing import List, Optional 

33 

34from cardinal_pythonlib.classes import classproperty 

35from cardinal_pythonlib.logs import BraceStyleAdapter 

36import cardinal_pythonlib.rnc_web as ws 

37from semantic_version import Version 

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

39 

40from camcops_server.cc_modules.cc_constants import CssClass 

41from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo 

42from camcops_server.cc_modules.cc_html import ( 

43 answer, 

44 bold, 

45 get_yes_no, 

46 get_yes_no_none, 

47 italic, 

48 subheading_spanning_two_columns, 

49 td, 

50 tr, 

51) 

52from camcops_server.cc_modules.cc_request import CamcopsRequest 

53from camcops_server.cc_modules.cc_sqla_coltypes import ( 

54 CamcopsColumn, 

55 ZERO_TO_FOUR_CHECKER, 

56 ONE_TO_TWO_CHECKER, 

57 ONE_TO_THREE_CHECKER, 

58 ONE_TO_FOUR_CHECKER, 

59 ONE_TO_FIVE_CHECKER, 

60 ONE_TO_SIX_CHECKER, 

61 ONE_TO_SEVEN_CHECKER, 

62 ONE_TO_EIGHT_CHECKER, 

63 ONE_TO_NINE_CHECKER, 

64) 

65from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

66from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin 

67 

68log = BraceStyleAdapter(logging.getLogger(__name__)) 

69 

70 

71# ============================================================================= 

72# Constants 

73# ============================================================================= 

74 

75DEBUG_SHOW_QUESTIONS_CONSIDERED = True 

76 

77NOT_APPLICABLE_TEXT = "—" 

78 

79# ----------------------------------------------------------------------------- 

80# Comments for fields 

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

82 

83CMT_DEMOGRAPHICS = "(Demographics) " 

84CMT_1_NO_2_YES = " (1 no, 2 yes)" 

85CMT_1_YES_2_NO = " (1 yes, 2 no)" 

86CMT_DURATION = ( 

87 " (1: <2 weeks; 2: 2 weeks–6 months; 3: 6 months–1 year; " 

88 "4: 1–2 years; 5: >2 years)" 

89) 

90CMT_NEVER_SOMETIMES_ALWAYS = " (1 never, 2 sometimes, 3 always)" 

91CMT_DAYS_PER_WEEK = " (1: none, 2: one to three, 3: four or more)" 

92CMT_NIGHTS_PER_WEEK = CMT_DAYS_PER_WEEK 

93CMT_UNPLEASANT = ( 

94 " (1 not at all, 2 a little unpleasant, 3 unpleasant, " 

95 "4 very unpleasant)" 

96) 

97CMT_NO_SOMETIMES_OFTEN = " (1 no, 2 sometimes, 3 often)" 

98CMT_BOTHERSOME_INTERESTING = ( 

99 " (1 no, 2 yes, 3 haven't done anything " "interesting)" 

100) 

101CMT_DURING_ENJOYABLE = " (1 no, 2 yes, 3 haven't done anything enjoyable)" 

102CMT_FATIGUE_CAUSE = ( 

103 " (1 problems with sleep; 2 medication; 3 physical illness; 4 working too " 

104 "hard inc. childcare; 5 stress/worry/other psychological; 6 physical " 

105 "exercise; 7 other; 8 don't know)" 

106) 

107CMT_STRESSORS = ( 

108 " (1 family members; 2 relationships with friends/colleagues; 3 housing; " 

109 "4 money/bills; 5 own physical health; 6 own mental health; 7 work/lack " 

110 "of work; 8 legal; 9 political/news)" 

111) 

112CMT_SLEEP_CHANGE = " (1: <15min, 2: 15–60min, 3: 1–3h, 4: >=3h)" 

113CMT_ANHEDONIA = ( 

114 " (1 yes; 2 no, less enjoyment than usual; " "3 no, don't enjoy anything)" 

115) 

116CMT_PANIC_SYMPTOM = "Panic symptom in past week: " 

117 

118# ... and results: 

119DESC_DEPCRIT1 = "Depressive criterion 1 (mood, anhedonia, energy; max. 3)" 

120DESC_DEPCRIT2 = ( 

121 "Depressive criterion 2 (appetite/weight, concentration, " 

122 "sleep, motor, guilt, self-worth, suicidality; max. 7)" 

123) 

124DESC_DEPCRIT3 = ( 

125 "Depressive criterion 3: somatic syndrome (anhedonia, lack of emotional " 

126 "reactivity, early-morning waking, depression worse in the morning, " 

127 "psychomotor retardation/agitation, loss of appetite, weight loss, loss " 

128 "of libido; max. 8)" 

129) 

130DESC_DEPCRIT3_MET = "Somatic syndrome criterion met (≥4)?" 

131DESC_NEURASTHENIA_SCORE = "Neurasthenia score (max. 3)" 

132 

133DISORDER_OCD = "Obsessive–compulsive disorder" 

134DISORDER_DEPR_MILD = "Depressive episode: at least mild" 

135DISORDER_DEPR_MOD = "Depressive episode: at least moderate" 

136DISORDER_DEPR_SEV = "Depressive episode: severe" 

137DISORDER_CFS = "Chronic fatigue syndrome" 

138DISORDER_GAD = "Generalized anxiety disorder" 

139DISORDER_AGORAPHOBIA = "Agoraphobia" 

140DISORDER_SOCIAL_PHOBIA = "Social phobia" 

141DISORDER_SPECIFIC_PHOBIA = "Specific phobia" 

142DISORDER_PANIC = "Panic disorder" 

143 

144# ----------------------------------------------------------------------------- 

145# Number of response values (numbered from 1 to N) 

146# ----------------------------------------------------------------------------- 

147 

148N_DURATIONS = 5 

149N_OPTIONS_DAYS_PER_WEEK = 3 

150N_OPTIONS_NIGHTS_PER_WEEK = 3 

151N_OPTIONS_HOW_UNPLEASANT = 4 

152N_OPTIONS_FATIGUE_CAUSES = 8 

153N_OPTIONS_STRESSORS = 9 

154N_OPTIONS_NO_SOMETIMES_OFTEN = 3 

155NUM_PANIC_SYMPTOMS = 13 # from a to m 

156 

157# ----------------------------------------------------------------------------- 

158# Actual response values 

159# ----------------------------------------------------------------------------- 

160 

161# For e.g. SOMATIC_DUR, etc.: "How long have you..." 

162V_DURATION_LT_2W = 1 

163V_DURATION_2W_6M = 2 

164V_DURATION_6M_1Y = 3 

165V_DURATION_1Y_2Y = 4 

166V_DURATION_GE_2Y = 5 

167 

168# For quite a few: "on how many days in the past week...?" 

169V_DAYS_IN_PAST_WEEK_0 = 1 

170V_DAYS_IN_PAST_WEEK_1_TO_3 = 2 

171V_DAYS_IN_PAST_WEEK_4_OR_MORE = 3 

172 

173V_NIGHTS_IN_PAST_WEEK_0 = 1 

174V_NIGHTS_IN_PAST_WEEK_1_TO_3 = 2 

175V_NIGHTS_IN_PAST_WEEK_4_OR_MORE = 3 

176 

177V_HOW_UNPLEASANT_NOT_AT_ALL = 1 

178V_HOW_UNPLEASANT_A_LITTLE = 2 

179V_HOW_UNPLEASANT_UNPLEASANT = 3 

180V_HOW_UNPLEASANT_VERY = 4 

181 

182V_FATIGUE_CAUSE_SLEEP = 1 

183V_FATIGUE_CAUSE_MEDICATION = 2 

184V_FATIGUE_CAUSE_PHYSICAL_ILLNESS = 3 

185V_FATIGUE_CAUSE_OVERWORK = 4 

186V_FATIGUE_CAUSE_PSYCHOLOGICAL = 5 

187V_FATIGUE_CAUSE_EXERCISE = 6 

188V_FATIGUE_CAUSE_OTHER = 7 

189V_FATIGUE_CAUSE_DONT_KNOW = 8 

190 

191V_STRESSOR_FAMILY = 1 

192V_STRESSOR_FRIENDS_COLLEAGUES = 2 

193V_STRESSOR_HOUSING = 3 

194V_STRESSOR_MONEY = 4 

195V_STRESSOR_PHYSICAL_HEALTH = 5 

196V_STRESSOR_MENTAL_HEALTH = 6 

197V_STRESSOR_WORK = 7 

198V_STRESSOR_LEGAL = 8 

199V_STRESSOR_POLITICAL_NEWS = 9 

200 

201V_NSO_NO = 1 

202V_NSO_SOMETIMES = 2 

203V_NSO_OFTEN = 3 

204 

205V_SLEEP_CHANGE_LT_15_MIN = 1 

206V_SLEEP_CHANGE_15_MIN_TO_1_H = 2 

207V_SLEEP_CHANGE_1_TO_3_H = 3 

208V_SLEEP_CHANGE_GT_3_H = 4 

209 

210V_ANHEDONIA_ENJOYING_NORMALLY = 1 

211V_ANHEDONIA_ENJOYING_LESS = 2 

212V_ANHEDONIA_NOT_ENJOYING = 3 

213 

214# Specific other question values: 

215 

216V_EMPSTAT_FT = 1 # unused 

217V_EMPSTAT_PT = 2 # unused 

218V_EMPSTAT_STUDENT = 3 # unused 

219V_EMPSTAT_RETIRED = 4 # unused 

220V_EMPSTAT_HOUSEPERSON = 5 # unused 

221V_EMPSTAT_UNEMPJOBSEEKER = 6 # unused 

222V_EMPSTAT_UNEMPILLHEALTH = 7 # unused 

223 

224V_EMPTYPE_SELFEMPWITHEMPLOYEES = 1 # unused 

225V_EMPTYPE_SELFEMPNOEMPLOYEES = 2 # unused 

226V_EMPTYPE_EMPLOYEE = 3 # unused 

227V_EMPTYPE_SUPERVISOR = 4 # unused 

228V_EMPTYPE_MANAGER = 5 # unused 

229V_EMPTYPE_NOT_APPLICABLE = 6 # unused 

230# ... the last one: added by RNC, in case pt never employed. (Mentioned to 

231# Glyn Lewis 2017-12-04. Not, in any case, part of the important bits of the 

232# CIS-R.) 

233 

234V_HOME_OWNER = 1 # unused 

235V_HOME_TENANT = 2 # unused 

236V_HOME_RELATIVEFRIEND = 3 # unused 

237V_HOME_HOSTELCAREHOME = 4 # unused 

238V_HOME_HOMELESS = 5 # unused 

239V_HOME_OTHER = 6 # unused 

240 

241V_WEIGHT2_WTLOSS_NOTTRYING = 1 

242V_WEIGHT2_WTLOSS_TRYING = 2 

243 

244V_WEIGHT3_WTLOSS_GE_HALF_STONE = 1 

245V_WEIGHT3_WTLOSS_LT_HALF_STONE = 2 

246 

247V_WEIGHT4_WTGAIN_YES_PREGNANT = 3 

248 

249V_WEIGHT5_WTGAIN_GE_HALF_STONE = 1 

250V_WEIGHT5_WTGAIN_LT_HALF_STONE = 2 

251 

252V_GPYEAR_NONE = 0 

253V_GPYEAR_1_2 = 1 

254V_GPYEAR_3_5 = 2 

255V_GPYEAR_6_10 = 3 

256V_GPYEAR_GT_10 = 4 

257 

258V_ILLNESS_DIABETES = 1 

259V_ILLNESS_ASTHMA = 2 

260V_ILLNESS_ARTHRITIS = 3 

261V_ILLNESS_HEART_DISEASE = 4 

262V_ILLNESS_HYPERTENSION = 5 

263V_ILLNESS_LUNG_DISEASE = 6 

264V_ILLNESS_MORE_THAN_ONE = 7 

265V_ILLNESS_NONE = 8 

266 

267V_SOMATIC_PAIN1_NEVER = 1 

268V_SOMATIC_PAIN1_SOMETIMES = 2 

269V_SOMATIC_PAIN1_ALWAYS = 3 

270 

271V_SOMATIC_PAIN3_LT_3H = 1 

272V_SOMATIC_PAIN3_GT_3H = 2 

273 

274V_SOMATIC_PAIN4_NOT_AT_ALL = 1 

275V_SOMATIC_PAIN4_LITTLE_UNPLEASANT = 2 

276V_SOMATIC_PAIN4_UNPLEASANT = 3 

277V_SOMATIC_PAIN4_VERY_UNPLEASANT = 4 

278 

279V_SOMATIC_PAIN5_NO = 1 

280V_SOMATIC_PAIN5_YES = 2 

281V_SOMATIC_PAIN5_NOT_DONE_ANYTHING_INTERESTING = 3 

282 

283V_SOMATIC_MAND2_NO = 1 

284V_SOMATIC_MAND2_YES = 2 

285 

286V_SOMATIC_DIS1_NEVER = 1 

287V_SOMATIC_DIS1_SOMETIMES = 2 

288V_SOMATIC_DIS1_ALWAYS = 3 

289 

290V_SOMATIC_DIS2_NONE = 1 

291V_SOMATIC_DIS2_1_TO_3_DAYS = 2 

292V_SOMATIC_DIS2_4_OR_MORE_DAYS = 3 

293 

294V_SOMATIC_DIS3_LT_3H = 1 

295V_SOMATIC_DIS3_GT_3H = 2 

296 

297V_SOMATIC_DIS4_NOT_AT_ALL = 1 

298V_SOMATIC_DIS4_LITTLE_UNPLEASANT = 2 

299V_SOMATIC_DIS4_UNPLEASANT = 3 

300V_SOMATIC_DIS4_VERY_UNPLEASANT = 4 

301 

302V_SOMATIC_DIS5_NO = 1 

303V_SOMATIC_DIS5_YES = 2 

304V_SOMATIC_DIS5_NOT_DONE_ANYTHING_INTERESTING = 3 

305 

306V_SLEEP_MAND2_NO = 1 

307V_SLEEP_MAND2_YES_BUT_NOT_A_PROBLEM = 2 

308V_SLEEP_MAND2_YES = 3 

309 

310V_IRRIT_MAND2_NO = 1 

311V_IRRIT_MAND2_SOMETIMES = 2 

312V_IRRIT_MAND2_YES = 3 

313 

314V_IRRIT3_SHOUTING_NO = 1 

315V_IRRIT3_SHOUTING_WANTED_TO = 2 

316V_IRRIT3_SHOUTING_DID = 3 

317 

318V_IRRIT4_ARGUMENTS_NO = 1 

319V_IRRIT4_ARGUMENTS_YES_JUSTIFIED = 2 

320V_IRRIT4_ARGUMENTS_YES_UNJUSTIFIED = 3 

321 

322V_DEPR5_COULD_CHEER_UP_YES = 1 

323V_DEPR5_COULD_CHEER_UP_SOMETIMES = 2 

324V_DEPR5_COULD_CHEER_UP_NO = 3 

325 

326V_DEPTH1_DMV_WORSE_MORNING = 1 

327V_DEPTH1_DMV_WORSE_EVENING = 2 

328V_DEPTH1_DMV_VARIES = 3 

329V_DEPTH1_DMV_NONE = 4 

330 

331V_DEPTH2_LIBIDO_NA = 1 

332V_DEPTH2_LIBIDO_NO_CHANGE = 2 

333V_DEPTH2_LIBIDO_INCREASED = 3 

334V_DEPTH2_LIBIDO_DECREASED = 4 

335 

336V_DEPTH5_GUILT_NEVER = 1 

337V_DEPTH5_GUILT_WHEN_AT_FAULT = 2 

338V_DEPTH5_GUILT_SOMETIMES = 3 

339V_DEPTH5_GUILT_OFTEN = 4 

340 

341V_DEPTH8_LNWL_NO = 1 

342V_DEPTH8_LNWL_SOMETIMES = 2 

343V_DEPTH8_LNWL_ALWAYS = 3 

344 

345V_DEPTH9_SUICIDAL_THOUGHTS_NO = 1 

346V_DEPTH9_SUICIDAL_THOUGHTS_YES_BUT_NEVER_WOULD = 2 

347V_DEPTH9_SUICIDAL_THOUGHTS_YES = 3 

348 

349V_DOCTOR_YES = 1 

350V_DOCTOR_NO_BUT_OTHERS = 2 

351V_DOCTOR_NO = 3 

352 

353V_ANX_PHOBIA2_ALWAYS_SPECIFIC = 1 

354V_ANX_PHOBIA2_SOMETIMES_GENERAL = 2 

355 

356V_PHOBIAS_TYPE1_ALONE_PUBLIC_TRANSPORT = 1 

357V_PHOBIAS_TYPE1_FAR_FROM_HOME = 2 

358V_PHOBIAS_TYPE1_PUBLIC_SPEAKING_EATING = 3 

359V_PHOBIAS_TYPE1_BLOOD = 4 

360V_PHOBIAS_TYPE1_CROWDED_SHOPS = 5 

361V_PHOBIAS_TYPE1_ANIMALS = 6 

362V_PHOBIAS_TYPE1_BEING_WATCHED = 7 

363V_PHOBIAS_TYPE1_ENCLOSED_SPACES_HEIGHTS = 8 

364V_PHOBIAS_TYPE1_OTHER = 9 

365 

366V_PANIC1_N_PANICS_PAST_WEEK_0 = 1 

367V_PANIC1_N_PANICS_PAST_WEEK_1 = 2 

368V_PANIC1_N_PANICS_PAST_WEEK_GT_1 = 3 

369 

370V_PANIC3_WORST_LT_10_MIN = 1 

371V_PANIC3_WORST_GE_10_MIN = 2 

372 

373V_COMP4_MAX_N_REPEATS_1 = 1 

374V_COMP4_MAX_N_REPEATS_2 = 2 

375V_COMP4_MAX_N_REPEATS_GE_3 = 3 

376 

377V_OBSESS_MAND1_SAME_THOUGHTS_REPEATED = 1 

378V_OBSESS_MAND1_GENERAL_WORRIES = 2 

379 

380V_OBSESS4_LT_15_MIN = 1 

381V_OBSESS4_GE_15_MIN = 2 

382 

383V_OVERALL_IMPAIRMENT_NONE = 1 

384V_OVERALL_IMPAIRMENT_DIFFICULT = 2 

385V_OVERALL_IMPAIRMENT_STOP_1_ACTIVITY = 3 

386V_OVERALL_IMPAIRMENT_STOP_GT_1_ACTIVITY = 4 

387 

388# ----------------------------------------------------------------------------- 

389# Internal coding, NOT answer values: 

390# ----------------------------------------------------------------------------- 

391 

392# Magic numbers from the original: 

393WTCHANGE_NONE_OR_APPETITE_INCREASE = 0 

394WTCHANGE_APPETITE_LOSS = 1 

395WTCHANGE_NONDELIBERATE_WTLOSS_OR_WTGAIN = 2 

396WTCHANGE_WTLOSS_GE_HALF_STONE = 3 

397WTCHANGE_WTGAIN_GE_HALF_STONE = 4 

398# ... I'm not entirely sure why this labelling system is used! 

399 

400DESC_WEIGHT_CHANGE = ( 

401 "Weight change " 

402 f"({WTCHANGE_NONE_OR_APPETITE_INCREASE}: none or appetite increase; " 

403 f"{WTCHANGE_APPETITE_LOSS}: appetite loss without weight loss; " 

404 f"{WTCHANGE_NONDELIBERATE_WTLOSS_OR_WTGAIN}: " 

405 "non-deliberate weight loss or gain <0.5 st; " 

406 f"{WTCHANGE_WTLOSS_GE_HALF_STONE}: weight loss ≥0.5 st; " 

407 f"{WTCHANGE_WTGAIN_GE_HALF_STONE}: weight gain ≥0.5 st)" 

408) 

409 

410PHOBIATYPES_OTHER = 0 

411PHOBIATYPES_AGORAPHOBIA = 1 

412PHOBIATYPES_SOCIAL = 2 

413PHOBIATYPES_BLOOD_INJURY = 3 

414PHOBIATYPES_ANIMALS_ENCLOSED_HEIGHTS = 4 

415# ... some of these are not really used, but I've followed the original CIS-R 

416# for clarity 

417 

418# One smaller than the answer codes: 

419OVERALL_IMPAIRMENT_NONE = 0 

420OVERALL_IMPAIRMENT_DIFFICULT = 1 

421OVERALL_IMPAIRMENT_STOP_1_ACTIVITY = 2 

422OVERALL_IMPAIRMENT_STOP_GT_1_ACTIVITY = 3 

423 

424# Again, we're following this coding structure primarily for compatibility: 

425DIAG_0_NO_DIAGNOSIS = 0 

426DIAG_1_MIXED_ANX_DEPR_DIS_MILD = 1 

427DIAG_2_GENERALIZED_ANX_DIS_MILD = 2 

428DIAG_3_OBSESSIVE_COMPULSIVE_DIS = 3 

429DIAG_4_MIXED_ANX_DEPR_DIS = 4 

430DIAG_5_SPECIFIC_PHOBIA = 5 

431DIAG_6_SOCIAL_PHOBIA = 6 

432DIAG_7_AGORAPHOBIA = 7 

433DIAG_8_GENERALIZED_ANX_DIS = 8 

434DIAG_9_PANIC_DIS = 9 

435DIAG_10_MILD_DEPR_EPISODE = 10 

436DIAG_11_MOD_DEPR_EPISODE = 11 

437DIAG_12_SEVERE_DEPR_EPISODE = 12 

438 

439SUICIDE_INTENT_NONE = 0 

440SUICIDE_INTENT_HOPELESS_NO_SUICIDAL_THOUGHTS = 1 

441SUICIDE_INTENT_LIFE_NOT_WORTH_LIVING = 2 

442SUICIDE_INTENT_SUICIDAL_THOUGHTS = 3 

443SUICIDE_INTENT_SUICIDAL_PLANS = 4 

444 

445SLEEPCHANGE_NONE = 0 # added 

446SLEEPCHANGE_EMW = 1 

447SLEEPCHANGE_INSOMNIA_NOT_EMW = 2 

448SLEEPCHANGE_INCREASE = 3 

449 

450DESC_SLEEP_CHANGE = ( 

451 f"Sleep change ({SLEEPCHANGE_NONE}: none; " 

452 f"{SLEEPCHANGE_EMW}: early-morning waking; " 

453 f"{SLEEPCHANGE_INSOMNIA_NOT_EMW}: insomnia without early-morning waking; " 

454 f"{SLEEPCHANGE_INCREASE}: sleep increase)" 

455) 

456 

457DIURNAL_MOOD_VAR_NONE = 0 

458DIURNAL_MOOD_VAR_WORSE_MORNING = 1 

459DIURNAL_MOOD_VAR_WORSE_EVENING = 2 

460 

461PSYCHOMOTOR_NONE = 0 

462PSYCHOMOTOR_RETARDATION = 1 

463PSYCHOMOTOR_AGITATION = 2 

464 

465# Answer values or pseudo-values: 

466 

467V_MISSING = 0 # Integer value of a missing answer 

468V_UNKNOWN = -1 # Dummy value, never used for answers 

469 

470SCORE_PREFIX = "... " 

471 

472# ----------------------------------------------------------------------------- 

473# Scoring constants: 

474# ----------------------------------------------------------------------------- 

475 

476MAX_TOTAL = 57 

477 

478MAX_SOMATIC = 4 

479MAX_HYPO = 4 

480MAX_IRRIT = 4 

481MAX_CONC = 4 

482MAX_FATIGUE = 4 

483MAX_SLEEP = 4 

484MAX_DEPR = 4 

485MAX_DEPTHTS = 5 

486MAX_PHOBIAS = 4 

487MAX_WORRY = 4 

488MAX_ANX = 4 

489MAX_PANIC = 4 

490MAX_COMP = 4 

491MAX_OBSESS = 4 

492MAX_DEPCRIT1 = 3 

493MAX_DEPCRIT2 = 7 

494MAX_DEPCRIT3 = 8 

495 

496SOMATIC_SYNDROME_CRITERION = 4 # number of symptoms 

497 

498# ----------------------------------------------------------------------------- 

499# Question numbers 

500# ----------------------------------------------------------------------------- 

501 

502# Not quite sure to do an autonumbering enum that also can have synonyms, like 

503# C++. The AutoNumberEnum (q.v.) is close, but won't do the synonyms. So: 

504 

505_nasty_hack_next_enum = 1 # start with 1 

506 

507 

508def next_enum() -> int: 

509 global _nasty_hack_next_enum 

510 v = _nasty_hack_next_enum 

511 _nasty_hack_next_enum += 1 

512 return v 

513 

514 

515class CisrQuestion(Enum): 

516 # The values below look like integers, but they aren't; they are of type 

517 # CisrQuestion, and have attributes like ".value". 

518 START_MARKER = next_enum() 

519 

520 INTRO_1 = START_MARKER 

521 INTRO_2 = next_enum() 

522 INTRO_DEMOGRAPHICS = next_enum() 

523 

524 ETHNIC = next_enum() 

525 MARRIED = next_enum() 

526 EMPSTAT = next_enum() 

527 EMPTYPE = next_enum() 

528 HOME = next_enum() 

529 HEALTH_WELLBEING = next_enum() 

530 

531 APPETITE1_LOSS_PAST_MONTH = next_enum() 

532 

533 WEIGHT1_LOSS_PAST_MONTH = next_enum() 

534 WEIGHT2_TRYING_TO_LOSE = next_enum() 

535 WEIGHT3_LOST_LOTS = next_enum() 

536 APPETITE2_INCREASE_PAST_MONTH = next_enum() 

537 WEIGHT4_INCREASE_PAST_MONTH = next_enum() 

538 # WEIGHT4A = WEIGHT4 with pregnancy question; blended 

539 WEIGHT5_GAINED_LOTS = next_enum() 

540 GP_YEAR = next_enum() 

541 DISABLE = next_enum() 

542 ILLNESS = next_enum() 

543 

544 SOMATIC_MAND1_PAIN_PAST_MONTH = next_enum() 

545 SOMATIC_PAIN1_PSYCHOL_EXAC = next_enum() 

546 SOMATIC_PAIN2_DAYS_PAST_WEEK = next_enum() 

547 SOMATIC_PAIN3_GT_3H_ANY_DAY = next_enum() 

548 SOMATIC_PAIN4_UNPLEASANT = next_enum() 

549 SOMATIC_PAIN5_INTERRUPTED_INTERESTING = next_enum() 

550 SOMATIC_MAND2_DISCOMFORT = next_enum() 

551 SOMATIC_DIS1_PSYCHOL_EXAC = next_enum() 

552 SOMATIC_DIS2_DAYS_PAST_WEEK = next_enum() 

553 SOMATIC_DIS3_GT_3H_ANY_DAY = next_enum() 

554 SOMATIC_DIS4_UNPLEASANT = next_enum() 

555 SOMATIC_DIS5_INTERRUPTED_INTERESTING = next_enum() 

556 SOMATIC_DUR = next_enum() 

557 

558 FATIGUE_MAND1_TIRED_PAST_MONTH = next_enum() 

559 FATIGUE_CAUSE1_TIRED = next_enum() 

560 FATIGUE_TIRED1_DAYS_PAST_WEEK = next_enum() 

561 FATIGUE_TIRED2_GT_3H_ANY_DAY = next_enum() 

562 FATIGUE_TIRED3_HAD_TO_PUSH = next_enum() 

563 FATIGUE_TIRED4_DURING_ENJOYABLE = next_enum() 

564 FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH = next_enum() 

565 FATIGUE_CAUSE2_LACK_ENERGY = next_enum() 

566 FATIGUE_ENERGY1_DAYS_PAST_WEEK = next_enum() 

567 FATIGUE_ENERGY2_GT_3H_ANY_DAY = next_enum() 

568 FATIGUE_ENERGY3_HAD_TO_PUSH = next_enum() 

569 FATIGUE_ENERGY4_DURING_ENJOYABLE = next_enum() 

570 FATIGUE_DUR = next_enum() 

571 

572 CONC_MAND1_POOR_CONC_PAST_MONTH = next_enum() 

573 CONC_MAND2_FORGETFUL_PAST_MONTH = next_enum() 

574 CONC1_CONC_DAYS_PAST_WEEK = next_enum() 

575 CONC2_CONC_FOR_TV_READING_CONVERSATION = next_enum() 

576 CONC3_CONC_PREVENTED_ACTIVITIES = next_enum() 

577 CONC_DUR = next_enum() 

578 CONC4_FORGOTTEN_IMPORTANT = next_enum() 

579 FORGET_DUR = next_enum() 

580 

581 SLEEP_MAND1_LOSS_PAST_MONTH = next_enum() 

582 SLEEP_LOSE1_NIGHTS_PAST_WEEK = next_enum() 

583 SLEEP_LOSE2_DIS_WORST_DURATION = ( 

584 next_enum() 

585 ) # DIS = delayed initiation of sleep # noqa 

586 SLEEP_LOSE3_NIGHTS_GT_3H_DIS_PAST_WEEK = next_enum() 

587 SLEEP_EMW_PAST_WEEK = next_enum() # EMW = early-morning waking 

588 SLEEP_CAUSE = next_enum() 

589 SLEEP_MAND2_GAIN_PAST_MONTH = next_enum() 

590 SLEEP_GAIN1_NIGHTS_PAST_WEEK = next_enum() 

591 SLEEP_GAIN2_EXTRA_ON_LONGEST_NIGHT = next_enum() 

592 SLEEP_GAIN3_NIGHTS_GT_3H_EXTRA_PAST_WEEK = next_enum() 

593 SLEEP_DUR = next_enum() 

594 

595 IRRIT_MAND1_PEOPLE_PAST_MONTH = next_enum() 

596 IRRIT_MAND2_THINGS_PAST_MONTH = next_enum() 

597 IRRIT1_DAYS_PER_WEEK = next_enum() 

598 IRRIT2_GT_1H_ANY_DAY = next_enum() 

599 IRRIT3_WANTED_TO_SHOUT = next_enum() 

600 IRRIT4_ARGUMENTS = next_enum() 

601 IRRIT_DUR = next_enum() 

602 

603 HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH = next_enum() 

604 HYPO_MAND2_WORRIED_RE_SERIOUS_ILLNESS = next_enum() 

605 HYPO1_DAYS_PAST_WEEK = next_enum() 

606 HYPO2_WORRY_TOO_MUCH = next_enum() 

607 HYPO3_HOW_UNPLEASANT = next_enum() 

608 HYPO4_CAN_DISTRACT = next_enum() 

609 HYPO_DUR = next_enum() 

610 

611 DEPR_MAND1_LOW_MOOD_PAST_MONTH = next_enum() 

612 DEPR1_LOW_MOOD_PAST_WEEK = next_enum() 

613 DEPR_MAND2_ENJOYMENT_PAST_MONTH = next_enum() 

614 DEPR2_ENJOYMENT_PAST_WEEK = next_enum() 

615 DEPR3_DAYS_PAST_WEEK = next_enum() 

616 DEPR4_GT_3H_ANY_DAY = next_enum() 

617 DEPR_CONTENT = next_enum() 

618 DEPR5_COULD_CHEER_UP = next_enum() 

619 DEPR_DUR = next_enum() 

620 DEPTH1_DIURNAL_VARIATION = next_enum() # "depth" = depressive thoughts? 

621 DEPTH2_LIBIDO = next_enum() 

622 DEPTH3_RESTLESS = next_enum() 

623 DEPTH4_SLOWED = next_enum() 

624 DEPTH5_GUILT = next_enum() 

625 DEPTH6_WORSE_THAN_OTHERS = next_enum() 

626 DEPTH7_HOPELESS = next_enum() 

627 DEPTH8_LNWL = next_enum() # life not worth living 

628 DEPTH9_SUICIDE_THOUGHTS = next_enum() 

629 DEPTH10_SUICIDE_METHOD = next_enum() 

630 DOCTOR = next_enum() 

631 DOCTOR2_PLEASE_TALK_TO = next_enum() 

632 DEPR_OUTRO = next_enum() 

633 

634 WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH = next_enum() 

635 WORRY_MAND2_ANY_WORRIES_PAST_MONTH = next_enum() 

636 WORRY_CONT1 = next_enum() 

637 WORRY1_INFO_ONLY = next_enum() 

638 WORRY2_DAYS_PAST_WEEK = next_enum() 

639 WORRY3_TOO_MUCH = next_enum() 

640 WORRY4_HOW_UNPLEASANT = next_enum() 

641 WORRY5_GT_3H_ANY_DAY = next_enum() 

642 WORRY_DUR = next_enum() 

643 

644 ANX_MAND1_ANXIETY_PAST_MONTH = next_enum() 

645 ANX_MAND2_TENSION_PAST_MONTH = next_enum() 

646 ANX_PHOBIA1_SPECIFIC_PAST_MONTH = next_enum() 

647 ANX_PHOBIA2_SPECIFIC_OR_GENERAL = next_enum() 

648 ANX1_INFO_ONLY = next_enum() 

649 ANX2_GENERAL_DAYS_PAST_WEEK = next_enum() 

650 ANX3_GENERAL_HOW_UNPLEASANT = next_enum() 

651 ANX4_GENERAL_PHYSICAL_SYMPTOMS = next_enum() 

652 ANX5_GENERAL_GT_3H_ANY_DAY = next_enum() 

653 ANX_DUR_GENERAL = next_enum() 

654 

655 PHOBIAS_MAND_AVOIDANCE_PAST_MONTH = next_enum() 

656 PHOBIAS_TYPE1 = next_enum() 

657 PHOBIAS1_DAYS_PAST_WEEK = next_enum() 

658 PHOBIAS2_PHYSICAL_SYMPTOMS = next_enum() 

659 PHOBIAS3_AVOIDANCE = next_enum() 

660 PHOBIAS4_AVOIDANCE_DAYS_PAST_WEEK = next_enum() 

661 PHOBIAS_DUR = next_enum() 

662 

663 PANIC_MAND_PAST_MONTH = next_enum() 

664 PANIC1_NUM_PAST_WEEK = next_enum() 

665 PANIC2_HOW_UNPLEASANT = next_enum() 

666 PANIC3_PANIC_GE_10_MIN = next_enum() 

667 PANIC4_RAPID_ONSET = next_enum() 

668 PANSYM = next_enum() # questions about each of several symptoms 

669 PANIC5_ALWAYS_SPECIFIC_TRIGGER = next_enum() 

670 PANIC_DUR = next_enum() 

671 

672 ANX_OUTRO = next_enum() 

673 

674 COMP_MAND1_COMPULSIONS_PAST_MONTH = next_enum() 

675 COMP1_DAYS_PAST_WEEK = next_enum() 

676 COMP2_TRIED_TO_STOP = next_enum() 

677 COMP3_UPSETTING = next_enum() 

678 COMP4_MAX_N_REPETITIONS = next_enum() 

679 COMP_DUR = next_enum() 

680 

681 OBSESS_MAND1_OBSESSIONS_PAST_MONTH = next_enum() 

682 OBSESS_MAND2_SAME_THOUGHTS_OR_GENERAL = next_enum() 

683 OBSESS1_DAYS_PAST_WEEK = next_enum() 

684 OBSESS2_TRIED_TO_STOP = next_enum() 

685 OBSESS3_UPSETTING = next_enum() 

686 OBSESS4_MAX_DURATION = next_enum() 

687 OBSESS_DUR = next_enum() 

688 

689 OVERALL1_INFO_ONLY = next_enum() 

690 OVERALL2_IMPACT_PAST_WEEK = next_enum() 

691 THANKS_FINISHED = next_enum() 

692 END_MARKER = next_enum() # not a real page 

693 

694 

695CQ = CisrQuestion # shorthand 

696 

697# Demographics section 

698FN_ETHNIC = "ethnic" 

699FN_MARRIED = "married" 

700FN_EMPSTAT = "empstat" 

701FN_EMPTYPE = "emptype" 

702FN_HOME = "home" 

703 

704FN_APPETITE1 = "appetite1" 

705FN_WEIGHT1 = "weight1" 

706FN_WEIGHT2 = "weight2" 

707FN_WEIGHT3 = "weight3" 

708FN_APPETITE2 = "appetite2" 

709FN_WEIGHT4 = "weight4" # male/female responses unified (no "weight4a" 

710FN_WEIGHT5 = "weight5" 

711 

712FN_GP_YEAR = "gp_year" 

713FN_DISABLE = "disable" 

714FN_ILLNESS = "illness" 

715 

716FN_SOMATIC_MAND1 = "somatic_mand1" 

717FN_SOMATIC_PAIN1 = "somatic_pain1" 

718FN_SOMATIC_PAIN2 = "somatic_pain2" 

719FN_SOMATIC_PAIN3 = "somatic_pain3" 

720FN_SOMATIC_PAIN4 = "somatic_pain4" 

721FN_SOMATIC_PAIN5 = "somatic_pain5" 

722FN_SOMATIC_MAND2 = "somatic_mand2" 

723FN_SOMATIC_DIS1 = "somatic_dis1" 

724FN_SOMATIC_DIS2 = "somatic_dis2" 

725FN_SOMATIC_DIS3 = "somatic_dis3" 

726FN_SOMATIC_DIS4 = "somatic_dis4" 

727FN_SOMATIC_DIS5 = "somatic_dis5" 

728FN_SOMATIC_DUR = "somatic_dur" 

729 

730FN_FATIGUE_MAND1 = "fatigue_mand1" 

731FN_FATIGUE_CAUSE1 = "fatigue_cause1" 

732FN_FATIGUE_TIRED1 = "fatigue_tired1" 

733FN_FATIGUE_TIRED2 = "fatigue_tired2" 

734FN_FATIGUE_TIRED3 = "fatigue_tired3" 

735FN_FATIGUE_TIRED4 = "fatigue_tired4" 

736FN_FATIGUE_MAND2 = "fatigue_mand2" 

737FN_FATIGUE_CAUSE2 = "fatigue_cause2" 

738FN_FATIGUE_ENERGY1 = "fatigue_energy1" 

739FN_FATIGUE_ENERGY2 = "fatigue_energy2" 

740FN_FATIGUE_ENERGY3 = "fatigue_energy3" 

741FN_FATIGUE_ENERGY4 = "fatigue_energy4" 

742FN_FATIGUE_DUR = "fatigue_dur" 

743 

744FN_CONC_MAND1 = "conc_mand1" 

745FN_CONC_MAND2 = "conc_mand2" 

746FN_CONC1 = "conc1" 

747FN_CONC2 = "conc2" 

748FN_CONC3 = "conc3" 

749FN_CONC_DUR = "conc_dur" 

750FN_CONC4 = "conc4" 

751FN_FORGET_DUR = "forget_dur" 

752 

753FN_SLEEP_MAND1 = "sleep_mand1" 

754FN_SLEEP_LOSE1 = "sleep_lose1" 

755FN_SLEEP_LOSE2 = "sleep_lose2" 

756FN_SLEEP_LOSE3 = "sleep_lose3" 

757FN_SLEEP_EMW = "sleep_emw" 

758FN_SLEEP_CAUSE = "sleep_cause" 

759FN_SLEEP_MAND2 = "sleep_mand2" 

760FN_SLEEP_GAIN1 = "sleep_gain1" 

761FN_SLEEP_GAIN2 = "sleep_gain2" 

762FN_SLEEP_GAIN3 = "sleep_gain3" 

763FN_SLEEP_DUR = "sleep_dur" 

764 

765FN_IRRIT_MAND1 = "irrit_mand1" 

766FN_IRRIT_MAND2 = "irrit_mand2" 

767FN_IRRIT1 = "irrit1" 

768FN_IRRIT2 = "irrit2" 

769FN_IRRIT3 = "irrit3" 

770FN_IRRIT4 = "irrit4" 

771FN_IRRIT_DUR = "irrit_dur" 

772 

773FN_HYPO_MAND1 = "hypo_mand1" 

774FN_HYPO_MAND2 = "hypo_mand2" 

775FN_HYPO1 = "hypo1" 

776FN_HYPO2 = "hypo2" 

777FN_HYPO3 = "hypo3" 

778FN_HYPO4 = "hypo4" 

779FN_HYPO_DUR = "hypo_dur" 

780 

781FN_DEPR_MAND1 = "depr_mand1" 

782FN_DEPR1 = "depr1" 

783FN_DEPR_MAND2 = "depr_mand2" 

784FN_DEPR2 = "depr2" 

785FN_DEPR3 = "depr3" 

786FN_DEPR4 = "depr4" 

787FN_DEPR_CONTENT = "depr_content" 

788FN_DEPR5 = "depr5" 

789FN_DEPR_DUR = "depr_dur" 

790FN_DEPTH1 = "depth1" 

791FN_DEPTH2 = "depth2" 

792FN_DEPTH3 = "depth3" 

793FN_DEPTH4 = "depth4" 

794FN_DEPTH5 = "depth5" 

795FN_DEPTH6 = "depth6" 

796FN_DEPTH7 = "depth7" 

797FN_DEPTH8 = "depth8" 

798FN_DEPTH9 = "depth9" 

799FN_DEPTH10 = "depth10" 

800FN_DOCTOR = "doctor" 

801 

802FN_WORRY_MAND1 = "worry_mand1" 

803FN_WORRY_MAND2 = "worry_mand2" 

804FN_WORRY_CONT1 = "worry_cont1" 

805FN_WORRY2 = "worry2" 

806FN_WORRY3 = "worry3" 

807FN_WORRY4 = "worry4" 

808FN_WORRY5 = "worry5" 

809FN_WORRY_DUR = "worry_dur" 

810 

811FN_ANX_MAND1 = "anx_mand1" 

812FN_ANX_MAND2 = "anx_mand2" 

813FN_ANX_PHOBIA1 = "anx_phobia1" 

814FN_ANX_PHOBIA2 = "anx_phobia2" 

815FN_ANX2 = "anx2" 

816FN_ANX3 = "anx3" 

817FN_ANX4 = "anx4" 

818FN_ANX5 = "anx5" 

819FN_ANX_DUR = "anx_dur" 

820 

821FN_PHOBIAS_MAND = "phobias_mand" 

822FN_PHOBIAS_TYPE1 = "phobias_type1" 

823FN_PHOBIAS1 = "phobias1" 

824FN_PHOBIAS2 = "phobias2" 

825FN_PHOBIAS3 = "phobias3" 

826FN_PHOBIAS4 = "phobias4" 

827FN_PHOBIAS_DUR = "phobias_dur" 

828 

829FN_PANIC_MAND = "panic_mand" 

830FN_PANIC1 = "panic1" 

831FN_PANIC2 = "panic2" 

832FN_PANIC3 = "panic3" 

833FN_PANIC4 = "panic4" 

834FN_PANSYM_A = "pansym_a" 

835FN_PANSYM_B = "pansym_b" 

836FN_PANSYM_C = "pansym_c" 

837FN_PANSYM_D = "pansym_d" 

838FN_PANSYM_E = "pansym_e" 

839FN_PANSYM_F = "pansym_f" 

840FN_PANSYM_G = "pansym_g" 

841FN_PANSYM_H = "pansym_h" 

842FN_PANSYM_I = "pansym_i" 

843FN_PANSYM_J = "pansym_j" 

844FN_PANSYM_K = "pansym_k" 

845FN_PANSYM_L = "pansym_l" 

846FN_PANSYM_M = "pansym_m" 

847FN_PANIC5 = "panic5" 

848FN_PANIC_DUR = "panic_dur" 

849 

850FN_COMP_MAND1 = "comp_mand1" 

851FN_COMP1 = "comp1" 

852FN_COMP2 = "comp2" 

853FN_COMP3 = "comp3" 

854FN_COMP4 = "comp4" 

855FN_COMP_DUR = "comp_dur" 

856 

857FN_OBSESS_MAND1 = "obsess_mand1" 

858FN_OBSESS_MAND2 = "obsess_mand2" 

859FN_OBSESS1 = "obsess1" 

860FN_OBSESS2 = "obsess2" 

861FN_OBSESS3 = "obsess3" 

862FN_OBSESS4 = "obsess4" 

863FN_OBSESS_DUR = "obsess_dur" 

864 

865FN_OVERALL2 = "overall2" 

866 

867PANIC_SYMPTOM_FIELDNAMES = [ 

868 FN_PANSYM_A, 

869 FN_PANSYM_B, 

870 FN_PANSYM_C, 

871 FN_PANSYM_D, 

872 FN_PANSYM_E, 

873 FN_PANSYM_F, 

874 FN_PANSYM_G, 

875 FN_PANSYM_H, 

876 FN_PANSYM_I, 

877 FN_PANSYM_J, 

878 FN_PANSYM_K, 

879 FN_PANSYM_L, 

880 FN_PANSYM_M, 

881] 

882 

883FIELDNAME_FOR_QUESTION = { 

884 # CQ.INTRO_1: # information only 

885 # CQ.INTRO_2: # information only 

886 # CQ.INTRO_DEMOGRAPHICS: # information only 

887 CQ.ETHNIC: FN_ETHNIC, 

888 CQ.MARRIED: FN_MARRIED, 

889 CQ.EMPSTAT: FN_EMPSTAT, 

890 CQ.EMPTYPE: FN_EMPTYPE, 

891 CQ.HOME: FN_HOME, 

892 # CQ.HEALTH_WELLBEING: # information only 

893 CQ.APPETITE1_LOSS_PAST_MONTH: FN_APPETITE1, 

894 CQ.WEIGHT1_LOSS_PAST_MONTH: FN_WEIGHT1, 

895 CQ.WEIGHT2_TRYING_TO_LOSE: FN_WEIGHT2, 

896 CQ.WEIGHT3_LOST_LOTS: FN_WEIGHT3, 

897 CQ.APPETITE2_INCREASE_PAST_MONTH: FN_APPETITE2, 

898 CQ.WEIGHT4_INCREASE_PAST_MONTH: FN_WEIGHT4, 

899 # CQ.WEIGHT4A: not used (= WEIGHT4 + pregnancy option) 

900 CQ.WEIGHT5_GAINED_LOTS: FN_WEIGHT5, 

901 CQ.GP_YEAR: FN_GP_YEAR, 

902 CQ.DISABLE: FN_DISABLE, 

903 CQ.ILLNESS: FN_ILLNESS, 

904 CQ.SOMATIC_MAND1_PAIN_PAST_MONTH: FN_SOMATIC_MAND1, 

905 CQ.SOMATIC_PAIN1_PSYCHOL_EXAC: FN_SOMATIC_PAIN1, 

906 CQ.SOMATIC_PAIN2_DAYS_PAST_WEEK: FN_SOMATIC_PAIN2, 

907 CQ.SOMATIC_PAIN3_GT_3H_ANY_DAY: FN_SOMATIC_PAIN3, 

908 CQ.SOMATIC_PAIN4_UNPLEASANT: FN_SOMATIC_PAIN4, 

909 CQ.SOMATIC_PAIN5_INTERRUPTED_INTERESTING: FN_SOMATIC_PAIN5, 

910 CQ.SOMATIC_MAND2_DISCOMFORT: FN_SOMATIC_MAND2, 

911 CQ.SOMATIC_DIS1_PSYCHOL_EXAC: FN_SOMATIC_DIS1, 

912 CQ.SOMATIC_DIS2_DAYS_PAST_WEEK: FN_SOMATIC_DIS2, 

913 CQ.SOMATIC_DIS3_GT_3H_ANY_DAY: FN_SOMATIC_DIS3, 

914 CQ.SOMATIC_DIS4_UNPLEASANT: FN_SOMATIC_DIS4, 

915 CQ.SOMATIC_DIS5_INTERRUPTED_INTERESTING: FN_SOMATIC_DIS5, 

916 CQ.SOMATIC_DUR: FN_SOMATIC_DUR, 

917 CQ.FATIGUE_MAND1_TIRED_PAST_MONTH: FN_FATIGUE_MAND1, 

918 CQ.FATIGUE_CAUSE1_TIRED: FN_FATIGUE_CAUSE1, 

919 CQ.FATIGUE_TIRED1_DAYS_PAST_WEEK: FN_FATIGUE_TIRED1, 

920 CQ.FATIGUE_TIRED2_GT_3H_ANY_DAY: FN_FATIGUE_TIRED2, 

921 CQ.FATIGUE_TIRED3_HAD_TO_PUSH: FN_FATIGUE_TIRED3, 

922 CQ.FATIGUE_TIRED4_DURING_ENJOYABLE: FN_FATIGUE_TIRED4, 

923 CQ.FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH: FN_FATIGUE_MAND2, 

924 CQ.FATIGUE_CAUSE2_LACK_ENERGY: FN_FATIGUE_CAUSE2, 

925 CQ.FATIGUE_ENERGY1_DAYS_PAST_WEEK: FN_FATIGUE_ENERGY1, 

926 CQ.FATIGUE_ENERGY2_GT_3H_ANY_DAY: FN_FATIGUE_ENERGY2, 

927 CQ.FATIGUE_ENERGY3_HAD_TO_PUSH: FN_FATIGUE_ENERGY3, 

928 CQ.FATIGUE_ENERGY4_DURING_ENJOYABLE: FN_FATIGUE_ENERGY4, 

929 CQ.FATIGUE_DUR: FN_FATIGUE_DUR, 

930 CQ.CONC_MAND1_POOR_CONC_PAST_MONTH: FN_CONC_MAND1, 

931 CQ.CONC_MAND2_FORGETFUL_PAST_MONTH: FN_CONC_MAND2, 

932 CQ.CONC1_CONC_DAYS_PAST_WEEK: FN_CONC1, 

933 CQ.CONC2_CONC_FOR_TV_READING_CONVERSATION: FN_CONC2, 

934 CQ.CONC3_CONC_PREVENTED_ACTIVITIES: FN_CONC3, 

935 CQ.CONC_DUR: FN_CONC_DUR, 

936 CQ.CONC4_FORGOTTEN_IMPORTANT: FN_CONC4, 

937 CQ.FORGET_DUR: FN_FORGET_DUR, 

938 CQ.SLEEP_MAND1_LOSS_PAST_MONTH: FN_SLEEP_MAND1, 

939 CQ.SLEEP_LOSE1_NIGHTS_PAST_WEEK: FN_SLEEP_LOSE1, 

940 CQ.SLEEP_LOSE2_DIS_WORST_DURATION: FN_SLEEP_LOSE2, 

941 CQ.SLEEP_LOSE3_NIGHTS_GT_3H_DIS_PAST_WEEK: FN_SLEEP_LOSE3, 

942 CQ.SLEEP_EMW_PAST_WEEK: FN_SLEEP_EMW, 

943 CQ.SLEEP_CAUSE: FN_SLEEP_CAUSE, 

944 CQ.SLEEP_MAND2_GAIN_PAST_MONTH: FN_SLEEP_MAND2, 

945 CQ.SLEEP_GAIN1_NIGHTS_PAST_WEEK: FN_SLEEP_GAIN1, 

946 CQ.SLEEP_GAIN2_EXTRA_ON_LONGEST_NIGHT: FN_SLEEP_GAIN2, 

947 CQ.SLEEP_GAIN3_NIGHTS_GT_3H_EXTRA_PAST_WEEK: FN_SLEEP_GAIN3, 

948 CQ.SLEEP_DUR: FN_SLEEP_DUR, 

949 CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH: FN_IRRIT_MAND1, 

950 CQ.IRRIT_MAND2_THINGS_PAST_MONTH: FN_IRRIT_MAND2, 

951 CQ.IRRIT1_DAYS_PER_WEEK: FN_IRRIT1, 

952 CQ.IRRIT2_GT_1H_ANY_DAY: FN_IRRIT2, 

953 CQ.IRRIT3_WANTED_TO_SHOUT: FN_IRRIT3, 

954 CQ.IRRIT4_ARGUMENTS: FN_IRRIT4, 

955 CQ.IRRIT_DUR: FN_IRRIT_DUR, 

956 CQ.HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH: FN_HYPO_MAND1, 

957 CQ.HYPO_MAND2_WORRIED_RE_SERIOUS_ILLNESS: FN_HYPO_MAND2, 

958 CQ.HYPO1_DAYS_PAST_WEEK: FN_HYPO1, 

959 CQ.HYPO2_WORRY_TOO_MUCH: FN_HYPO2, 

960 CQ.HYPO3_HOW_UNPLEASANT: FN_HYPO3, 

961 CQ.HYPO4_CAN_DISTRACT: FN_HYPO4, 

962 CQ.HYPO_DUR: FN_HYPO_DUR, 

963 CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH: FN_DEPR_MAND1, 

964 CQ.DEPR1_LOW_MOOD_PAST_WEEK: FN_DEPR1, 

965 CQ.DEPR_MAND2_ENJOYMENT_PAST_MONTH: FN_DEPR_MAND2, 

966 CQ.DEPR2_ENJOYMENT_PAST_WEEK: FN_DEPR2, 

967 CQ.DEPR3_DAYS_PAST_WEEK: FN_DEPR3, 

968 CQ.DEPR4_GT_3H_ANY_DAY: FN_DEPR4, 

969 CQ.DEPR_CONTENT: FN_DEPR_CONTENT, 

970 CQ.DEPR5_COULD_CHEER_UP: FN_DEPR5, 

971 CQ.DEPR_DUR: FN_DEPR_DUR, 

972 CQ.DEPTH1_DIURNAL_VARIATION: FN_DEPTH1, 

973 CQ.DEPTH2_LIBIDO: FN_DEPTH2, 

974 CQ.DEPTH3_RESTLESS: FN_DEPTH3, 

975 CQ.DEPTH4_SLOWED: FN_DEPTH4, 

976 CQ.DEPTH5_GUILT: FN_DEPTH5, 

977 CQ.DEPTH6_WORSE_THAN_OTHERS: FN_DEPTH6, 

978 CQ.DEPTH7_HOPELESS: FN_DEPTH7, 

979 CQ.DEPTH8_LNWL: FN_DEPTH8, 

980 CQ.DEPTH9_SUICIDE_THOUGHTS: FN_DEPTH9, 

981 CQ.DEPTH10_SUICIDE_METHOD: FN_DEPTH10, 

982 CQ.DOCTOR: FN_DOCTOR, 

983 # CQ.DOCTOR2_PLEASE_TALK_TO: # info only 

984 # CQ.DEPR_OUTRO: # info only 

985 CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH: FN_WORRY_MAND1, 

986 CQ.WORRY_MAND2_ANY_WORRIES_PAST_MONTH: FN_WORRY_MAND2, 

987 CQ.WORRY_CONT1: FN_WORRY_CONT1, 

988 # CQ.WORRY1_INFO_ONLY: # info only 

989 CQ.WORRY2_DAYS_PAST_WEEK: FN_WORRY2, 

990 CQ.WORRY3_TOO_MUCH: FN_WORRY3, 

991 CQ.WORRY4_HOW_UNPLEASANT: FN_WORRY4, 

992 CQ.WORRY5_GT_3H_ANY_DAY: FN_WORRY5, 

993 CQ.WORRY_DUR: FN_WORRY_DUR, 

994 CQ.ANX_MAND1_ANXIETY_PAST_MONTH: FN_ANX_MAND1, 

995 CQ.ANX_MAND2_TENSION_PAST_MONTH: FN_ANX_MAND2, 

996 CQ.ANX_PHOBIA1_SPECIFIC_PAST_MONTH: FN_ANX_PHOBIA1, 

997 CQ.ANX_PHOBIA2_SPECIFIC_OR_GENERAL: FN_ANX_PHOBIA2, 

998 # CQ.ANX1_INFO_ONLY: # info only 

999 CQ.ANX2_GENERAL_DAYS_PAST_WEEK: FN_ANX2, 

1000 CQ.ANX3_GENERAL_HOW_UNPLEASANT: FN_ANX3, 

1001 CQ.ANX4_GENERAL_PHYSICAL_SYMPTOMS: FN_ANX4, 

1002 CQ.ANX5_GENERAL_GT_3H_ANY_DAY: FN_ANX5, 

1003 CQ.ANX_DUR_GENERAL: FN_ANX_DUR, 

1004 CQ.PHOBIAS_MAND_AVOIDANCE_PAST_MONTH: FN_PHOBIAS_MAND, 

1005 CQ.PHOBIAS_TYPE1: FN_PHOBIAS_TYPE1, 

1006 CQ.PHOBIAS1_DAYS_PAST_WEEK: FN_PHOBIAS1, 

1007 CQ.PHOBIAS2_PHYSICAL_SYMPTOMS: FN_PHOBIAS2, 

1008 CQ.PHOBIAS3_AVOIDANCE: FN_PHOBIAS3, 

1009 CQ.PHOBIAS4_AVOIDANCE_DAYS_PAST_WEEK: FN_PHOBIAS4, 

1010 CQ.PHOBIAS_DUR: FN_PHOBIAS_DUR, 

1011 CQ.PANIC_MAND_PAST_MONTH: FN_PANIC_MAND, 

1012 CQ.PANIC1_NUM_PAST_WEEK: FN_PANIC1, 

1013 CQ.PANIC2_HOW_UNPLEASANT: FN_PANIC2, 

1014 CQ.PANIC3_PANIC_GE_10_MIN: FN_PANIC3, 

1015 CQ.PANIC4_RAPID_ONSET: FN_PANIC4, 

1016 # CQ.PANSYM: # multiple stems 

1017 CQ.PANIC5_ALWAYS_SPECIFIC_TRIGGER: FN_PANIC5, 

1018 CQ.PANIC_DUR: FN_PANIC_DUR, 

1019 # CQ.ANX_OUTRO: # info only 

1020 CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH: FN_COMP_MAND1, 

1021 CQ.COMP1_DAYS_PAST_WEEK: FN_COMP1, 

1022 CQ.COMP2_TRIED_TO_STOP: FN_COMP2, 

1023 CQ.COMP3_UPSETTING: FN_COMP3, 

1024 CQ.COMP4_MAX_N_REPETITIONS: FN_COMP4, 

1025 CQ.COMP_DUR: FN_COMP_DUR, 

1026 CQ.OBSESS_MAND1_OBSESSIONS_PAST_MONTH: FN_OBSESS_MAND1, 

1027 CQ.OBSESS_MAND2_SAME_THOUGHTS_OR_GENERAL: FN_OBSESS_MAND2, 

1028 CQ.OBSESS1_DAYS_PAST_WEEK: FN_OBSESS1, 

1029 CQ.OBSESS2_TRIED_TO_STOP: FN_OBSESS2, 

1030 CQ.OBSESS3_UPSETTING: FN_OBSESS3, 

1031 CQ.OBSESS4_MAX_DURATION: FN_OBSESS4, 

1032 CQ.OBSESS_DUR: FN_OBSESS_DUR, 

1033 # CQ.OVERALL1: # info only 

1034 CQ.OVERALL2_IMPACT_PAST_WEEK: FN_OVERALL2, 

1035} 

1036 

1037# Questions for which 1 = no, 2 = yes (+/- other options) 

1038QUESTIONS_1_NO_2_YES = [ 

1039 CQ.APPETITE1_LOSS_PAST_MONTH, 

1040 CQ.WEIGHT1_LOSS_PAST_MONTH, 

1041 CQ.WEIGHT2_TRYING_TO_LOSE, 

1042 CQ.APPETITE2_INCREASE_PAST_MONTH, 

1043 CQ.WEIGHT4_INCREASE_PAST_MONTH, # may also offer "yes but pregnant" # noqa 

1044 CQ.SOMATIC_MAND1_PAIN_PAST_MONTH, 

1045 CQ.SOMATIC_MAND2_DISCOMFORT, 

1046 CQ.SOMATIC_PAIN3_GT_3H_ANY_DAY, 

1047 CQ.SOMATIC_PAIN5_INTERRUPTED_INTERESTING, # also has other options # noqa 

1048 CQ.SOMATIC_DIS3_GT_3H_ANY_DAY, 

1049 CQ.SOMATIC_DIS5_INTERRUPTED_INTERESTING, # also has other options # noqa 

1050 CQ.FATIGUE_MAND1_TIRED_PAST_MONTH, 

1051 CQ.FATIGUE_TIRED2_GT_3H_ANY_DAY, 

1052 CQ.FATIGUE_TIRED3_HAD_TO_PUSH, 

1053 CQ.FATIGUE_TIRED4_DURING_ENJOYABLE, # also has other options 

1054 CQ.FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH, 

1055 CQ.FATIGUE_ENERGY2_GT_3H_ANY_DAY, 

1056 CQ.FATIGUE_ENERGY3_HAD_TO_PUSH, 

1057 CQ.FATIGUE_ENERGY4_DURING_ENJOYABLE, # also has other options 

1058 CQ.CONC_MAND1_POOR_CONC_PAST_MONTH, 

1059 CQ.CONC_MAND2_FORGETFUL_PAST_MONTH, 

1060 CQ.CONC3_CONC_PREVENTED_ACTIVITIES, 

1061 CQ.CONC4_FORGOTTEN_IMPORTANT, 

1062 CQ.SLEEP_MAND1_LOSS_PAST_MONTH, 

1063 CQ.SLEEP_EMW_PAST_WEEK, 

1064 CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH, 

1065 CQ.IRRIT2_GT_1H_ANY_DAY, 

1066 CQ.HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH, 

1067 CQ.HYPO_MAND2_WORRIED_RE_SERIOUS_ILLNESS, 

1068 CQ.HYPO2_WORRY_TOO_MUCH, 

1069 CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH, 

1070 CQ.DEPR1_LOW_MOOD_PAST_WEEK, 

1071 CQ.DEPR4_GT_3H_ANY_DAY, 

1072 CQ.DEPTH3_RESTLESS, 

1073 CQ.DEPTH4_SLOWED, 

1074 CQ.DEPTH6_WORSE_THAN_OTHERS, 

1075 CQ.DEPTH7_HOPELESS, 

1076 CQ.DEPTH10_SUICIDE_METHOD, 

1077 CQ.WORRY_MAND2_ANY_WORRIES_PAST_MONTH, 

1078 CQ.WORRY3_TOO_MUCH, 

1079 CQ.WORRY5_GT_3H_ANY_DAY, 

1080 CQ.ANX_MAND1_ANXIETY_PAST_MONTH, 

1081 CQ.ANX_PHOBIA1_SPECIFIC_PAST_MONTH, 

1082 CQ.ANX4_GENERAL_PHYSICAL_SYMPTOMS, 

1083 CQ.ANX5_GENERAL_GT_3H_ANY_DAY, 

1084 CQ.PHOBIAS_MAND_AVOIDANCE_PAST_MONTH, 

1085 CQ.PHOBIAS2_PHYSICAL_SYMPTOMS, 

1086 CQ.PHOBIAS3_AVOIDANCE, 

1087 CQ.PANIC4_RAPID_ONSET, 

1088 CQ.PANIC5_ALWAYS_SPECIFIC_TRIGGER, 

1089 CQ.COMP2_TRIED_TO_STOP, 

1090 CQ.COMP3_UPSETTING, 

1091 CQ.OBSESS2_TRIED_TO_STOP, 

1092 CQ.OBSESS3_UPSETTING, 

1093] 

1094# Questions for which 1 = yes, 2 = no (+/- other options) 

1095QUESTIONS_1_YES_2_NO = [ 

1096 CQ.DISABLE, 

1097 CQ.CONC2_CONC_FOR_TV_READING_CONVERSATION, 

1098 CQ.HYPO4_CAN_DISTRACT, 

1099] 

1100# Yes-no (or no-yes) questions but with specific text 

1101QUESTIONS_YN_SPECIFIC_TEXT = [ 

1102 CQ.WEIGHT2_TRYING_TO_LOSE, 

1103 CQ.SOMATIC_PAIN3_GT_3H_ANY_DAY, 

1104 CQ.SOMATIC_DIS3_GT_3H_ANY_DAY, 

1105 CQ.FATIGUE_TIRED2_GT_3H_ANY_DAY, 

1106 CQ.FATIGUE_TIRED3_HAD_TO_PUSH, 

1107 CQ.FATIGUE_ENERGY2_GT_3H_ANY_DAY, 

1108 CQ.FATIGUE_ENERGY3_HAD_TO_PUSH, 

1109 CQ.CONC_MAND1_POOR_CONC_PAST_MONTH, 

1110 CQ.CONC2_CONC_FOR_TV_READING_CONVERSATION, 

1111 CQ.CONC4_FORGOTTEN_IMPORTANT, 

1112 CQ.SLEEP_EMW_PAST_WEEK, 

1113 CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH, 

1114 CQ.IRRIT2_GT_1H_ANY_DAY, 

1115 CQ.HYPO2_WORRY_TOO_MUCH, 

1116 CQ.HYPO4_CAN_DISTRACT, 

1117 CQ.DEPR1_LOW_MOOD_PAST_WEEK, 

1118 CQ.DEPR4_GT_3H_ANY_DAY, 

1119 CQ.DEPTH6_WORSE_THAN_OTHERS, 

1120 CQ.DEPTH7_HOPELESS, 

1121 CQ.WORRY3_TOO_MUCH, 

1122 CQ.WORRY5_GT_3H_ANY_DAY, 

1123 CQ.ANX4_GENERAL_PHYSICAL_SYMPTOMS, 

1124 CQ.ANX5_GENERAL_GT_3H_ANY_DAY, 

1125 CQ.PHOBIAS2_PHYSICAL_SYMPTOMS, 

1126 CQ.PHOBIAS3_AVOIDANCE, 

1127 CQ.COMP2_TRIED_TO_STOP, 

1128 CQ.COMP3_UPSETTING, 

1129 CQ.OBSESS2_TRIED_TO_STOP, 

1130 CQ.OBSESS3_UPSETTING, 

1131] 

1132# Demographics questions (optional for diagnosis) 

1133QUESTIONS_DEMOGRAPHICS = [ 

1134 CQ.ETHNIC, 

1135 CQ.MARRIED, 

1136 CQ.EMPSTAT, 

1137 CQ.EMPTYPE, 

1138 CQ.HOME, 

1139] 

1140# "Questions" that are just a prompt screen 

1141QUESTIONS_PROMPT_ONLY = { 

1142 # Maps questions to their prompt's xstring name 

1143 CQ.INTRO_1: "intro_1", 

1144 CQ.INTRO_2: "intro_2", 

1145 CQ.INTRO_DEMOGRAPHICS: "intro_demographics_statement", 

1146 CQ.HEALTH_WELLBEING: "health_wellbeing_statement", 

1147 CQ.DOCTOR2_PLEASE_TALK_TO: "doctor2", 

1148 CQ.DEPR_OUTRO: "depr_outro", 

1149 CQ.WORRY1_INFO_ONLY: "worry1", 

1150 CQ.ANX1_INFO_ONLY: "anx1", 

1151 CQ.ANX_OUTRO: "anx_outro", 

1152 CQ.OVERALL1_INFO_ONLY: "overall1", 

1153 CQ.THANKS_FINISHED: "end", 

1154} 

1155# "How many days per week" questions 

1156# "Overall duration" questions 

1157QUESTIONS_OVERALL_DURATION = [ 

1158 CQ.SOMATIC_DUR, 

1159 CQ.FATIGUE_DUR, 

1160 CQ.CONC_DUR, 

1161 CQ.FORGET_DUR, 

1162 CQ.SLEEP_DUR, 

1163 CQ.IRRIT_DUR, 

1164 CQ.HYPO_DUR, 

1165 CQ.DEPR_DUR, 

1166 CQ.WORRY_DUR, 

1167 CQ.ANX_DUR_GENERAL, 

1168 CQ.PHOBIAS_DUR, 

1169 CQ.PANIC_DUR, 

1170 CQ.COMP_DUR, 

1171 CQ.OBSESS_DUR, 

1172] 

1173# Multi-way questions, other than yes/no ones. 

1174QUESTIONS_MULTIWAY = { 

1175 # Maps questions to first and last number of answers. 

1176 CQ.WEIGHT3_LOST_LOTS: (1, 2), 

1177 CQ.WEIGHT4_INCREASE_PAST_MONTH: (1, 2), # may be modified to 3 if female 

1178 CQ.WEIGHT5_GAINED_LOTS: (1, 2), 

1179 CQ.GP_YEAR: (0, 4), # unusual; starts at 0 

1180 CQ.ILLNESS: (1, 8), 

1181 CQ.SOMATIC_PAIN1_PSYCHOL_EXAC: (1, 3), 

1182 CQ.SOMATIC_PAIN5_INTERRUPTED_INTERESTING: (1, 3), 

1183 CQ.SOMATIC_DIS1_PSYCHOL_EXAC: (1, 3), 

1184 CQ.SOMATIC_DIS5_INTERRUPTED_INTERESTING: (1, 3), 

1185 CQ.FATIGUE_TIRED4_DURING_ENJOYABLE: (1, 3), 

1186 CQ.FATIGUE_ENERGY4_DURING_ENJOYABLE: (1, 3), 

1187 CQ.SLEEP_LOSE2_DIS_WORST_DURATION: (1, 4), 

1188 CQ.SLEEP_CAUSE: (1, 6), 

1189 CQ.SLEEP_MAND2_GAIN_PAST_MONTH: (1, 3), 

1190 CQ.SLEEP_GAIN2_EXTRA_ON_LONGEST_NIGHT: (1, 4), 

1191 CQ.IRRIT_MAND2_THINGS_PAST_MONTH: (1, 3), 

1192 CQ.IRRIT3_WANTED_TO_SHOUT: (1, 3), 

1193 CQ.IRRIT4_ARGUMENTS: (1, 3), 

1194 CQ.DEPR_MAND2_ENJOYMENT_PAST_MONTH: (1, 3), 

1195 CQ.DEPR2_ENJOYMENT_PAST_WEEK: (1, 3), 

1196 CQ.DEPR5_COULD_CHEER_UP: (1, 3), 

1197 CQ.DEPTH1_DIURNAL_VARIATION: (1, 4), 

1198 CQ.DEPTH2_LIBIDO: (1, 4), 

1199 CQ.DEPTH5_GUILT: (1, 4), 

1200 CQ.DEPTH8_LNWL: (1, 3), 

1201 CQ.DEPTH9_SUICIDE_THOUGHTS: (1, 3), 

1202 CQ.DOCTOR: (1, 3), 

1203 CQ.ANX_PHOBIA2_SPECIFIC_OR_GENERAL: (1, 2), 

1204 CQ.PHOBIAS_TYPE1: (1, 9), 

1205 CQ.PHOBIAS4_AVOIDANCE_DAYS_PAST_WEEK: (1, 3), 

1206 CQ.PANIC_MAND_PAST_MONTH: (1, 3), 

1207 CQ.PANIC1_NUM_PAST_WEEK: (1, 3), 

1208 CQ.PANIC2_HOW_UNPLEASANT: (1, 3), 

1209 CQ.PANIC3_PANIC_GE_10_MIN: (1, 2), 

1210 CQ.COMP4_MAX_N_REPETITIONS: (1, 3), 

1211 CQ.OBSESS_MAND2_SAME_THOUGHTS_OR_GENERAL: (1, 2), 

1212 CQ.OBSESS4_MAX_DURATION: (1, 2), 

1213 CQ.OVERALL2_IMPACT_PAST_WEEK: (1, 4), 

1214} 

1215QUESTIONS_MULTIWAY_WITH_EXTRA_STEM = { 

1216 # Maps questions to first and last number of answers. 

1217 CQ.ETHNIC: (1, 7), # 7 includes our additional "prefer not to say" 

1218 CQ.MARRIED: (1, 6), # 6 includes our additional "prefer not to say" 

1219 CQ.EMPSTAT: (1, 8), # 8 includes our additional "prefer not to say" 

1220 CQ.EMPTYPE: ( 

1221 1, 

1222 7, 

1223 ), # 7 includes our additional "not applicable" + "prefer not to say" # noqa 

1224 CQ.HOME: (1, 7), # 7 includes our additional "prefer not to say" 

1225} 

1226QUESTIONS_DAYS_PER_WEEK = [ 

1227 CQ.SOMATIC_PAIN2_DAYS_PAST_WEEK, 

1228 CQ.SOMATIC_DIS2_DAYS_PAST_WEEK, 

1229 CQ.FATIGUE_TIRED1_DAYS_PAST_WEEK, 

1230 CQ.FATIGUE_ENERGY1_DAYS_PAST_WEEK, 

1231 CQ.CONC1_CONC_DAYS_PAST_WEEK, 

1232 CQ.IRRIT1_DAYS_PER_WEEK, 

1233 CQ.HYPO1_DAYS_PAST_WEEK, 

1234 CQ.DEPR3_DAYS_PAST_WEEK, 

1235 CQ.WORRY2_DAYS_PAST_WEEK, 

1236 CQ.ANX2_GENERAL_DAYS_PAST_WEEK, 

1237 CQ.PHOBIAS1_DAYS_PAST_WEEK, 

1238 # not this: CQ.PHOBIAS4_AVOIDANCE_FREQUENCY -- different phrasing 

1239 # not this: CQ.PANIC1_FREQUENCY 

1240 CQ.COMP1_DAYS_PAST_WEEK, 

1241 CQ.OBSESS1_DAYS_PAST_WEEK, 

1242] 

1243QUESTIONS_NIGHTS_PER_WEEK = [ 

1244 CQ.SLEEP_LOSE1_NIGHTS_PAST_WEEK, 

1245 CQ.SLEEP_LOSE3_NIGHTS_GT_3H_DIS_PAST_WEEK, 

1246 CQ.SLEEP_GAIN1_NIGHTS_PAST_WEEK, # (*) see below 

1247 # (*) Probably an error in the original: 

1248 # "On how many nights in the PAST SEVEN NIGHTS did you have problems 

1249 # with your sleep? (1) None. (2) Between one and three days. (3) Four 

1250 # days or more." Note day/night confusion. Altered to "nights". 

1251 CQ.SLEEP_GAIN3_NIGHTS_GT_3H_EXTRA_PAST_WEEK, 

1252] 

1253QUESTIONS_HOW_UNPLEASANT_STANDARD = [ 

1254 CQ.SOMATIC_PAIN4_UNPLEASANT, 

1255 CQ.SOMATIC_DIS4_UNPLEASANT, 

1256 CQ.HYPO3_HOW_UNPLEASANT, 

1257 CQ.WORRY4_HOW_UNPLEASANT, 

1258 CQ.ANX3_GENERAL_HOW_UNPLEASANT, 

1259] 

1260QUESTIONS_FATIGUE_CAUSES = [ 

1261 CQ.FATIGUE_CAUSE1_TIRED, 

1262 CQ.FATIGUE_CAUSE2_LACK_ENERGY, 

1263] 

1264QUESTIONS_STRESSORS = [CQ.DEPR_CONTENT, CQ.WORRY_CONT1] 

1265QUESTIONS_NO_SOMETIMES_OFTEN = [ 

1266 CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH, 

1267 CQ.ANX_MAND2_TENSION_PAST_MONTH, 

1268 CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH, 

1269 CQ.OBSESS_MAND1_OBSESSIONS_PAST_MONTH, 

1270 # and no-sometimes-often values also used by: 

1271 # CQ.PANIC_MAND_PAST_MONTH 

1272 # ... but with variations on the text. 

1273] 

1274 

1275 

1276# ============================================================================= 

1277# Ancillary functions 

1278# ============================================================================= 

1279 

1280 

1281def fieldname_for_q(q: CisrQuestion) -> str: 

1282 return FIELDNAME_FOR_QUESTION.get(q, "") 

1283 

1284 

1285def enum_to_int(qe: CisrQuestion) -> int: 

1286 return qe.value 

1287 

1288 

1289def int_to_enum(qi: int) -> CisrQuestion: 

1290 # https://stackoverflow.com/questions/23951641/how-to-convert-int-to-enum-in-python # noqa 

1291 return CisrQuestion(qi) 

1292 

1293 

1294# ============================================================================= 

1295# CisrResult 

1296# ============================================================================= 

1297 

1298 

1299class CisrResult(object): 

1300 def __init__(self, record_decisions: bool = False) -> None: 

1301 self.incomplete = False 

1302 self.record_decisions = record_decisions 

1303 self.decisions = [] # type: List[str] 

1304 

1305 # Symptom scoring 

1306 self.depression = 0 # DEPR in original 

1307 self.depr_crit_1_mood_anhedonia_energy = 0 # DEPCRIT1 

1308 self.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui = 0 # DEPCRIT2 

1309 self.depr_crit_3_somatic_synd = 0 # DEPCRIT3 

1310 # ... looks to me like the ICD-10 criteria for somatic syndrome 

1311 # (e.g. F32.01, F32.11, F33.01, F33.11), with the "do you cheer up 

1312 # when..." question (DEPR5) being the one for "lack of emotional 

1313 # reactions to events or activities that normally produce an 

1314 # emotional response". 

1315 self.weight_change = ( 

1316 WTCHANGE_NONE_OR_APPETITE_INCREASE # WTCHANGE IN original # noqa 

1317 ) 

1318 self.somatic_symptoms = 0 # SOMATIC in original 

1319 self.fatigue = 0 # FATIGUE in original 

1320 self.neurasthenia = 0 # NEURAS in original 

1321 self.concentration_poor = 0 # CONC in original 

1322 self.sleep_problems = 0 # SLEEP in original 

1323 self.sleep_change = SLEEPCHANGE_NONE # SLEEPCH in original 

1324 self.depressive_thoughts = 0 # DEPTHTS in original 

1325 self.irritability = 0 # IRRIT in original 

1326 self.diurnal_mood_variation = DIURNAL_MOOD_VAR_NONE # DVM in original 

1327 self.libido_decreased = False # LIBID in original 

1328 self.psychomotor_changes = PSYCHOMOTOR_NONE # PSYCHMOT in original 

1329 self.suicidality = ( 

1330 SUICIDE_INTENT_NONE 

1331 ) # type: int # SUICID in original # noqa 

1332 self.depression_at_least_2_weeks = False # DEPR_DUR >= 2 in original 

1333 

1334 self.hypochondria = 0 # HYPO in original 

1335 self.worry = 0 # WORRY in original 

1336 self.anxiety = 0 # ANX in original 

1337 self.anxiety_physical_symptoms = False # AN4 == 2 in original 

1338 self.anxiety_at_least_2_weeks = False # ANX_DUR >= 2 in original 

1339 self.phobias_flag = False # PHOBIAS_FLAG in original 

1340 self.phobias_score = 0 # PHOBIAS in original 

1341 self.phobias_type = 0 # PHOBIAS_TYPE in original 

1342 self.phobic_avoidance = False # PHOBIAS3 == 2 in original 

1343 self.panic = 0 # PANIC in original 

1344 self.panic_rapid_onset = False # PANIC4 == 2 in original 

1345 self.panic_symptoms_total = 0 # PANSYTOT in original 

1346 

1347 self.compulsions = 0 # COMP in original 

1348 self.compulsions_tried_to_stop = False # COMP2 == 2 in original 

1349 self.compulsions_at_least_2_weeks = False # COMP_DUR >= 2 in original 

1350 self.obsessions = 0 # OBSESS in original 

1351 self.obsessions_tried_to_stop = False # OBSESS2 == 2 in original 

1352 self.obsessions_at_least_2_weeks = False # OBSESS_DUR >= 2 in original 

1353 

1354 self.functional_impairment = 0 # IMPAIR in original 

1355 

1356 # Disorder flags 

1357 self.obsessive_compulsive_disorder = False # OBCOMP in original 

1358 self.depression_mild = False # DEPRMILD in original 

1359 self.depression_moderate = False # DEPRMOD in original 

1360 self.depression_severe = False # DEPRSEV in original 

1361 self.chronic_fatigue_syndrome = False # CFS in original 

1362 self.generalized_anxiety_disorder = False # GAD in original 

1363 self.phobia_agoraphobia = False # PHOBAG in original 

1364 self.phobia_social = False # PHOBSOC in original 

1365 self.phobia_specific = False # PHOBSPEC in original 

1366 self.panic_disorder = False # PANICD in original 

1367 

1368 # Final diagnoses 

1369 self.diagnosis_1 = DIAG_0_NO_DIAGNOSIS # DIAG1 in original 

1370 self.diagnosis_2 = DIAG_0_NO_DIAGNOSIS # DIAG2 in original 

1371 

1372 # ------------------------------------------------------------------------- 

1373 # Overall scoring 

1374 # ------------------------------------------------------------------------- 

1375 

1376 def get_score(self) -> int: # SCORE in original 

1377 return ( 

1378 self.somatic_symptoms 

1379 + self.fatigue 

1380 + self.concentration_poor 

1381 + self.sleep_problems 

1382 + self.irritability 

1383 + self.hypochondria 

1384 + self.depression 

1385 + self.depressive_thoughts 

1386 + self.worry 

1387 + self.anxiety 

1388 + self.phobias_score 

1389 + self.panic 

1390 + self.compulsions 

1391 + self.obsessions 

1392 ) 

1393 

1394 def needs_impairment_question(self) -> bool: 

1395 # code in OVERALL1 in original 

1396 threshold = 2 # for all symptoms 

1397 return ( 

1398 self.somatic_symptoms >= threshold 

1399 or self.hypochondria >= threshold 

1400 or self.fatigue >= threshold 

1401 or self.sleep_problems >= threshold 

1402 or self.irritability >= threshold 

1403 or self.concentration_poor >= threshold 

1404 or self.depression >= threshold 

1405 or self.depressive_thoughts >= threshold 

1406 or self.phobias_score >= threshold 

1407 or self.worry >= threshold 

1408 or self.anxiety >= threshold 

1409 or self.panic >= threshold 

1410 or self.compulsions >= threshold 

1411 or self.obsessions >= threshold 

1412 ) 

1413 

1414 def has_somatic_syndrome(self) -> bool: 

1415 return self.depr_crit_3_somatic_synd >= SOMATIC_SYNDROME_CRITERION 

1416 

1417 def get_final_page(self) -> CisrQuestion: 

1418 # see chooseFinalPage() in the C++ version 

1419 return ( 

1420 CQ.OVERALL1_INFO_ONLY 

1421 if self.needs_impairment_question() 

1422 else CQ.THANKS_FINISHED 

1423 ) 

1424 

1425 def decide(self, decision: str) -> None: 

1426 if self.record_decisions: 

1427 self.decisions.append(decision) 

1428 

1429 def _showint(self, name: str, value: int) -> None: 

1430 self.decide(f"{SCORE_PREFIX}{name}: {value}") 

1431 

1432 def _showbool(self, name: str, value: bool) -> None: 

1433 self.decide(f"{SCORE_PREFIX}{name}: {'true' if value else 'false'}") 

1434 

1435 def diagnosis_name(self, diagnosis_code: int) -> str: 

1436 if self.incomplete: 

1437 # Do NOT offer diagnostic information based on partial data. 

1438 # Might be dangerous (e.g. say "mild depressive episode" when it's 

1439 # severe + incomplete information). 

1440 return "INFORMATION INCOMPLETE" 

1441 

1442 if diagnosis_code == DIAG_0_NO_DIAGNOSIS: 

1443 return "No diagnosis identified" 

1444 elif diagnosis_code == DIAG_1_MIXED_ANX_DEPR_DIS_MILD: 

1445 return "Mixed anxiety and depressive disorder (mild)" 

1446 elif diagnosis_code == DIAG_2_GENERALIZED_ANX_DIS_MILD: 

1447 return "Generalized anxiety disorder (mild)" 

1448 elif diagnosis_code == DIAG_3_OBSESSIVE_COMPULSIVE_DIS: 

1449 return "Obsessive–compulsive disorder" 

1450 elif diagnosis_code == DIAG_4_MIXED_ANX_DEPR_DIS: 

1451 return "Mixed anxiety and depressive disorder" 

1452 elif diagnosis_code == DIAG_5_SPECIFIC_PHOBIA: 

1453 return "Specific (isolated) phobia" 

1454 elif diagnosis_code == DIAG_6_SOCIAL_PHOBIA: 

1455 return "Social phobia" 

1456 elif diagnosis_code == DIAG_7_AGORAPHOBIA: 

1457 return "Agoraphobia" 

1458 elif diagnosis_code == DIAG_8_GENERALIZED_ANX_DIS: 

1459 return "Generalized anxiety disorder" 

1460 elif diagnosis_code == DIAG_9_PANIC_DIS: 

1461 return "Panic disorder" 

1462 elif diagnosis_code == DIAG_10_MILD_DEPR_EPISODE: 

1463 return "Mild depressive episode" 

1464 elif diagnosis_code == DIAG_11_MOD_DEPR_EPISODE: 

1465 return "Moderate depressive episode" 

1466 elif diagnosis_code == DIAG_12_SEVERE_DEPR_EPISODE: 

1467 return "Severe depressive episode" 

1468 else: 

1469 return "[INTERNAL ERROR: BAD DIAGNOSIS CODE]" 

1470 

1471 def diagnosis_icd10_code(self, diagnosis_code: int) -> str: 

1472 if self.incomplete: 

1473 return "" 

1474 

1475 if diagnosis_code == DIAG_0_NO_DIAGNOSIS: 

1476 return "" 

1477 elif diagnosis_code == DIAG_1_MIXED_ANX_DEPR_DIS_MILD: 

1478 return "F41.2" # no sub-code for "mild" 

1479 elif diagnosis_code == DIAG_2_GENERALIZED_ANX_DIS_MILD: 

1480 return "F41.1" # no sub-code for "mild" 

1481 elif diagnosis_code == DIAG_3_OBSESSIVE_COMPULSIVE_DIS: 

1482 return "Obsessive–compulsive disorder" 

1483 elif diagnosis_code == DIAG_4_MIXED_ANX_DEPR_DIS: 

1484 return "F41.2" 

1485 elif diagnosis_code == DIAG_5_SPECIFIC_PHOBIA: 

1486 return "F40.2" 

1487 elif diagnosis_code == DIAG_6_SOCIAL_PHOBIA: 

1488 return "F40.1" 

1489 elif diagnosis_code == DIAG_7_AGORAPHOBIA: 

1490 return "F40.0" # not clear whether F40.00/F40.01 are distinguished 

1491 elif diagnosis_code == DIAG_8_GENERALIZED_ANX_DIS: 

1492 return "F41.1" 

1493 elif diagnosis_code == DIAG_9_PANIC_DIS: 

1494 return "F41.0" 

1495 elif diagnosis_code == DIAG_10_MILD_DEPR_EPISODE: 

1496 if self.has_somatic_syndrome(): 

1497 return "F32.01" 

1498 else: 

1499 return "F32.00" 

1500 elif diagnosis_code == DIAG_11_MOD_DEPR_EPISODE: 

1501 if self.has_somatic_syndrome(): 

1502 return "F32.11" 

1503 else: 

1504 return "F32.10" 

1505 elif diagnosis_code == DIAG_12_SEVERE_DEPR_EPISODE: 

1506 return "F32.2 or F32.3" 

1507 else: 

1508 return "[INTERNAL ERROR: BAD DIAGNOSIS CODE]" 

1509 

1510 def has_diagnosis(self, diagnosis_code: int) -> bool: 

1511 return not self.incomplete and diagnosis_code != DIAG_0_NO_DIAGNOSIS 

1512 

1513 def has_diagnosis_1(self) -> bool: 

1514 return self.has_diagnosis(self.diagnosis_1) 

1515 

1516 def has_diagnosis_2(self) -> bool: 

1517 return self.has_diagnosis(self.diagnosis_1) 

1518 

1519 def diagnosis_1_name(self) -> str: 

1520 return self.diagnosis_name(self.diagnosis_1) 

1521 

1522 def diagnosis_1_icd10_code(self) -> str: 

1523 return self.diagnosis_icd10_code(self.diagnosis_1) 

1524 

1525 def diagnosis_2_name(self) -> str: 

1526 return self.diagnosis_name(self.diagnosis_2) 

1527 

1528 def diagnosis_2_icd10_code(self) -> str: 

1529 return self.diagnosis_icd10_code(self.diagnosis_2) 

1530 

1531 def finalize(self) -> None: 

1532 at_least_1_activity_impaired = ( 

1533 self.functional_impairment >= OVERALL_IMPAIRMENT_STOP_1_ACTIVITY 

1534 ) 

1535 score = self.get_score() 

1536 

1537 # GAD 

1538 if ( 

1539 self.anxiety >= 2 

1540 and self.anxiety_physical_symptoms 

1541 and self.anxiety_at_least_2_weeks 

1542 ): 

1543 self.decide( 

1544 "Anxiety score >= 2 AND physical symptoms of anxiety AND " 

1545 "anxiety for at least 2 weeks. " 

1546 "Setting generalized_anxiety_disorder." 

1547 ) 

1548 self.generalized_anxiety_disorder = True 

1549 

1550 # Panic 

1551 if self.panic >= 3 and self.panic_rapid_onset: 

1552 self.decide( 

1553 "Panic score >= 3 AND panic_rapid_onset. " 

1554 "Setting panic_disorder." 

1555 ) 

1556 self.panic_disorder = True 

1557 

1558 # Phobias 

1559 if ( 

1560 self.phobias_type == PHOBIATYPES_AGORAPHOBIA 

1561 and self.phobic_avoidance 

1562 and self.phobias_score >= 2 

1563 ): 

1564 self.decide( 

1565 "Phobia type is agoraphobia AND phobic avoidance AND" 

1566 "phobia score >= 2. Setting phobia_agoraphobia." 

1567 ) 

1568 self.phobia_agoraphobia = True 

1569 if ( 

1570 self.phobias_type == PHOBIATYPES_SOCIAL 

1571 and self.phobic_avoidance 

1572 and self.phobias_score >= 2 

1573 ): 

1574 self.decide( 

1575 "Phobia type is social AND phobic avoidance AND" 

1576 "phobia score >= 2. Setting phobia_social." 

1577 ) 

1578 self.phobia_social = True 

1579 if ( 

1580 self.phobias_type == PHOBIATYPES_SOCIAL 

1581 and self.phobic_avoidance 

1582 and self.phobias_score >= 2 

1583 ): 

1584 self.decide( 

1585 "Phobia type is (animals/enclosed/heights OR other) AND " 

1586 "phobic avoidance AND phobia score >= 2. " 

1587 "Setting phobia_specific." 

1588 ) 

1589 self.phobia_specific = True 

1590 

1591 # OCD 

1592 if ( 

1593 self.obsessions + self.compulsions >= 6 

1594 and self.obsessions_tried_to_stop 

1595 and self.obsessions_at_least_2_weeks 

1596 and at_least_1_activity_impaired 

1597 ): 

1598 self.decide( 

1599 "obsessions + compulsions >= 6 AND " 

1600 "tried to stop obsessions AND " 

1601 "obsessions for at least 2 weeks AND " 

1602 "at least 1 activity impaired. " 

1603 "Setting obsessive_compulsive_disorder." 

1604 ) 

1605 self.obsessive_compulsive_disorder = True 

1606 if ( 

1607 self.obsessions + self.compulsions >= 6 

1608 and self.compulsions_tried_to_stop 

1609 and self.compulsions_at_least_2_weeks 

1610 and at_least_1_activity_impaired 

1611 ): 

1612 self.decide( 

1613 "obsessions + compulsions >= 6 AND " 

1614 "tried to stop compulsions AND " 

1615 "compulsions for at least 2 weeks AND " 

1616 "at least 1 activity impaired. " 

1617 "Setting obsessive_compulsive_disorder." 

1618 ) 

1619 self.obsessive_compulsive_disorder = True 

1620 if ( 

1621 self.obsessions == 4 

1622 and self.obsessions_tried_to_stop 

1623 and self.obsessions_at_least_2_weeks 

1624 and at_least_1_activity_impaired 

1625 ): 

1626 # NOTE: 4 is the maximum for obsessions 

1627 self.decide( 

1628 "obsessions == 4 AND " 

1629 "tried to stop obsessions AND " 

1630 "obsessions for at least 2 weeks AND " 

1631 "at least 1 activity impaired. " 

1632 "Setting obsessive_compulsive_disorder." 

1633 ) 

1634 self.obsessive_compulsive_disorder = True 

1635 if ( 

1636 self.compulsions == 4 

1637 and self.compulsions_tried_to_stop 

1638 and self.compulsions_at_least_2_weeks 

1639 and at_least_1_activity_impaired 

1640 ): 

1641 # NOTE: 4 is the maximum for compulsions 

1642 self.decide( 

1643 "compulsions == 4 AND " 

1644 "tried to stop compulsions AND " 

1645 "compulsions for at least 2 weeks AND " 

1646 "at least 1 activity impaired. " 

1647 "Setting obsessive_compulsive_disorder." 

1648 ) 

1649 self.obsessive_compulsive_disorder = True 

1650 

1651 # Depression 

1652 if ( 

1653 self.depression_at_least_2_weeks 

1654 and self.depr_crit_1_mood_anhedonia_energy > 1 

1655 and self.depr_crit_1_mood_anhedonia_energy 

1656 + self.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui 

1657 > 3 

1658 ): 

1659 self.decide( 

1660 "Depressive symptoms >=2 weeks AND " 

1661 "depr_crit_1_mood_anhedonia_energy > 1 AND " 

1662 "depr_crit_1_mood_anhedonia_energy + " 

1663 "depr_crit_2_app_cnc_slp_mtr_glt_wth_sui > 3. " 

1664 "Setting depression_mild." 

1665 ) 

1666 self.depression_mild = True 

1667 if ( 

1668 self.depression_at_least_2_weeks 

1669 and self.depr_crit_1_mood_anhedonia_energy > 1 

1670 and ( 

1671 self.depr_crit_1_mood_anhedonia_energy 

1672 + self.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui 

1673 ) 

1674 > 5 

1675 ): 

1676 self.decide( 

1677 "Depressive symptoms >=2 weeks AND " 

1678 "depr_crit_1_mood_anhedonia_energy > 1 AND " 

1679 "depr_crit_1_mood_anhedonia_energy + " 

1680 "depr_crit_2_app_cnc_slp_mtr_glt_wth_sui > 5. " 

1681 "Setting depression_moderate." 

1682 ) 

1683 self.depression_moderate = True 

1684 if ( 

1685 self.depression_at_least_2_weeks 

1686 and self.depr_crit_1_mood_anhedonia_energy == 3 

1687 and self.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui > 4 

1688 ): 

1689 self.decide( 

1690 "Depressive symptoms >=2 weeks AND " 

1691 "depr_crit_1_mood_anhedonia_energy == 3 AND " 

1692 "depr_crit_2_app_cnc_slp_mtr_glt_wth_sui > 4. " 

1693 "Setting depression_severe." 

1694 ) 

1695 self.depression_severe = True 

1696 

1697 # CFS 

1698 if self.neurasthenia >= 2: 

1699 # The original had a pointless check for "DIAG1 == 0" too, but that 

1700 # was always true. 

1701 self.decide("neurasthenia >= 2. Setting chronic_fatigue_syndrome.") 

1702 self.chronic_fatigue_syndrome = True 

1703 

1704 # Final diagnostic hierarchy 

1705 

1706 # ... primary diagnosis 

1707 if score >= 12: 

1708 self.decide( 

1709 "Total score >= 12. Setting diagnosis_1 to " 

1710 "DIAG_1_MIXED_ANX_DEPR_DIS_MILD." 

1711 ) 

1712 self.diagnosis_1 = DIAG_1_MIXED_ANX_DEPR_DIS_MILD 

1713 if self.generalized_anxiety_disorder: 

1714 self.decide( 

1715 "generalized_anxiety_disorder is true. Setting " 

1716 "diagnosis_1 to DIAG_2_GENERALIZED_ANX_DIS_MILD." 

1717 ) 

1718 self.diagnosis_1 = DIAG_2_GENERALIZED_ANX_DIS_MILD 

1719 if self.obsessive_compulsive_disorder: 

1720 self.decide( 

1721 "obsessive_compulsive_disorder is true. Setting " 

1722 "diagnosis_1 to DIAG_3_OBSESSIVE_COMPULSIVE_DIS." 

1723 ) 

1724 self.diagnosis_1 = DIAG_3_OBSESSIVE_COMPULSIVE_DIS 

1725 if score >= 20: 

1726 self.decide( 

1727 "Total score >= 20. Setting diagnosis_1 to " 

1728 "DIAG_4_MIXED_ANX_DEPR_DIS." 

1729 ) 

1730 self.diagnosis_1 = DIAG_4_MIXED_ANX_DEPR_DIS 

1731 if self.phobia_specific: 

1732 self.decide( 

1733 "phobia_specific is true. Setting diagnosis_1 to " 

1734 "DIAG_5_SPECIFIC_PHOBIA." 

1735 ) 

1736 self.diagnosis_1 = DIAG_5_SPECIFIC_PHOBIA 

1737 if self.phobia_social: 

1738 self.decide( 

1739 "phobia_social is true. Setting diagnosis_1 to " 

1740 "DIAG_6_SOCIAL_PHOBIA." 

1741 ) 

1742 self.diagnosis_1 = DIAG_6_SOCIAL_PHOBIA 

1743 if self.phobia_agoraphobia: 

1744 self.decide( 

1745 "phobia_agoraphobia is true. Setting diagnosis_1 to " 

1746 "DIAG_7_AGORAPHOBIA." 

1747 ) 

1748 self.diagnosis_1 = DIAG_7_AGORAPHOBIA 

1749 if self.generalized_anxiety_disorder and score >= 20: 

1750 self.decide( 

1751 "generalized_anxiety_disorder is true AND " 

1752 "score >= 20. Setting diagnosis_1 to " 

1753 "DIAG_8_GENERALIZED_ANX_DIS." 

1754 ) 

1755 self.diagnosis_1 = DIAG_8_GENERALIZED_ANX_DIS 

1756 if self.panic_disorder: 

1757 self.decide( 

1758 "panic_disorder is true. Setting diagnosis_1 to " 

1759 "DIAG_9_PANIC_DIS." 

1760 ) 

1761 self.diagnosis_1 = DIAG_9_PANIC_DIS 

1762 if self.depression_mild: 

1763 self.decide( 

1764 "depression_mild is true. Setting diagnosis_1 to " 

1765 "DIAG_10_MILD_DEPR_EPISODE." 

1766 ) 

1767 self.diagnosis_1 = DIAG_10_MILD_DEPR_EPISODE 

1768 if self.depression_moderate: 

1769 self.decide( 

1770 "depression_moderate is true. Setting diagnosis_1 to " 

1771 "DIAG_11_MOD_DEPR_EPISODE." 

1772 ) 

1773 self.diagnosis_1 = DIAG_11_MOD_DEPR_EPISODE 

1774 if self.depression_severe: 

1775 self.decide( 

1776 "depression_severe is true. Setting diagnosis_1 to " 

1777 "DIAG_12_SEVERE_DEPR_EPISODE." 

1778 ) 

1779 self.diagnosis_1 = DIAG_12_SEVERE_DEPR_EPISODE 

1780 

1781 # ... secondary diagnosis 

1782 if score >= 12 and self.diagnosis_1 >= 2: 

1783 self.decide( 

1784 "score >= 12 AND diagnosis_1 >= 2. " 

1785 "Setting diagnosis_2 to DIAG_1_MIXED_ANX_DEPR_DIS_MILD." 

1786 ) 

1787 self.diagnosis_2 = DIAG_1_MIXED_ANX_DEPR_DIS_MILD 

1788 if self.generalized_anxiety_disorder and self.diagnosis_1 >= 3: 

1789 self.decide( 

1790 "generalized_anxiety_disorder is true AND " 

1791 "diagnosis_1 >= 3. " 

1792 "Setting diagnosis_2 to DIAG_2_GENERALIZED_ANX_DIS_MILD." 

1793 ) 

1794 self.diagnosis_2 = DIAG_2_GENERALIZED_ANX_DIS_MILD 

1795 if self.obsessive_compulsive_disorder and self.diagnosis_1 >= 4: 

1796 self.decide( 

1797 "obsessive_compulsive_disorder is true AND " 

1798 "diagnosis_1 >= 4. " 

1799 "Setting diagnosis_2 to DIAG_3_OBSESSIVE_COMPULSIVE_DIS." 

1800 ) 

1801 self.diagnosis_2 = DIAG_3_OBSESSIVE_COMPULSIVE_DIS 

1802 if score >= 20 and self.diagnosis_1 >= 5: 

1803 self.decide( 

1804 "score >= 20 AND diagnosis_1 >= 5. " 

1805 "Setting diagnosis_2 to DIAG_4_MIXED_ANX_DEPR_DIS." 

1806 ) 

1807 self.diagnosis_2 = DIAG_4_MIXED_ANX_DEPR_DIS 

1808 if self.phobia_specific and self.diagnosis_1 >= 6: 

1809 self.decide( 

1810 "phobia_specific is true AND diagnosis_1 >= 6. " 

1811 "Setting diagnosis_2 to DIAG_5_SPECIFIC_PHOBIA." 

1812 ) 

1813 self.diagnosis_2 = DIAG_5_SPECIFIC_PHOBIA 

1814 if self.phobia_social and self.diagnosis_1 >= 7: 

1815 self.decide( 

1816 "phobia_social is true AND diagnosis_1 >= 7. " 

1817 "Setting diagnosis_2 to DIAG_6_SOCIAL_PHOBIA." 

1818 ) 

1819 self.diagnosis_2 = DIAG_6_SOCIAL_PHOBIA 

1820 if self.phobia_agoraphobia and self.diagnosis_1 >= 8: 

1821 self.decide( 

1822 "phobia_agoraphobia is true AND diagnosis_1 >= 8. " 

1823 "Setting diagnosis_2 to DIAG_7_AGORAPHOBIA." 

1824 ) 

1825 self.diagnosis_2 = DIAG_7_AGORAPHOBIA 

1826 if ( 

1827 self.generalized_anxiety_disorder 

1828 and score >= 20 

1829 and self.diagnosis_1 >= 9 

1830 ): 

1831 self.decide( 

1832 "generalized_anxiety_disorder is true AND " 

1833 "score >= 20 AND " 

1834 "diagnosis_1 >= 9. " 

1835 "Setting diagnosis_2 to DIAG_8_GENERALIZED_ANX_DIS." 

1836 ) 

1837 self.diagnosis_2 = DIAG_8_GENERALIZED_ANX_DIS 

1838 if self.panic_disorder and self.diagnosis_1 >= 9: 

1839 self.decide( 

1840 "panic_disorder is true AND diagnosis_1 >= 9. " 

1841 "Setting diagnosis_2 to DIAG_9_PANIC_DIS." 

1842 ) 

1843 self.diagnosis_2 = DIAG_9_PANIC_DIS 

1844 

1845 # In summary: 

1846 self.decide("FINISHED.") 

1847 self.decide("--- Final scores:") 

1848 self._showint("depression", self.depression) 

1849 self._showint( 

1850 "depr_crit_1_mood_anhedonia_energy", 

1851 self.depr_crit_1_mood_anhedonia_energy, 

1852 ) 

1853 self._showint( 

1854 "depr_crit_2_app_cnc_slp_mtr_glt_wth_sui", 

1855 self.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui, 

1856 ) 

1857 self._showint( 

1858 "depr_crit_3_somatic_synd", self.depr_crit_3_somatic_synd 

1859 ) 

1860 self._showint("weight_change", self.weight_change) 

1861 self._showint("somatic_symptoms", self.somatic_symptoms) 

1862 self._showint("fatigue", self.fatigue) 

1863 self._showint("neurasthenia", self.neurasthenia) 

1864 self._showint("concentration_poor", self.concentration_poor) 

1865 self._showint("sleep_problems", self.sleep_problems) 

1866 self._showint("sleep_change", self.sleep_change) 

1867 self._showint("depressive_thoughts", self.depressive_thoughts) 

1868 self._showint("irritability", self.irritability) 

1869 self._showint("diurnal_mood_variation", self.diurnal_mood_variation) 

1870 self._showbool("libido_decreased", self.libido_decreased) 

1871 self._showint("psychomotor_changes", self.psychomotor_changes) 

1872 self._showint("suicidality", self.suicidality) 

1873 self._showbool( 

1874 "depression_at_least_2_weeks", self.depression_at_least_2_weeks 

1875 ) 

1876 

1877 self._showint("hypochondria", self.hypochondria) 

1878 self._showint("worry", self.worry) 

1879 self._showint("anxiety", self.anxiety) 

1880 self._showbool( 

1881 "anxiety_physical_symptoms", self.anxiety_physical_symptoms 

1882 ) 

1883 self._showbool( 

1884 "anxiety_at_least_2_weeks", self.anxiety_at_least_2_weeks 

1885 ) 

1886 self._showbool("phobias_flag", self.phobias_flag) 

1887 self._showint("phobias_score", self.phobias_score) 

1888 self._showint("phobias_type", self.phobias_type) 

1889 self._showbool("phobic_avoidance", self.phobic_avoidance) 

1890 self._showint("panic", self.panic) 

1891 self._showbool("panic_rapid_onset", self.panic_rapid_onset) 

1892 self._showint("panic_symptoms_total", self.panic_symptoms_total) 

1893 

1894 self._showint("compulsions", self.compulsions) 

1895 self._showbool( 

1896 "compulsions_tried_to_stop", self.compulsions_tried_to_stop 

1897 ) 

1898 self._showbool( 

1899 "compulsions_at_least_2_weeks", self.compulsions_at_least_2_weeks 

1900 ) 

1901 self._showint("obsessions", self.obsessions) 

1902 self._showbool( 

1903 "obsessions_tried_to_stop", self.obsessions_tried_to_stop 

1904 ) 

1905 self._showbool( 

1906 "obsessions_at_least_2_weeks", self.obsessions_at_least_2_weeks 

1907 ) 

1908 

1909 self._showint("functional_impairment", self.functional_impairment) 

1910 

1911 # Disorder flags 

1912 self._showbool( 

1913 "obsessive_compulsive_disorder", self.obsessive_compulsive_disorder 

1914 ) 

1915 self._showbool("depression_mild", self.depression_mild) 

1916 self._showbool("depression_moderate", self.depression_moderate) 

1917 self._showbool("depression_severe", self.depression_severe) 

1918 self._showbool( 

1919 "chronic_fatigue_syndrome", self.chronic_fatigue_syndrome 

1920 ) 

1921 self._showbool( 

1922 "generalized_anxiety_disorder", self.generalized_anxiety_disorder 

1923 ) 

1924 self._showbool("phobia_agoraphobia", self.phobia_agoraphobia) 

1925 self._showbool("phobia_social", self.phobia_social) 

1926 self._showbool("phobia_specific", self.phobia_specific) 

1927 self._showbool("panic_disorder", self.panic_disorder) 

1928 

1929 self.decide("--- Final diagnoses:") 

1930 self.decide( 

1931 "Probable primary diagnosis: " 

1932 + self.diagnosis_name(self.diagnosis_1) 

1933 ) 

1934 self.decide( 

1935 "Probable secondary diagnosis: " 

1936 + self.diagnosis_name(self.diagnosis_2) 

1937 ) 

1938 

1939 

1940# ============================================================================= 

1941# CISR 

1942# ============================================================================= 

1943 

1944 

1945class Cisr(TaskHasPatientMixin, Task): 

1946 """ 

1947 Server implementation of the CIS-R task. 

1948 """ 

1949 

1950 __tablename__ = "cisr" 

1951 shortname = "CIS-R" 

1952 provides_trackers = False 

1953 

1954 # Demographics 

1955 

1956 ethnic = CamcopsColumn( 

1957 FN_ETHNIC, 

1958 Integer, 

1959 comment=( 

1960 CMT_DEMOGRAPHICS 

1961 + "Ethnicity (1 white, 2 mixed, 3 Asian/British Asian, " 

1962 "4 Black/Black British, 5 Chinese, 6 other, 7 prefer not to say)" 

1963 ), 

1964 permitted_value_checker=ONE_TO_SEVEN_CHECKER, 

1965 ) 

1966 married = CamcopsColumn( 

1967 FN_MARRIED, 

1968 Integer, 

1969 comment=( 

1970 CMT_DEMOGRAPHICS 

1971 + "Marital status (1 married/living as married, 2 single, " 

1972 "3 separated, 4 divorced, 5 widowed, 6 prefer not to say)" 

1973 ), 

1974 permitted_value_checker=ONE_TO_SIX_CHECKER, 

1975 ) 

1976 empstat = CamcopsColumn( 

1977 FN_EMPSTAT, 

1978 Integer, 

1979 comment=( 

1980 CMT_DEMOGRAPHICS 

1981 + "Current employment status (1 working full time, " 

1982 "2 working part time, 3 student, 4 retired, 5 houseperson, " 

1983 "6 unemployed job seeker, 7 unemployed due to ill health," 

1984 "8 prefer not to say)" 

1985 ), 

1986 permitted_value_checker=ONE_TO_EIGHT_CHECKER, 

1987 ) 

1988 emptype = CamcopsColumn( 

1989 FN_EMPTYPE, 

1990 Integer, 

1991 comment=( 

1992 CMT_DEMOGRAPHICS + "Current/last paid employment " 

1993 "(1 self-employed with paid employees, " 

1994 "2 self-employed with no paid employees, 3 employee, " 

1995 "4 foreman/supervisor, 5 manager, 6 not applicable," 

1996 "7 prefer not to say)" 

1997 ), 

1998 permitted_value_checker=ONE_TO_SEVEN_CHECKER, 

1999 ) 

2000 home = CamcopsColumn( 

2001 FN_HOME, 

2002 Integer, 

2003 comment=( 

2004 CMT_DEMOGRAPHICS 

2005 + "Housing situation (1 home owner, 2 tenant, 3 living with " 

2006 "relative/friend, 4 hostel/care home, 5 homeless, 6 other," 

2007 "7 prefer not to say)" 

2008 ), 

2009 permitted_value_checker=ONE_TO_SEVEN_CHECKER, 

2010 ) 

2011 

2012 # Appetite/weight 

2013 

2014 appetite1 = CamcopsColumn( 

2015 FN_APPETITE1, 

2016 Integer, 

2017 comment="Marked appetite loss in past month" + CMT_1_NO_2_YES, 

2018 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2019 ) 

2020 weight1 = CamcopsColumn( 

2021 FN_WEIGHT1, 

2022 Integer, 

2023 comment="Weight loss in past month" + CMT_1_NO_2_YES, 

2024 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2025 ) 

2026 weight2 = CamcopsColumn( 

2027 FN_WEIGHT2, 

2028 Integer, 

2029 comment="Weight loss: trying to lose weight?" + CMT_1_NO_2_YES, 

2030 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2031 ) 

2032 weight3 = CamcopsColumn( 

2033 FN_WEIGHT3, 

2034 Integer, 

2035 comment="Weight loss amount (1: ≥0.5 stones; 2: <0.5 stones)", 

2036 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2037 ) 

2038 appetite2 = CamcopsColumn( 

2039 FN_APPETITE2, 

2040 Integer, 

2041 comment="Marked increase in appetite in past month" + CMT_1_NO_2_YES, 

2042 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2043 ) 

2044 weight4 = CamcopsColumn( 

2045 # male/female responses unified (no "weight4a") 

2046 FN_WEIGHT4, 

2047 Integer, 

2048 comment="Weight gain in past month (1 yes, 2 no, 3 yes but pregnant)", 

2049 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2050 ) 

2051 weight5 = CamcopsColumn( 

2052 FN_WEIGHT5, 

2053 Integer, 

2054 comment="Weight gain amount (1: ≥0.5 stones; 2: <0.5 stones)", 

2055 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2056 ) 

2057 

2058 # Somatic problems 

2059 

2060 gp_year = CamcopsColumn( 

2061 FN_GP_YEAR, 

2062 Integer, 

2063 comment="Consultations with GP in past year (0: none, 1: 1–2, 2: 3–4, " 

2064 "3: 6–10; 4: >10", 

2065 permitted_value_checker=ZERO_TO_FOUR_CHECKER, 

2066 ) 

2067 disable = CamcopsColumn( 

2068 FN_DISABLE, 

2069 Integer, 

2070 comment="Longstanding illness/disability/infirmity" + CMT_1_YES_2_NO, 

2071 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2072 ) 

2073 illness = CamcopsColumn( 

2074 FN_ILLNESS, 

2075 Integer, 

2076 comment="Conditions (1 diabetes, 2 asthma, 3 arthritis, 4 heart " 

2077 "disease, 5 high blood pressure, 6 lung disease, 7 more than " 

2078 "one of the above, 8 none of the above)", 

2079 permitted_value_checker=ONE_TO_EIGHT_CHECKER, 

2080 ) 

2081 

2082 somatic_mand1 = CamcopsColumn( 

2083 FN_SOMATIC_MAND1, 

2084 Integer, 

2085 comment="Any aches/pains in past month?" + CMT_1_NO_2_YES, 

2086 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2087 ) 

2088 somatic_pain1 = CamcopsColumn( 

2089 FN_SOMATIC_PAIN1, 

2090 Integer, 

2091 comment="Pain/ache brought on or made worse because low/anxious/" 

2092 "stressed" + CMT_NEVER_SOMETIMES_ALWAYS, 

2093 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2094 ) 

2095 somatic_pain2 = CamcopsColumn( 

2096 FN_SOMATIC_PAIN2, 

2097 Integer, 

2098 comment="Pain: days in past week" + CMT_DAYS_PER_WEEK, 

2099 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2100 ) 

2101 somatic_pain3 = CamcopsColumn( 

2102 FN_SOMATIC_PAIN3, 

2103 Integer, 

2104 comment="Pain: lasted >3h on any day in past week" + CMT_1_NO_2_YES, 

2105 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2106 ) 

2107 somatic_pain4 = CamcopsColumn( 

2108 FN_SOMATIC_PAIN4, 

2109 Integer, 

2110 comment="Pain: unpleasant in past week?" + CMT_UNPLEASANT, 

2111 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2112 ) 

2113 somatic_pain5 = CamcopsColumn( 

2114 FN_SOMATIC_PAIN5, 

2115 Integer, 

2116 comment="Pain: bothersome whilst doing something interesting in past " 

2117 "week?" + CMT_BOTHERSOME_INTERESTING, 

2118 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2119 ) 

2120 somatic_mand2 = CamcopsColumn( 

2121 FN_SOMATIC_MAND2, 

2122 Integer, 

2123 comment="Bodily discomfort in past month?" + CMT_1_NO_2_YES, 

2124 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2125 ) 

2126 somatic_dis1 = CamcopsColumn( 

2127 FN_SOMATIC_DIS1, 

2128 Integer, 

2129 comment="Discomfort brought on or made worse because low/anxious/" 

2130 "stressed" + CMT_NEVER_SOMETIMES_ALWAYS, 

2131 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2132 ) 

2133 somatic_dis2 = CamcopsColumn( 

2134 FN_SOMATIC_DIS2, 

2135 Integer, 

2136 comment="Discomfort: days in past week" + CMT_DAYS_PER_WEEK, 

2137 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2138 ) 

2139 somatic_dis3 = CamcopsColumn( 

2140 FN_SOMATIC_DIS3, 

2141 Integer, 

2142 comment="Discomfort: lasted >3h on any day in past week" 

2143 + CMT_1_NO_2_YES, 

2144 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2145 ) 

2146 somatic_dis4 = CamcopsColumn( 

2147 FN_SOMATIC_DIS4, 

2148 Integer, 

2149 comment="Discomfort: unpleasant in past week?" + CMT_UNPLEASANT, 

2150 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2151 ) 

2152 somatic_dis5 = CamcopsColumn( 

2153 FN_SOMATIC_DIS5, 

2154 Integer, 

2155 comment="Discomfort: bothersome whilst doing something interesting in " 

2156 "past week?" + CMT_BOTHERSOME_INTERESTING, 

2157 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2158 ) 

2159 somatic_dur = CamcopsColumn( 

2160 FN_SOMATIC_DUR, 

2161 Integer, 

2162 comment="Duration of ache/pain/discomfort" + CMT_DURATION, 

2163 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2164 ) 

2165 

2166 # Fatigue/lacking energy 

2167 

2168 fatigue_mand1 = CamcopsColumn( 

2169 FN_FATIGUE_MAND1, 

2170 Integer, 

2171 comment="Tired in past month" + CMT_1_NO_2_YES, 

2172 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2173 ) 

2174 fatigue_cause1 = CamcopsColumn( 

2175 FN_FATIGUE_CAUSE1, 

2176 Integer, 

2177 comment="Main reason for feeling tired" + CMT_FATIGUE_CAUSE, 

2178 permitted_value_checker=ONE_TO_EIGHT_CHECKER, 

2179 ) 

2180 fatigue_tired1 = CamcopsColumn( 

2181 FN_FATIGUE_TIRED1, 

2182 Integer, 

2183 comment="Tired: days in past week" + CMT_DAYS_PER_WEEK, 

2184 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2185 ) 

2186 fatigue_tired2 = CamcopsColumn( 

2187 FN_FATIGUE_TIRED2, 

2188 Integer, 

2189 comment="Tired: >3h on any one day in past week" + CMT_1_NO_2_YES, 

2190 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2191 ) 

2192 fatigue_tired3 = CamcopsColumn( 

2193 FN_FATIGUE_TIRED3, 

2194 Integer, 

2195 comment="So tired you've had to push yourself to get things done in " 

2196 "past week" + CMT_1_NO_2_YES, 

2197 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2198 ) 

2199 fatigue_tired4 = CamcopsColumn( 

2200 FN_FATIGUE_TIRED4, 

2201 Integer, 

2202 comment="Tired during an enjoyable activity" + CMT_DURING_ENJOYABLE, 

2203 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2204 ) 

2205 fatigue_mand2 = CamcopsColumn( 

2206 FN_FATIGUE_MAND2, 

2207 Integer, 

2208 comment="Lacking in energy in past month" + CMT_1_NO_2_YES, 

2209 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2210 ) 

2211 fatigue_cause2 = CamcopsColumn( 

2212 FN_FATIGUE_CAUSE2, 

2213 Integer, 

2214 comment="Main reason for lacking energy" + CMT_FATIGUE_CAUSE, 

2215 permitted_value_checker=ONE_TO_EIGHT_CHECKER, 

2216 ) 

2217 fatigue_energy1 = CamcopsColumn( 

2218 FN_FATIGUE_ENERGY1, 

2219 Integer, 

2220 comment="Lacking energy: days in past week" + CMT_DAYS_PER_WEEK, 

2221 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2222 ) 

2223 fatigue_energy2 = CamcopsColumn( 

2224 FN_FATIGUE_ENERGY2, 

2225 Integer, 

2226 comment="Lacking energy: for >3h on any one day in past week" 

2227 + CMT_1_NO_2_YES, 

2228 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2229 ) 

2230 fatigue_energy3 = CamcopsColumn( 

2231 FN_FATIGUE_ENERGY3, 

2232 Integer, 

2233 comment="So lacking in energy you've had to push yourself to get " 

2234 "things done in past week" + CMT_1_NO_2_YES, 

2235 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2236 ) 

2237 fatigue_energy4 = CamcopsColumn( 

2238 FN_FATIGUE_ENERGY4, 

2239 Integer, 

2240 comment="Lacking energy during an enjoyable activity" 

2241 + CMT_DURING_ENJOYABLE, 

2242 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2243 ) 

2244 fatigue_dur = CamcopsColumn( 

2245 FN_FATIGUE_DUR, 

2246 Integer, 

2247 comment="Feeling tired/lacking energy for how long?" + CMT_DURATION, 

2248 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2249 ) 

2250 

2251 # Concentration/memory 

2252 

2253 conc_mand1 = CamcopsColumn( 

2254 FN_CONC_MAND1, 

2255 Integer, 

2256 comment="Problems in concentrating during past monnth?" 

2257 + CMT_1_NO_2_YES, 

2258 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2259 ) 

2260 conc_mand2 = CamcopsColumn( 

2261 FN_CONC_MAND2, 

2262 Integer, 

2263 comment="Problems with forgetting things during past month?" 

2264 + CMT_1_NO_2_YES, 

2265 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2266 ) 

2267 conc1 = CamcopsColumn( 

2268 FN_CONC1, 

2269 Integer, 

2270 comment="Concentration/memory problems: days in past week" 

2271 + CMT_DAYS_PER_WEEK, 

2272 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2273 ) 

2274 conc2 = CamcopsColumn( 

2275 FN_CONC2, 

2276 Integer, 

2277 comment="In past week, could concentrate on all of: TV, newspaper, " 

2278 "conversation" + CMT_1_YES_2_NO, 

2279 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2280 ) 

2281 conc3 = CamcopsColumn( 

2282 FN_CONC3, 

2283 Integer, 

2284 comment="Problems with concentration have stopped you from getting on " 

2285 "with things in past week" + CMT_1_NO_2_YES, 

2286 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2287 ) 

2288 conc_dur = CamcopsColumn( 

2289 FN_CONC_DUR, 

2290 Integer, 

2291 comment="Problems with concentration: for how long?" + CMT_DURATION, 

2292 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2293 ) 

2294 conc4 = CamcopsColumn( 

2295 FN_CONC4, 

2296 Integer, 

2297 comment="Forgotten anything important in past week" + CMT_1_NO_2_YES, 

2298 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2299 ) 

2300 forget_dur = CamcopsColumn( 

2301 FN_FORGET_DUR, 

2302 Integer, 

2303 comment="Problems with memory: for how long?" + CMT_DURATION, 

2304 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2305 ) 

2306 

2307 # Sleep 

2308 

2309 sleep_mand1 = CamcopsColumn( 

2310 FN_SLEEP_MAND1, 

2311 Integer, 

2312 comment="Problems with sleep loss in past month" + CMT_1_NO_2_YES, 

2313 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2314 ) 

2315 sleep_lose1 = CamcopsColumn( 

2316 FN_SLEEP_LOSE1, 

2317 Integer, 

2318 comment="Sleep loss: nights in past week with problems" 

2319 + CMT_NIGHTS_PER_WEEK, 

2320 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2321 ) 

2322 sleep_lose2 = CamcopsColumn( 

2323 FN_SLEEP_LOSE2, 

2324 Integer, 

2325 comment="On night with least sleep in past week, how long trying to " 

2326 "get to sleep?" + CMT_SLEEP_CHANGE, 

2327 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2328 ) 

2329 sleep_lose3 = CamcopsColumn( 

2330 FN_SLEEP_LOSE3, 

2331 Integer, 

2332 comment="On how many nights in past week did you spend >=3h trying to " 

2333 "get to sleep?" + CMT_NIGHTS_PER_WEEK, 

2334 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2335 ) 

2336 sleep_emw = CamcopsColumn( 

2337 FN_SLEEP_EMW, 

2338 Integer, 

2339 comment="Woken >2h earlier (and couldn't return to sleep) in past " 

2340 "week?" + CMT_1_NO_2_YES, 

2341 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2342 ) 

2343 sleep_cause = CamcopsColumn( 

2344 FN_SLEEP_CAUSE, 

2345 Integer, 

2346 comment="What are your sleep difficulties caused by? (1 noise, " 

2347 "2 shift work, 3 pain/illness, 4 worries, 5 unknown, 6 other", 

2348 permitted_value_checker=ONE_TO_SIX_CHECKER, 

2349 ) 

2350 sleep_mand2 = CamcopsColumn( 

2351 FN_SLEEP_MAND2, 

2352 Integer, 

2353 comment="Problems with excess sleep in past month (1 no, 2 slept more " 

2354 "than usual but not a problem, 3 yes)", 

2355 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2356 ) 

2357 sleep_gain1 = CamcopsColumn( 

2358 FN_SLEEP_GAIN1, 

2359 Integer, 

2360 comment="Sleep gain: how many nights in past week" 

2361 + CMT_NIGHTS_PER_WEEK, 

2362 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2363 ) 

2364 sleep_gain2 = CamcopsColumn( 

2365 FN_SLEEP_GAIN2, 

2366 Integer, 

2367 comment="On night with most sleep in past week, how much more than " 

2368 "usual?" + CMT_SLEEP_CHANGE, 

2369 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2370 ) 

2371 sleep_gain3 = CamcopsColumn( 

2372 FN_SLEEP_GAIN3, 

2373 Integer, 

2374 comment="On how many nights in past week did you sleep >3h longer " 

2375 "than usual?" + CMT_NIGHTS_PER_WEEK, 

2376 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2377 ) 

2378 sleep_dur = CamcopsColumn( 

2379 FN_SLEEP_DUR, 

2380 Integer, 

2381 comment="How long have you had these problems with sleep?" 

2382 + CMT_DURATION, 

2383 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2384 ) 

2385 

2386 # Irritability 

2387 

2388 irrit_mand1 = CamcopsColumn( 

2389 FN_IRRIT_MAND1, 

2390 Integer, 

2391 comment="Irritable with those around you in past month?" 

2392 + CMT_1_NO_2_YES, 

2393 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2394 ) 

2395 irrit_mand2 = CamcopsColumn( 

2396 FN_IRRIT_MAND2, 

2397 Integer, 

2398 comment="Short-tempered/angry over trivial things in past month? " 

2399 "(1 no, 2 sometimes, 3 yes)", 

2400 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2401 ) 

2402 irrit1 = CamcopsColumn( 

2403 FN_IRRIT1, 

2404 Integer, 

2405 comment="Irritable/short-tempered/angry: days in past week" 

2406 + CMT_DAYS_PER_WEEK, 

2407 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2408 ) 

2409 irrit2 = CamcopsColumn( 

2410 FN_IRRIT2, 

2411 Integer, 

2412 comment="Irritable/short-tempered/angry: for >1h on any day in past " 

2413 "week?" + CMT_1_NO_2_YES, 

2414 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2415 ) 

2416 irrit3 = CamcopsColumn( 

2417 FN_IRRIT3, 

2418 Integer, 

2419 comment="Irritable/short-tempered/angry: wanted to shout at someone? " 

2420 "(1 no; yes but didn't shout; 3 yes and did shout)", 

2421 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2422 ) 

2423 irrit4 = CamcopsColumn( 

2424 FN_IRRIT4, 

2425 Integer, 

2426 comment="In past week, have you had arguments/rows/lost temper? " 

2427 "(1 no; 2 yes but justified; 3 yes)", 

2428 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2429 ) 

2430 irrit_dur = CamcopsColumn( 

2431 FN_IRRIT_DUR, 

2432 Integer, 

2433 comment="Irritable/short-tempered/angry: for how long?" + CMT_DURATION, 

2434 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2435 ) 

2436 

2437 # Hypochondriasis 

2438 

2439 hypo_mand1 = CamcopsColumn( 

2440 FN_HYPO_MAND1, 

2441 Integer, 

2442 comment="Worried about physical health in past month?" 

2443 + CMT_1_NO_2_YES, 

2444 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2445 ) 

2446 hypo_mand2 = CamcopsColumn( 

2447 FN_HYPO_MAND2, 

2448 Integer, 

2449 comment="Do you worry you have a serious illness?" + CMT_1_NO_2_YES, 

2450 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2451 ) 

2452 hypo1 = CamcopsColumn( 

2453 FN_HYPO1, 

2454 Integer, 

2455 comment="Worrying about health/having a serious illness: how many " 

2456 "days in past week?" + CMT_DAYS_PER_WEEK, 

2457 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2458 ) 

2459 hypo2 = CamcopsColumn( 

2460 FN_HYPO2, 

2461 Integer, 

2462 comment="Worrying too much about physical health?" + CMT_1_NO_2_YES, 

2463 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2464 ) 

2465 hypo3 = CamcopsColumn( 

2466 FN_HYPO3, 

2467 Integer, 

2468 comment="Worrying about health: how unpleasant?" + CMT_UNPLEASANT, 

2469 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2470 ) 

2471 hypo4 = CamcopsColumn( 

2472 FN_HYPO4, 

2473 Integer, 

2474 comment="Able to take mind off health worries in past week?" 

2475 + CMT_1_YES_2_NO, 

2476 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2477 ) 

2478 hypo_dur = CamcopsColumn( 

2479 FN_HYPO_DUR, 

2480 Integer, 

2481 comment="Worrying about physical health: for how long?" + CMT_DURATION, 

2482 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2483 ) 

2484 

2485 # Depression 

2486 

2487 depr_mand1 = CamcopsColumn( 

2488 FN_DEPR_MAND1, 

2489 Integer, 

2490 comment="Sad/miserable/depressed in past month?" + CMT_1_NO_2_YES, 

2491 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2492 ) 

2493 depr1 = CamcopsColumn( 

2494 FN_DEPR1, 

2495 Integer, 

2496 comment="Sad/miserable/depressed in past week?" + CMT_1_NO_2_YES, 

2497 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2498 ) 

2499 depr_mand2 = CamcopsColumn( 

2500 FN_DEPR_MAND2, 

2501 Integer, 

2502 comment="In the past month, able to enjoy/take an interest in things " 

2503 "as much as usual?" + CMT_ANHEDONIA, 

2504 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2505 ) 

2506 depr2 = CamcopsColumn( 

2507 FN_DEPR2, 

2508 Integer, 

2509 comment="In the past week, able to enjoy/take an interest in things " 

2510 "as much as usual?" + CMT_ANHEDONIA, 

2511 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2512 ) 

2513 depr3 = CamcopsColumn( 

2514 FN_DEPR3, 

2515 Integer, 

2516 comment="[Depressed mood] or [anhedonia] on how many days in past " 

2517 "week" + CMT_DAYS_PER_WEEK, 

2518 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2519 ) 

2520 depr4 = CamcopsColumn( 

2521 FN_DEPR4, 

2522 Integer, 

2523 comment="[Depressed mood] or [anhedonia] for >3h on any day in past " 

2524 "week?" + CMT_1_NO_2_YES, 

2525 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2526 ) 

2527 depr_content = CamcopsColumn( 

2528 FN_DEPR_CONTENT, 

2529 Integer, 

2530 comment="Main reason for [depressed mood] or [anhedonia]?" 

2531 + CMT_STRESSORS, 

2532 permitted_value_checker=ONE_TO_NINE_CHECKER, 

2533 ) 

2534 depr5 = CamcopsColumn( 

2535 FN_DEPR5, 

2536 Integer, 

2537 comment="In past week, during [depressed mood] or [anhedonia], did " 

2538 "nice things/company make you happier? " 

2539 "(1 always, 2 sometimes, 3 no)", 

2540 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2541 ) 

2542 depr_dur = CamcopsColumn( 

2543 FN_DEPR_DUR, 

2544 Integer, 

2545 comment="Depressed mood/anhedonia: for how long?" + CMT_DURATION, 

2546 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2547 ) 

2548 depth1 = CamcopsColumn( 

2549 FN_DEPTH1, 

2550 Integer, 

2551 comment="Diurnal mood variation in past week (1 worse in the morning, " 

2552 "2 worse in the evening, 3 varies, 4 no difference)", 

2553 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2554 ) 

2555 depth2 = CamcopsColumn( 

2556 FN_DEPTH2, 

2557 Integer, 

2558 comment="Libido in past month (1 not applicable, 2 no change, " 

2559 "3 increased, 4 decreased)", 

2560 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2561 ) 

2562 depth3 = CamcopsColumn( 

2563 FN_DEPTH3, 

2564 Integer, 

2565 comment="Restlessness in past week" + CMT_1_NO_2_YES, 

2566 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2567 ) 

2568 depth4 = CamcopsColumn( 

2569 FN_DEPTH4, 

2570 Integer, 

2571 comment="Psychomotor retardation in past week" + CMT_1_NO_2_YES, 

2572 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2573 ) 

2574 depth5 = CamcopsColumn( 

2575 FN_DEPTH5, 

2576 Integer, 

2577 comment="Guilt/blamed self in past week (1 never, 2 only when it was " 

2578 "my fault, 3 sometimes, 4 often)", 

2579 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2580 ) 

2581 depth6 = CamcopsColumn( 

2582 FN_DEPTH6, 

2583 Integer, 

2584 comment="Feeling not as good as other people in past week" 

2585 + CMT_1_NO_2_YES, 

2586 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2587 ) 

2588 depth7 = CamcopsColumn( 

2589 FN_DEPTH7, 

2590 Integer, 

2591 comment="Hopeless in past week" + CMT_1_NO_2_YES, 

2592 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2593 ) 

2594 depth8 = CamcopsColumn( 

2595 FN_DEPTH8, 

2596 Integer, 

2597 comment="Life not worth living in past week (1 no, 2 sometimes, " 

2598 "3 always)", 

2599 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2600 ) 

2601 depth9 = CamcopsColumn( 

2602 FN_DEPTH9, 

2603 Integer, 

2604 comment="Thoughts of suicide in past week (1 no; 2 yes, but would " 

2605 "never commit suicide; 3 yes)", 

2606 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2607 ) 

2608 depth10 = CamcopsColumn( 

2609 FN_DEPTH10, 

2610 Integer, 

2611 comment="Thoughts of way to kill self in past week" + CMT_1_NO_2_YES, 

2612 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2613 ) 

2614 doctor = CamcopsColumn( 

2615 FN_DOCTOR, 

2616 Integer, 

2617 comment="Have you spoken to your doctor about these thoughts of " 

2618 "killing yourself (1 yes; 2 no, but have talked to other " 

2619 "people; 3 no)", 

2620 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2621 ) 

2622 

2623 # Worry/generalized anxiety 

2624 

2625 worry_mand1 = CamcopsColumn( 

2626 FN_WORRY_MAND1, 

2627 Integer, 

2628 comment="Excessive worry in past month?" + CMT_NO_SOMETIMES_OFTEN, 

2629 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2630 ) 

2631 worry_mand2 = CamcopsColumn( 

2632 FN_WORRY_MAND2, 

2633 Integer, 

2634 comment="Any worries at all in past month?" + CMT_1_NO_2_YES, 

2635 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2636 ) 

2637 worry_cont1 = CamcopsColumn( 

2638 FN_WORRY_CONT1, 

2639 Integer, 

2640 comment="Main source of worry in past week?" + CMT_STRESSORS, 

2641 permitted_value_checker=ONE_TO_NINE_CHECKER, 

2642 ) 

2643 worry2 = CamcopsColumn( 

2644 FN_WORRY2, 

2645 Integer, 

2646 comment="Worries (about things other than physical health) on how " 

2647 "many days in past week" + CMT_DAYS_PER_WEEK, 

2648 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2649 ) 

2650 worry3 = CamcopsColumn( 

2651 FN_WORRY3, 

2652 Integer, 

2653 comment="Worrying too much?" + CMT_1_NO_2_YES, 

2654 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2655 ) 

2656 worry4 = CamcopsColumn( 

2657 FN_WORRY4, 

2658 Integer, 

2659 comment="How unpleasant is worry (about things other than physical " 

2660 "health)" + CMT_UNPLEASANT, 

2661 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2662 ) 

2663 worry5 = CamcopsColumn( 

2664 FN_WORRY5, 

2665 Integer, 

2666 comment="Worry (about things other than physical health) for >3h on " 

2667 "any day in past week?" + CMT_1_NO_2_YES, 

2668 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2669 ) 

2670 worry_dur = CamcopsColumn( 

2671 FN_WORRY_DUR, 

2672 Integer, 

2673 comment="Worry (about things other than physical health): for how " 

2674 "long?" + CMT_DURATION, 

2675 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2676 ) 

2677 

2678 anx_mand1 = CamcopsColumn( 

2679 FN_ANX_MAND1, 

2680 Integer, 

2681 comment="Anxious/nervous in past month?" + CMT_1_NO_2_YES, 

2682 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2683 ) 

2684 anx_mand2 = CamcopsColumn( 

2685 FN_ANX_MAND2, 

2686 Integer, 

2687 comment="Muscle tension/couldn't relax in past month?" 

2688 + CMT_NO_SOMETIMES_OFTEN, 

2689 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2690 ) 

2691 anx_phobia1 = CamcopsColumn( 

2692 FN_ANX_PHOBIA1, 

2693 Integer, 

2694 comment="Phobic anxiety in past month?" + CMT_1_NO_2_YES, 

2695 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2696 ) 

2697 anx_phobia2 = CamcopsColumn( 

2698 FN_ANX_PHOBIA2, 

2699 Integer, 

2700 comment="Phobic anxiety: always specific? (1 always specific, " 

2701 "2 sometimes general)", 

2702 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2703 ) 

2704 anx2 = CamcopsColumn( 

2705 FN_ANX2, 

2706 Integer, 

2707 comment="Anxiety/nervousness/tension: how many days in past week" 

2708 + CMT_DAYS_PER_WEEK, 

2709 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2710 ) 

2711 anx3 = CamcopsColumn( 

2712 FN_ANX3, 

2713 Integer, 

2714 comment="Anxiety/nervousness/tension: how unpleasant in past week" 

2715 + CMT_UNPLEASANT, 

2716 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

2717 ) 

2718 anx4 = CamcopsColumn( 

2719 FN_ANX4, 

2720 Integer, 

2721 comment="Anxiety/nervousness/tension: physical symptoms in past " 

2722 "week?" + CMT_1_NO_2_YES, 

2723 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2724 ) 

2725 anx5 = CamcopsColumn( 

2726 FN_ANX5, 

2727 Integer, 

2728 comment="Anxiety/nervousness/tension: for >3h on any day in past " 

2729 "week?" + CMT_1_NO_2_YES, 

2730 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2731 ) 

2732 anx_dur = CamcopsColumn( 

2733 FN_ANX_DUR, 

2734 Integer, 

2735 comment="Anxiety/nervousness/tension: for how long?" + CMT_DURATION, 

2736 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2737 ) 

2738 

2739 # Specific phobias 

2740 

2741 phobias_mand = CamcopsColumn( 

2742 FN_PHOBIAS_MAND, 

2743 Integer, 

2744 comment="Phobic avoidance in past month?" + CMT_1_NO_2_YES, 

2745 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2746 ) 

2747 phobias_type1 = CamcopsColumn( 

2748 FN_PHOBIAS_TYPE1, 

2749 Integer, 

2750 comment="Which phobia? (1 travelling alone by bus/train; 2 being far " 

2751 "from home; 3 public eating/speaking; 4 sight of blood; " 

2752 "5 crowded shops; 6 insects/spiders/animals; 7 being watched; " 

2753 "8 enclosed spaces or heights; 9 something else)", 

2754 permitted_value_checker=ONE_TO_NINE_CHECKER, 

2755 ) 

2756 phobias1 = CamcopsColumn( 

2757 FN_PHOBIAS1, 

2758 Integer, 

2759 comment="Phobic anxiety: days in past week" + CMT_DAYS_PER_WEEK, 

2760 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2761 ) 

2762 phobias2 = CamcopsColumn( 

2763 FN_PHOBIAS2, 

2764 Integer, 

2765 comment="Phobic anxiety: physical symptoms in past week?" 

2766 + CMT_1_NO_2_YES, 

2767 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2768 ) 

2769 phobias3 = CamcopsColumn( 

2770 FN_PHOBIAS3, 

2771 Integer, 

2772 comment="Phobic avoidance in past week?" + CMT_1_NO_2_YES, 

2773 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2774 ) 

2775 phobias4 = CamcopsColumn( 

2776 FN_PHOBIAS4, 

2777 Integer, 

2778 comment="Phobic avoidance: how many times in past week? (1: none, " 

2779 "2: 1–3, 3: >=4)", 

2780 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2781 ) 

2782 phobias_dur = CamcopsColumn( 

2783 FN_PHOBIAS_DUR, 

2784 Integer, 

2785 comment="Phobic anxiety: for how long?" + CMT_DURATION, 

2786 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2787 ) 

2788 

2789 # Panic 

2790 

2791 panic_mand = CamcopsColumn( 

2792 FN_PANIC_MAND, 

2793 Integer, 

2794 comment="Panic in past month (1: no, my anxiety never got that bad; " 

2795 "2: yes, sometimes; 3: yes, often)", 

2796 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2797 ) 

2798 panic1 = CamcopsColumn( 

2799 FN_PANIC1, 

2800 Integer, 

2801 comment="Panic: how often in past week (1 not in past seven days, " 

2802 "2 once, 3 more than once)", 

2803 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2804 ) 

2805 panic2 = CamcopsColumn( 

2806 FN_PANIC2, 

2807 Integer, 

2808 comment="Panic: how unpleasant in past week (1 a little " 

2809 "uncomfortable; 2 unpleasant; 3 unbearable, or very " 

2810 "unpleasant)", 

2811 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2812 ) 

2813 panic3 = CamcopsColumn( 

2814 FN_PANIC3, 

2815 Integer, 

2816 comment="Panic: in the past week, did the worst panic last >10min " 

2817 "(1: <10min; 2 >=10min)", 

2818 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2819 ) 

2820 panic4 = CamcopsColumn( 

2821 FN_PANIC4, 

2822 Integer, 

2823 comment="Do panics start suddenly?" + CMT_1_NO_2_YES, 

2824 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2825 ) 

2826 pansym_a = CamcopsColumn( 

2827 FN_PANSYM_A, 

2828 Integer, 

2829 comment=CMT_PANIC_SYMPTOM + "heart racing" + CMT_1_NO_2_YES, 

2830 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2831 ) 

2832 pansym_b = CamcopsColumn( 

2833 FN_PANSYM_B, 

2834 Integer, 

2835 comment=CMT_PANIC_SYMPTOM + "hands sweaty/clammy" + CMT_1_NO_2_YES, 

2836 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2837 ) 

2838 pansym_c = CamcopsColumn( 

2839 FN_PANSYM_C, 

2840 Integer, 

2841 comment=CMT_PANIC_SYMPTOM + "trembling/shaking" + CMT_1_NO_2_YES, 

2842 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2843 ) 

2844 pansym_d = CamcopsColumn( 

2845 FN_PANSYM_D, 

2846 Integer, 

2847 comment=CMT_PANIC_SYMPTOM + "short of breath" + CMT_1_NO_2_YES, 

2848 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2849 ) 

2850 pansym_e = CamcopsColumn( 

2851 FN_PANSYM_E, 

2852 Integer, 

2853 comment=CMT_PANIC_SYMPTOM + "choking sensation" + CMT_1_NO_2_YES, 

2854 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2855 ) 

2856 pansym_f = CamcopsColumn( 

2857 FN_PANSYM_F, 

2858 Integer, 

2859 comment=( 

2860 CMT_PANIC_SYMPTOM 

2861 + "chest pain/pressure/discomfort" 

2862 + CMT_1_NO_2_YES 

2863 ), 

2864 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2865 ) 

2866 pansym_g = CamcopsColumn( 

2867 FN_PANSYM_G, 

2868 Integer, 

2869 comment=CMT_PANIC_SYMPTOM + "nausea" + CMT_1_NO_2_YES, 

2870 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2871 ) 

2872 pansym_h = CamcopsColumn( 

2873 FN_PANSYM_H, 

2874 Integer, 

2875 comment=( 

2876 CMT_PANIC_SYMPTOM 

2877 + "dizzy/unsteady/lightheaded/faint" 

2878 + CMT_1_NO_2_YES 

2879 ), 

2880 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2881 ) 

2882 pansym_i = CamcopsColumn( 

2883 FN_PANSYM_I, 

2884 Integer, 

2885 comment=( 

2886 CMT_PANIC_SYMPTOM 

2887 + "derealization/depersonalization" 

2888 + CMT_1_NO_2_YES 

2889 ), 

2890 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2891 ) 

2892 pansym_j = CamcopsColumn( 

2893 FN_PANSYM_J, 

2894 Integer, 

2895 comment=( 

2896 CMT_PANIC_SYMPTOM + "losing control/going crazy" + CMT_1_NO_2_YES 

2897 ), 

2898 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2899 ) 

2900 pansym_k = CamcopsColumn( 

2901 FN_PANSYM_K, 

2902 Integer, 

2903 comment=CMT_PANIC_SYMPTOM + "fear were dying" + CMT_1_NO_2_YES, 

2904 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2905 ) 

2906 pansym_l = CamcopsColumn( 

2907 FN_PANSYM_L, 

2908 Integer, 

2909 comment=CMT_PANIC_SYMPTOM + "tingling/numbness" + CMT_1_NO_2_YES, 

2910 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2911 ) 

2912 pansym_m = CamcopsColumn( 

2913 FN_PANSYM_M, 

2914 Integer, 

2915 comment=CMT_PANIC_SYMPTOM + "hot flushes/chills" + CMT_1_NO_2_YES, 

2916 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2917 ) 

2918 panic5 = CamcopsColumn( 

2919 FN_PANIC5, 

2920 Integer, 

2921 comment="Is panic always brought on by specific things?" 

2922 + CMT_1_NO_2_YES, 

2923 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2924 ) 

2925 panic_dur = CamcopsColumn( 

2926 FN_PANIC_DUR, 

2927 Integer, 

2928 comment="Panic: for how long?" + CMT_DURATION, 

2929 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2930 ) 

2931 

2932 # Compulsions 

2933 

2934 comp_mand1 = CamcopsColumn( 

2935 FN_COMP_MAND1, 

2936 Integer, 

2937 comment="Compulsions in past month" + CMT_NO_SOMETIMES_OFTEN, 

2938 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2939 ) 

2940 comp1 = CamcopsColumn( 

2941 FN_COMP1, 

2942 Integer, 

2943 comment="Compulsions: how many days in past week" + CMT_DAYS_PER_WEEK, 

2944 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2945 ) 

2946 comp2 = CamcopsColumn( 

2947 FN_COMP2, 

2948 Integer, 

2949 comment="Compulsions: tried to stop in past week" + CMT_1_NO_2_YES, 

2950 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2951 ) 

2952 comp3 = CamcopsColumn( 

2953 FN_COMP3, 

2954 Integer, 

2955 comment="Compulsions: upsetting/annoying in past week" 

2956 + CMT_1_NO_2_YES, 

2957 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2958 ) 

2959 comp4 = CamcopsColumn( 

2960 FN_COMP4, 

2961 Integer, 

2962 comment="Compulsions: greatest number of repeats in past week " 

2963 "(1: once, i.e. two times altogether; 2: two repeats; " 

2964 "3: three or more repeats)", 

2965 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2966 ) 

2967 comp_dur = CamcopsColumn( 

2968 FN_COMP_DUR, 

2969 Integer, 

2970 comment="Compulsions: for how long?" + CMT_DURATION, 

2971 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

2972 ) 

2973 

2974 # Obsessions 

2975 

2976 obsess_mand1 = CamcopsColumn( 

2977 FN_OBSESS_MAND1, 

2978 Integer, 

2979 comment="Obsessions in past month" + CMT_NO_SOMETIMES_OFTEN, 

2980 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2981 ) 

2982 obsess_mand2 = CamcopsColumn( 

2983 FN_OBSESS_MAND2, 

2984 Integer, 

2985 comment="Obsessions: same thoughts repeating or general worries (1 " 

2986 "same thoughts over and over, 2 worrying about something in " 

2987 "general)", 

2988 permitted_value_checker=ONE_TO_TWO_CHECKER, 

2989 ) 

2990 obsess1 = CamcopsColumn( 

2991 FN_OBSESS1, 

2992 Integer, 

2993 comment="Obsessions: how many days in past week" + CMT_DAYS_PER_WEEK, 

2994 permitted_value_checker=ONE_TO_THREE_CHECKER, 

2995 ) 

2996 obsess2 = CamcopsColumn( 

2997 FN_OBSESS2, 

2998 Integer, 

2999 comment="Obsessions: tried to stop in past week" + CMT_1_NO_2_YES, 

3000 permitted_value_checker=ONE_TO_TWO_CHECKER, 

3001 ) 

3002 obsess3 = CamcopsColumn( 

3003 FN_OBSESS3, 

3004 Integer, 

3005 comment="Obsessions: upsetting/annoying in past week" + CMT_1_NO_2_YES, 

3006 permitted_value_checker=ONE_TO_TWO_CHECKER, 

3007 ) 

3008 obsess4 = CamcopsColumn( 

3009 FN_OBSESS4, 

3010 Integer, 

3011 comment="Obsessions: longest time spent thinking these thoughts, in " 

3012 "past week (1: <15min; 2: >=15min)", 

3013 permitted_value_checker=ONE_TO_TWO_CHECKER, 

3014 ) 

3015 obsess_dur = CamcopsColumn( 

3016 FN_OBSESS_DUR, 

3017 Integer, 

3018 comment="Obsessions: for how long?" + CMT_DURATION, 

3019 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

3020 ) 

3021 

3022 # Overall impact 

3023 

3024 overall2 = CamcopsColumn( 

3025 FN_OVERALL2, 

3026 Integer, 

3027 comment="Overall impact on normal activities in past week (1 not at " 

3028 "all; 2 they have made things more difficult but I get " 

3029 "everything done; 3 they have stopped one activity; 4 they " 

3030 "have stopped >1 activity)", 

3031 permitted_value_checker=ONE_TO_FOUR_CHECKER, 

3032 ) 

3033 

3034 # ------------------------------------------------------------------------- 

3035 # Functions 

3036 # ------------------------------------------------------------------------- 

3037 

3038 @staticmethod 

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

3040 _ = req.gettext 

3041 return _("Clinical Interview Schedule, Revised") 

3042 

3043 # noinspection PyMethodParameters 

3044 @classproperty 

3045 def minimum_client_version(cls) -> Version: 

3046 return Version("2.2.0") 

3047 

3048 def value_for_question(self, q: CisrQuestion) -> Optional[int]: 

3049 fieldname = fieldname_for_q(q) 

3050 assert fieldname, f"Blank fieldname for question {q}" 

3051 return getattr(self, fieldname) 

3052 

3053 def int_value_for_question(self, q: CisrQuestion) -> int: 

3054 value = self.value_for_question(q) 

3055 return int(value) if value is not None else 0 

3056 

3057 def answer_is_no(self, q: CisrQuestion, value: int = V_UNKNOWN) -> bool: 

3058 if value == V_UNKNOWN: # "Please look it up for me" 

3059 value = self.int_value_for_question(q) 

3060 if q in QUESTIONS_1_NO_2_YES: 

3061 return value == 1 

3062 elif q in QUESTIONS_1_YES_2_NO: 

3063 return value == 2 

3064 else: 

3065 raise ValueError( 

3066 "answer_is_no() called for inappropriate " f"question {q}" 

3067 ) 

3068 

3069 def answer_is_yes(self, q: CisrQuestion, value: int = V_UNKNOWN) -> bool: 

3070 if value == V_UNKNOWN: # "Please look it up for me" 

3071 value = self.int_value_for_question(q) 

3072 if q in QUESTIONS_1_NO_2_YES: 

3073 return value == 2 

3074 elif q in QUESTIONS_1_YES_2_NO: 

3075 return value == 1 

3076 else: 

3077 raise ValueError( 

3078 "answer_is_yes() called for inappropriate " f"question {q}" 

3079 ) 

3080 

3081 def answered(self, q: CisrQuestion, value: int = V_UNKNOWN) -> bool: 

3082 if value == V_UNKNOWN: # "Please look it up for me" 

3083 value = self.int_value_for_question(q) 

3084 return value != V_MISSING 

3085 

3086 def get_textual_answer( 

3087 self, req: CamcopsRequest, q: CisrQuestion 

3088 ) -> Optional[str]: 

3089 value = self.value_for_question(q) 

3090 if value is None or value == V_MISSING: 

3091 return None 

3092 if q in QUESTIONS_1_NO_2_YES: 

3093 return get_yes_no(req, value == 2) 

3094 elif q in QUESTIONS_1_YES_2_NO: 

3095 return get_yes_no(req, value == 1) 

3096 elif q in QUESTIONS_PROMPT_ONLY: 

3097 return NOT_APPLICABLE_TEXT 

3098 fieldname = fieldname_for_q(q) 

3099 if ( 

3100 q in QUESTIONS_YN_SPECIFIC_TEXT 

3101 or q in QUESTIONS_MULTIWAY 

3102 or q in QUESTIONS_MULTIWAY_WITH_EXTRA_STEM 

3103 ): 

3104 return self.wxstring(req, fieldname + f"_a{value}") 

3105 elif q in QUESTIONS_OVERALL_DURATION: 

3106 return self.wxstring(req, f"duration_a{value}") 

3107 elif q in QUESTIONS_DAYS_PER_WEEK: 

3108 return self.wxstring(req, f"dpw_a{value}") 

3109 elif q in QUESTIONS_NIGHTS_PER_WEEK: 

3110 return self.wxstring(req, f"npw_a{value}") 

3111 elif q in QUESTIONS_HOW_UNPLEASANT_STANDARD: 

3112 return self.wxstring(req, f"how_unpleasant_a{value}") 

3113 elif q in QUESTIONS_FATIGUE_CAUSES: 

3114 return self.wxstring(req, f"fatigue_causes_a{value}") 

3115 elif q in QUESTIONS_STRESSORS: 

3116 return self.wxstring(req, f"stressors_a{value}") 

3117 elif q in QUESTIONS_NO_SOMETIMES_OFTEN: 

3118 return self.wxstring(req, f"nso_a{value}") 

3119 return f"? [value: {value}]" 

3120 

3121 def next_q(self, q: CisrQuestion, r: CisrResult) -> CisrQuestion: 

3122 # See equivalent in the C++ code. 

3123 # ANY CHANGES HERE MUST BE REFLECTED IN THE C++ CODE AND VICE VERSA. 

3124 

3125 v = V_MISSING # integer value 

3126 if DEBUG_SHOW_QUESTIONS_CONSIDERED: 

3127 r.decide(f"Considering question {q.value}: {q.name}") 

3128 fieldname = fieldname_for_q(q) 

3129 if fieldname: # eliminates prompt-only questions 

3130 var_q = getattr(self, fieldname) # integer-or-NULL value 

3131 if var_q is None: 

3132 if q not in QUESTIONS_DEMOGRAPHICS: 

3133 # From a diagnostic point of view, OK to have missing 

3134 # demographic information. Otherwise: 

3135 r.decide("INCOMPLETE INFORMATION. STOPPING.") 

3136 r.incomplete = True 

3137 else: 

3138 v = int(var_q) 

3139 

3140 next_q = -1 

3141 

3142 def jump_to(qe: CisrQuestion) -> None: 

3143 nonlocal next_q 

3144 next_q = enum_to_int(qe) 

3145 

3146 # If there is no special handling for a question, then after the 

3147 # switch() statement we will move to the next question in sequence. 

3148 # So only special "skip" situations are handled here. 

3149 

3150 # FOLLOW THE EXACT SEQUENCE of the CIS-R. Don't agglomerate case 

3151 # statements just because it's shorter (except empty ones when they are 

3152 # in sequence). Clarity is key. 

3153 

3154 # --------------------------------------------------------------------- 

3155 # Demographics/preamble 

3156 # --------------------------------------------------------------------- 

3157 

3158 if q in QUESTIONS_DEMOGRAPHICS or q in QUESTIONS_PROMPT_ONLY: 

3159 # Nothing special 

3160 pass 

3161 # Note that this makes some of the other prompt-only checks 

3162 # below redundant! Still, it's quicker. The C++ version uses 

3163 # switch() instead. 

3164 

3165 # -------------------------------------------------------------------- 

3166 # Appetite/weight 

3167 # -------------------------------------------------------------------- 

3168 

3169 elif q == CQ.APPETITE1_LOSS_PAST_MONTH: 

3170 if self.answer_is_no(q, v): 

3171 r.decide("No loss of appetite in past month.") 

3172 jump_to(CQ.APPETITE2_INCREASE_PAST_MONTH) 

3173 elif self.answer_is_yes(q, v): 

3174 r.decide( 

3175 "Loss of appetite in past month. " 

3176 "Incrementing depr_crit_3_somatic_synd." 

3177 ) 

3178 r.depr_crit_3_somatic_synd += 1 

3179 r.weight_change = WTCHANGE_APPETITE_LOSS 

3180 

3181 elif q == CQ.WEIGHT1_LOSS_PAST_MONTH: 

3182 if self.answer_is_no(q, v): 

3183 r.decide("No weight loss.") 

3184 jump_to(CQ.GP_YEAR) 

3185 

3186 elif q == CQ.WEIGHT2_TRYING_TO_LOSE: 

3187 if v == V_WEIGHT2_WTLOSS_TRYING: 

3188 # Trying to lose weight. Move on. 

3189 r.decide("Weight loss but it was deliberate.") 

3190 elif v == V_WEIGHT2_WTLOSS_NOTTRYING: 

3191 r.decide("Non-deliberate weight loss.") 

3192 r.weight_change = WTCHANGE_NONDELIBERATE_WTLOSS_OR_WTGAIN 

3193 

3194 elif q == CQ.WEIGHT3_LOST_LOTS: 

3195 if v == V_WEIGHT3_WTLOSS_GE_HALF_STONE: 

3196 r.decide( 

3197 "Weight loss ≥0.5st in past month. " 

3198 "Incrementing depr_crit_3_somatic_synd." 

3199 ) 

3200 r.weight_change = WTCHANGE_WTLOSS_GE_HALF_STONE 

3201 r.depr_crit_3_somatic_synd += 1 

3202 r.decide( 

3203 "Loss of weight, so skipping appetite/weight gain " 

3204 "questions." 

3205 ) 

3206 jump_to(CQ.GP_YEAR) 

3207 

3208 elif q == CQ.APPETITE2_INCREASE_PAST_MONTH: 

3209 if self.answer_is_no(q, v): 

3210 r.decide("No increase in appetite in past month.") 

3211 jump_to(CQ.GP_YEAR) 

3212 

3213 elif q == CQ.WEIGHT4_INCREASE_PAST_MONTH: 

3214 if self.answer_is_yes(q, v): 

3215 r.decide("Weight gain.") 

3216 r.weight_change = WTCHANGE_NONDELIBERATE_WTLOSS_OR_WTGAIN 

3217 elif self.answered(q, v): 

3218 r.decide("No weight gain, or weight gain but pregnant.") 

3219 jump_to(CQ.GP_YEAR) 

3220 

3221 elif q == CQ.WEIGHT5_GAINED_LOTS: 

3222 if ( 

3223 v == V_WEIGHT5_WTGAIN_GE_HALF_STONE 

3224 and r.weight_change == WTCHANGE_NONDELIBERATE_WTLOSS_OR_WTGAIN 

3225 ): 

3226 # ... redundant check on weight_change, I think! 

3227 r.decide("Weight gain ≥0.5 st in past month.") 

3228 r.weight_change = WTCHANGE_WTGAIN_GE_HALF_STONE 

3229 

3230 # -------------------------------------------------------------------- 

3231 # Somatic symptoms 

3232 # -------------------------------------------------------------------- 

3233 

3234 elif q == CQ.GP_YEAR: 

3235 # Score the preceding block: 

3236 if ( 

3237 r.weight_change == WTCHANGE_WTLOSS_GE_HALF_STONE 

3238 and self.answer_is_yes(CQ.APPETITE1_LOSS_PAST_MONTH) 

3239 ): 

3240 r.decide( 

3241 "Appetite loss and weight loss ≥0.5st in past month. " 

3242 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3243 ) 

3244 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3245 if ( 

3246 r.weight_change == WTCHANGE_WTGAIN_GE_HALF_STONE 

3247 and self.answer_is_yes(CQ.APPETITE2_INCREASE_PAST_MONTH) 

3248 ): 

3249 r.decide( 

3250 "Appetite gain and weight gain ≥0.5st in past month. " 

3251 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3252 ) 

3253 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3254 

3255 elif q == CQ.DISABLE: 

3256 if self.answer_is_no(q): 

3257 r.decide("No longstanding illness/disability/infirmity.") 

3258 jump_to(CQ.SOMATIC_MAND1_PAIN_PAST_MONTH) 

3259 

3260 elif q == CQ.ILLNESS: 

3261 pass 

3262 

3263 elif q == CQ.SOMATIC_MAND1_PAIN_PAST_MONTH: 

3264 if self.answer_is_no(q): 

3265 r.decide("No aches/pains in past month.") 

3266 jump_to(CQ.SOMATIC_MAND2_DISCOMFORT) 

3267 

3268 elif q == CQ.SOMATIC_PAIN1_PSYCHOL_EXAC: 

3269 if v == V_SOMATIC_PAIN1_NEVER: 

3270 r.decide("Pains never exacerbated by low mood/anxiety/stress.") 

3271 jump_to(CQ.SOMATIC_MAND2_DISCOMFORT) 

3272 

3273 elif q == CQ.SOMATIC_PAIN2_DAYS_PAST_WEEK: 

3274 if v == V_DAYS_IN_PAST_WEEK_0: 

3275 r.decide("No pain in last 7 days.") 

3276 jump_to(CQ.SOMATIC_MAND2_DISCOMFORT) 

3277 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3278 r.decide( 

3279 "Pain on >=4 of last 7 days. " 

3280 "Incrementing somatic_symptoms." 

3281 ) 

3282 r.somatic_symptoms += 1 

3283 

3284 elif q == CQ.SOMATIC_PAIN3_GT_3H_ANY_DAY: 

3285 if self.answer_is_yes(q, v): 

3286 r.decide( 

3287 "Pain for >3h on any day in past week. " 

3288 "Incrementing somatic_symptoms." 

3289 ) 

3290 r.somatic_symptoms += 1 

3291 

3292 elif q == CQ.SOMATIC_PAIN4_UNPLEASANT: 

3293 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

3294 r.decide( 

3295 "Pain 'unpleasant' or worse in past week. " 

3296 "Incrementing somatic_symptoms." 

3297 ) 

3298 r.somatic_symptoms += 1 

3299 

3300 elif q == CQ.SOMATIC_PAIN5_INTERRUPTED_INTERESTING: 

3301 if self.answer_is_yes(q, v): 

3302 r.decide( 

3303 "Pain interrupted an interesting activity in past " 

3304 "week. " 

3305 "Incrementing somatic_symptoms." 

3306 ) 

3307 r.somatic_symptoms += 1 

3308 r.decide("There was pain, so skip 'discomfort' section.") 

3309 jump_to(CQ.SOMATIC_DUR) # skip SOMATIC_MAND2 

3310 

3311 elif q == CQ.SOMATIC_MAND2_DISCOMFORT: 

3312 if self.answer_is_no(q, v): 

3313 r.decide("No discomfort.") 

3314 jump_to(CQ.FATIGUE_MAND1_TIRED_PAST_MONTH) 

3315 

3316 elif q == CQ.SOMATIC_DIS1_PSYCHOL_EXAC: 

3317 if v == V_SOMATIC_DIS1_NEVER: 

3318 r.decide( 

3319 "Discomfort never exacerbated by being " 

3320 "low/anxious/stressed." 

3321 ) 

3322 jump_to(CQ.FATIGUE_MAND1_TIRED_PAST_MONTH) 

3323 

3324 elif q == CQ.SOMATIC_DIS2_DAYS_PAST_WEEK: 

3325 if v == V_DAYS_IN_PAST_WEEK_0: 

3326 r.decide("No discomfort in last 7 days.") 

3327 jump_to(CQ.FATIGUE_MAND1_TIRED_PAST_MONTH) 

3328 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3329 r.decide( 

3330 "Discomfort on >=4 days in past week. " 

3331 "Incrementing somatic_symptoms." 

3332 ) 

3333 r.somatic_symptoms += 1 

3334 

3335 elif q == CQ.SOMATIC_DIS3_GT_3H_ANY_DAY: 

3336 if self.answer_is_yes(q, v): 

3337 r.decide( 

3338 "Discomfort for >3h on any day in past week. " 

3339 "Incrementing somatic_symptoms." 

3340 ) 

3341 r.somatic_symptoms += 1 

3342 

3343 elif q == CQ.SOMATIC_DIS4_UNPLEASANT: 

3344 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

3345 r.decide( 

3346 "Discomfort 'unpleasant' or worse in past week. " 

3347 "Incrementing somatic_symptoms." 

3348 ) 

3349 r.somatic_symptoms += 1 

3350 

3351 elif q == CQ.SOMATIC_DIS5_INTERRUPTED_INTERESTING: 

3352 if self.answer_is_yes(q, v): 

3353 r.decide( 

3354 "Discomfort interrupted an interesting activity in " 

3355 "past " 

3356 "week. Incrementing somatic_symptoms." 

3357 ) 

3358 r.somatic_symptoms += 1 

3359 

3360 # -------------------------------------------------------------------- 

3361 # Fatigue/energy 

3362 # -------------------------------------------------------------------- 

3363 

3364 elif q == CQ.FATIGUE_MAND1_TIRED_PAST_MONTH: 

3365 if self.answer_is_no(q, v): 

3366 r.decide("Not tired.") 

3367 jump_to(CQ.FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH) 

3368 

3369 elif q == CQ.FATIGUE_CAUSE1_TIRED: 

3370 if v == V_FATIGUE_CAUSE_EXERCISE: 

3371 r.decide("Tired due to exercise. Move on.") 

3372 jump_to(CQ.CONC_MAND1_POOR_CONC_PAST_MONTH) 

3373 

3374 elif q == CQ.FATIGUE_TIRED1_DAYS_PAST_WEEK: 

3375 if v == V_DAYS_IN_PAST_WEEK_0: 

3376 r.decide("Not tired in past week.") 

3377 jump_to(CQ.FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH) 

3378 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3379 r.decide( 

3380 "Tired on >=4 days in past week. " "Incrementing fatigue." 

3381 ) 

3382 r.fatigue += 1 

3383 

3384 elif q == CQ.FATIGUE_TIRED2_GT_3H_ANY_DAY: 

3385 if self.answer_is_yes(q, v): 

3386 r.decide( 

3387 "Tired for >3h on any day in past week. " 

3388 "Incrementing fatigue." 

3389 ) 

3390 r.fatigue += 1 

3391 

3392 elif q == CQ.FATIGUE_TIRED3_HAD_TO_PUSH: 

3393 if self.answer_is_yes(q, v): 

3394 r.decide( 

3395 "Tired enough to have to push self during past week. " 

3396 "Incrementing fatigue." 

3397 ) 

3398 r.fatigue += 1 

3399 

3400 elif q == CQ.FATIGUE_TIRED4_DURING_ENJOYABLE: 

3401 if self.answer_is_yes(q, v): 

3402 r.decide( 

3403 "Tired during an enjoyable activity during past " 

3404 "week. " 

3405 "Incrementing fatigue." 

3406 ) 

3407 r.fatigue += 1 

3408 r.decide("There was tiredness, so skip 'lack of energy' section.") 

3409 jump_to(CQ.FATIGUE_DUR) # skip FATIGUE_MAND2 

3410 

3411 elif q == CQ.FATIGUE_MAND2_LACK_ENERGY_PAST_MONTH: 

3412 if self.answer_is_no(q, v): 

3413 r.decide("Not lacking in energy.") 

3414 jump_to(CQ.CONC_MAND1_POOR_CONC_PAST_MONTH) 

3415 

3416 elif q == CQ.FATIGUE_CAUSE2_LACK_ENERGY: 

3417 if v == V_FATIGUE_CAUSE_EXERCISE: 

3418 r.decide("Lacking in energy due to exercise. Move on.") 

3419 jump_to(CQ.CONC_MAND1_POOR_CONC_PAST_MONTH) 

3420 

3421 elif q == CQ.FATIGUE_ENERGY1_DAYS_PAST_WEEK: 

3422 if v == V_DAYS_IN_PAST_WEEK_0: 

3423 r.decide("Not lacking in energy during last week.") 

3424 jump_to(CQ.CONC_MAND1_POOR_CONC_PAST_MONTH) 

3425 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3426 r.decide( 

3427 "Lacking in energy on >=4 days in past week. " 

3428 "Incrementing fatigue." 

3429 ) 

3430 r.fatigue += 1 

3431 

3432 elif q == CQ.FATIGUE_ENERGY2_GT_3H_ANY_DAY: 

3433 if self.answer_is_yes(q, v): 

3434 r.decide( 

3435 "Lacking in energy for >3h on any day in past week. " 

3436 "Incrementing fatigue." 

3437 ) 

3438 r.fatigue += 1 

3439 

3440 elif q == CQ.FATIGUE_ENERGY3_HAD_TO_PUSH: 

3441 if self.answer_is_yes(q, v): 

3442 r.decide( 

3443 "Lacking in energy enough to have to push self during " 

3444 "past week. Incrementing fatigue." 

3445 ) 

3446 r.fatigue += 1 

3447 

3448 elif q == CQ.FATIGUE_ENERGY4_DURING_ENJOYABLE: 

3449 if self.answer_is_yes(q, v): 

3450 r.decide( 

3451 "Lacking in energy during an enjoyable activity " 

3452 "during " 

3453 "past week. Incrementing fatigue." 

3454 ) 

3455 r.fatigue += 1 

3456 

3457 elif q == CQ.FATIGUE_DUR: 

3458 # Score preceding: 

3459 if r.somatic_symptoms >= 2 and r.fatigue >= 2: 

3460 r.decide( 

3461 "somatic >= 2 and fatigue >= 2. " 

3462 "Incrementing neurasthenia." 

3463 ) 

3464 r.neurasthenia += 1 

3465 

3466 # -------------------------------------------------------------------- 

3467 # Concentration/memory 

3468 # -------------------------------------------------------------------- 

3469 

3470 elif q == CQ.CONC_MAND1_POOR_CONC_PAST_MONTH: 

3471 # Score preceding: 

3472 if r.fatigue >= 2: 

3473 r.decide( 

3474 "fatigue >= 2. " 

3475 "Incrementing depr_crit_1_mood_anhedonia_energy." 

3476 ) 

3477 r.depr_crit_1_mood_anhedonia_energy += 1 

3478 

3479 elif q == CQ.CONC_MAND2_FORGETFUL_PAST_MONTH: 

3480 if self.answer_is_no( 

3481 CQ.CONC_MAND1_POOR_CONC_PAST_MONTH 

3482 ) and self.answer_is_no(q, v): 

3483 r.decide("No problems with concentration or forgetfulness.") 

3484 jump_to(CQ.SLEEP_MAND1_LOSS_PAST_MONTH) 

3485 

3486 elif q == CQ.CONC1_CONC_DAYS_PAST_WEEK: 

3487 if v == V_DAYS_IN_PAST_WEEK_0: 

3488 r.decide("No concentration/memory problems in past week.") 

3489 jump_to(CQ.SLEEP_MAND1_LOSS_PAST_MONTH) 

3490 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3491 r.decide( 

3492 "Problems with concentration/memory problems on >=4 " 

3493 "days in past week. Incrementing concentration_poor." 

3494 ) 

3495 r.concentration_poor += 1 

3496 if self.answer_is_no( 

3497 CQ.CONC_MAND1_POOR_CONC_PAST_MONTH 

3498 ) and self.answer_is_yes(CQ.CONC_MAND2_FORGETFUL_PAST_MONTH): 

3499 r.decide( 

3500 "Forgetfulness, not concentration, problems; skip " 

3501 "over more detailed concentration questions." 

3502 ) 

3503 jump_to( 

3504 CQ.CONC4_FORGOTTEN_IMPORTANT 

3505 ) # skip CONC2, CONC3, CONC_DUR # noqa 

3506 

3507 elif q == CQ.CONC2_CONC_FOR_TV_READING_CONVERSATION: 

3508 if self.answer_is_no(q, v): 

3509 r.decide( 

3510 "Couldn't concentrate on at least one of {TV, " 

3511 "newspaper, " 

3512 "conversation}. Incrementing concentration_poor." 

3513 ) 

3514 r.concentration_poor += 1 

3515 

3516 elif q == CQ.CONC3_CONC_PREVENTED_ACTIVITIES: 

3517 if self.answer_is_yes(q, v): 

3518 r.decide( 

3519 "Problems with concentration stopped usual/desired " 

3520 "activity. Incrementing concentration_poor." 

3521 ) 

3522 r.concentration_poor += 1 

3523 

3524 elif q == CQ.CONC_DUR: 

3525 if self.answer_is_no(CQ.CONC_MAND2_FORGETFUL_PAST_MONTH): 

3526 jump_to(CQ.SLEEP_MAND1_LOSS_PAST_MONTH) 

3527 

3528 elif q == CQ.CONC4_FORGOTTEN_IMPORTANT: 

3529 if self.answer_is_yes(q, v): 

3530 r.decide( 

3531 "Forgotten something important in past week. " 

3532 "Incrementing concentration_poor." 

3533 ) 

3534 r.concentration_poor += 1 

3535 

3536 elif q == CQ.FORGET_DUR: 

3537 pass 

3538 

3539 # -------------------------------------------------------------------- 

3540 # Sleep 

3541 # -------------------------------------------------------------------- 

3542 

3543 elif q == CQ.SLEEP_MAND1_LOSS_PAST_MONTH: 

3544 # Score previous block: 

3545 if r.concentration_poor >= 2: 

3546 r.decide( 

3547 "concentration >= 2. " 

3548 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3549 ) 

3550 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3551 # This question: 

3552 if self.answer_is_no(q, v): 

3553 r.decide( 

3554 "No problems with sleep loss in past month. " "Moving on." 

3555 ) 

3556 jump_to(CQ.SLEEP_MAND2_GAIN_PAST_MONTH) 

3557 

3558 elif q == CQ.SLEEP_LOSE1_NIGHTS_PAST_WEEK: 

3559 if v == V_NIGHTS_IN_PAST_WEEK_0: 

3560 r.decide("No problems with sleep in past week. Moving on.") 

3561 jump_to(CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH) 

3562 elif v == V_NIGHTS_IN_PAST_WEEK_4_OR_MORE: 

3563 r.decide( 

3564 "Problems with sleep on >=4 nights in past week. " 

3565 "Incrementing sleep_problems." 

3566 ) 

3567 r.sleep_problems += 1 

3568 

3569 elif q == CQ.SLEEP_LOSE2_DIS_WORST_DURATION: 

3570 if v == V_SLEEP_CHANGE_LT_15_MIN: 

3571 r.decide( 

3572 "Less than 15min maximum delayed initiation of sleep " 

3573 "in past week. Moving on." 

3574 ) 

3575 jump_to(CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH) 

3576 elif v == V_SLEEP_CHANGE_15_MIN_TO_1_H: 

3577 r.decide( 

3578 "15min-1h maximum delayed initiation of sleep in past " 

3579 "week. Incrementing sleep_problems." 

3580 ) 

3581 r.sleep_problems += 1 

3582 elif v == V_SLEEP_CHANGE_1_TO_3_H or v == V_SLEEP_CHANGE_GT_3_H: 

3583 r.decide( 

3584 ">=1h maximum delayed initiation of sleep in past " 

3585 "week. Adding 2 to sleep_problems." 

3586 ) 

3587 r.sleep_problems += 2 

3588 

3589 elif q == CQ.SLEEP_LOSE3_NIGHTS_GT_3H_DIS_PAST_WEEK: 

3590 if v == V_NIGHTS_IN_PAST_WEEK_4_OR_MORE: 

3591 r.decide( 

3592 ">=4 nights in past week with >=3h delayed " 

3593 "initiation of " 

3594 "sleep. Incrementing sleep_problems." 

3595 ) 

3596 r.sleep_problems += 1 

3597 

3598 elif q == CQ.SLEEP_EMW_PAST_WEEK: 

3599 if self.answer_is_yes(q, v): 

3600 r.decide( 

3601 "EMW of >2h in past week. " 

3602 "Setting sleep_change to SLEEPCHANGE_EMW. " 

3603 "Incrementing depr_crit_3_somatic_synd." 

3604 ) 

3605 # Was: SLEEPCH += answer - 1 (which only does anything for a 

3606 # "yes" (2) answer). 

3607 # ... but at this point, SLEEPCH is always 0. 

3608 r.sleep_change = SLEEPCHANGE_EMW # LIKELY REDUNDANT. 

3609 r.depr_crit_3_somatic_synd += 1 

3610 if r.sleep_problems >= 1: 

3611 r.decide( 

3612 "EMW of >2h in past week and sleep_problems >= 1; " 

3613 "setting sleep_change to SLEEPCHANGE_EMW." 

3614 ) 

3615 r.sleep_change = SLEEPCHANGE_EMW 

3616 elif self.answer_is_no(q, v): 

3617 r.decide("No EMW of >2h in past week.") 

3618 if r.sleep_problems >= 1: 

3619 r.decide( 

3620 "No EMW of >2h in past week, and sleep_problems " 

3621 ">= 1. Setting sleep_change to " 

3622 "SLEEPCHANGE_INSOMNIA_NOT_EMW." 

3623 ) 

3624 r.sleep_change = SLEEPCHANGE_INSOMNIA_NOT_EMW 

3625 

3626 elif q == CQ.SLEEP_CAUSE: 

3627 r.decide("Problems with sleep loss; skipping over sleep gain.") 

3628 jump_to(CQ.SLEEP_DUR) 

3629 

3630 elif q == CQ.SLEEP_MAND2_GAIN_PAST_MONTH: 

3631 if ( 

3632 v == V_SLEEP_MAND2_NO 

3633 or v == V_SLEEP_MAND2_YES_BUT_NOT_A_PROBLEM 

3634 ): 

3635 r.decide("No problematic sleep gain. Moving on.") 

3636 jump_to(CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH) 

3637 

3638 elif q == CQ.SLEEP_GAIN1_NIGHTS_PAST_WEEK: 

3639 if v == V_NIGHTS_IN_PAST_WEEK_0: 

3640 r.decide("No nights with sleep problems [gain] in past week.") 

3641 jump_to(CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH) 

3642 elif v == V_NIGHTS_IN_PAST_WEEK_4_OR_MORE: 

3643 r.decide( 

3644 "Problems with sleep [gain] on >=4 nights in past " 

3645 "week. Incrementing sleep_problems." 

3646 ) 

3647 r.sleep_problems += 1 

3648 

3649 elif q == CQ.SLEEP_GAIN2_EXTRA_ON_LONGEST_NIGHT: 

3650 if v == V_SLEEP_CHANGE_LT_15_MIN: 

3651 r.decide("Sleep gain <15min. Moving on.") 

3652 jump_to(CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH) 

3653 elif v == V_SLEEP_CHANGE_15_MIN_TO_1_H: 

3654 r.decide("Sleep gain 15min-1h. Incrementing sleep_problems.") 

3655 r.sleep_problems += 1 

3656 elif v >= V_SLEEP_CHANGE_1_TO_3_H: 

3657 r.decide( 

3658 "Sleep gain >=1h. " 

3659 "Adding 2 to sleep_problems. " 

3660 "Setting sleep_change to SLEEPCHANGE_INCREASE." 

3661 ) 

3662 r.sleep_problems += 2 

3663 r.sleep_change = SLEEPCHANGE_INCREASE 

3664 # Note that in the original, if the answer was 3 

3665 # (V_SLEEP_CHANGE_1_TO_3_H) or greater, first 2 was added to 

3666 # sleep, and then if sleep was >=1, sleepch [sleep_change] was set # noqa 

3667 # to 3. However, sleep is never decremented/set below 0, so that # noqa 

3668 # was a redundant test (always true). 

3669 

3670 elif q == CQ.SLEEP_GAIN3_NIGHTS_GT_3H_EXTRA_PAST_WEEK: 

3671 if v == V_NIGHTS_IN_PAST_WEEK_4_OR_MORE: 

3672 r.decide( 

3673 "Sleep gain of >3h on >=4 nights in past week. " 

3674 "Incrementing sleep_problems." 

3675 ) 

3676 r.sleep_problems += 1 

3677 

3678 elif q == CQ.SLEEP_DUR: 

3679 pass 

3680 

3681 # -------------------------------------------------------------------- 

3682 # Irritability 

3683 # -------------------------------------------------------------------- 

3684 

3685 elif q == CQ.IRRIT_MAND1_PEOPLE_PAST_MONTH: 

3686 # Score previous block: 

3687 if r.sleep_problems >= 2: 

3688 r.decide( 

3689 "sleep_problems >= 2. " 

3690 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3691 ) 

3692 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3693 # This bit erroneously lived under IRRIT_DUR in the original; see 

3694 # discussion there: 

3695 if r.sleep_problems >= 2 and r.fatigue >= 2: 

3696 r.decide( 

3697 "sleep_problems >=2 and fatigue >=2. " 

3698 "Incrementing neurasthenia." 

3699 ) 

3700 r.neurasthenia += 1 

3701 # This question: 

3702 if self.answer_is_yes(q, v): 

3703 r.decide( 

3704 "Irritability (people) in past month; exploring " 

3705 "further." 

3706 ) 

3707 jump_to(CQ.IRRIT1_DAYS_PER_WEEK) 

3708 

3709 elif q == CQ.IRRIT_MAND2_THINGS_PAST_MONTH: 

3710 if v == V_IRRIT_MAND2_NO: 

3711 r.decide("No irritability. Moving on.") 

3712 jump_to(CQ.HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH) 

3713 elif self.answered(q, v): 

3714 r.decide( 

3715 "Irritability (things) in past month; exploring " 

3716 "further." 

3717 ) 

3718 

3719 elif q == CQ.IRRIT1_DAYS_PER_WEEK: 

3720 if v == V_DAYS_IN_PAST_WEEK_0: 

3721 r.decide("No irritability in past week. Moving on.") 

3722 jump_to(CQ.HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH) 

3723 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3724 r.decide( 

3725 "Irritable on >=4 days in past week. " 

3726 "Incrementing irritability." 

3727 ) 

3728 r.irritability += 1 

3729 

3730 elif q == CQ.IRRIT2_GT_1H_ANY_DAY: 

3731 if self.answer_is_yes(q, v): 

3732 r.decide( 

3733 "Irritable for >1h on any day in past week. " 

3734 "Incrementing irritability." 

3735 ) 

3736 r.irritability += 1 

3737 

3738 elif q == CQ.IRRIT3_WANTED_TO_SHOUT: 

3739 if v >= V_IRRIT3_SHOUTING_WANTED_TO: 

3740 r.decide("Wanted to or did shout. Incrementing irritability.") 

3741 r.irritability += 1 

3742 

3743 elif q == CQ.IRRIT4_ARGUMENTS: 

3744 if v == V_IRRIT4_ARGUMENTS_YES_UNJUSTIFIED: 

3745 r.decide( 

3746 "Arguments without justification. " 

3747 "Incrementing irritability." 

3748 ) 

3749 r.irritability += 1 

3750 

3751 elif q == CQ.IRRIT_DUR: 

3752 # Score recent things: 

3753 if r.irritability >= 2 and r.fatigue >= 2: 

3754 r.decide( 

3755 "irritability >=2 and fatigue >=2. " 

3756 "Incrementing neurasthenia." 

3757 ) 

3758 r.neurasthenia += 1 

3759 # In the original, we had the rule "sleep_problems >=2 and 

3760 # fatigue >=2 -> incrementing neurasthenia" here, but that would mean # noqa 

3761 # we would fail to score sleep if the patient didn't report 

3762 # irritability (because if you say no at IRRIT_MAND2, you jump beyond # noqa 

3763 # this point to HYPO_MAND1). Checked with Glyn Lewis 2017-12-04, who # noqa 

3764 # agreed on 2017-12-05. Therefore, moved to IRRIT_MAND1 as above. 

3765 # Note that the only implication would have been potential small 

3766 # mis-scoring of the CFS criterion (not any of the diagnoses that 

3767 # the CIS-R reports as its primary/secondary diagnoses). 

3768 

3769 # -------------------------------------------------------------------- 

3770 # Hypochondriasis 

3771 # -------------------------------------------------------------------- 

3772 

3773 elif q == CQ.HYPO_MAND1_WORRIED_RE_HEALTH_PAST_MONTH: 

3774 if self.answer_is_yes(q, v): 

3775 r.decide( 

3776 "No worries about physical health in past month. " 

3777 "Moving on." 

3778 ) 

3779 jump_to(CQ.HYPO1_DAYS_PAST_WEEK) 

3780 

3781 elif q == CQ.HYPO_MAND2_WORRIED_RE_SERIOUS_ILLNESS: 

3782 if self.answer_is_no(q, v): 

3783 r.decide( 

3784 "No worries about having a serious illness. " "Moving on." 

3785 ) 

3786 jump_to(CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH) 

3787 

3788 elif q == CQ.HYPO1_DAYS_PAST_WEEK: 

3789 if v == V_DAYS_IN_PAST_WEEK_0: 

3790 r.decide( 

3791 "No days in past week worrying about health. " "Moving on." 

3792 ) 

3793 jump_to(CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH) 

3794 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3795 r.decide( 

3796 "Worries about health on >=4 days in past week. " 

3797 "Incrementing hypochondria." 

3798 ) 

3799 r.hypochondria += 1 

3800 

3801 elif q == CQ.HYPO2_WORRY_TOO_MUCH: 

3802 if self.answer_is_yes(q, v): 

3803 r.decide( 

3804 "Worrying too much about health. " 

3805 "Incrementing hypochondria." 

3806 ) 

3807 r.hypochondria += 1 

3808 

3809 elif q == CQ.HYPO3_HOW_UNPLEASANT: 

3810 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

3811 r.decide( 

3812 "Worrying re health 'unpleasant' or worse in past " 

3813 "week. Incrementing hypochondria." 

3814 ) 

3815 r.hypochondria += 1 

3816 

3817 elif q == CQ.HYPO4_CAN_DISTRACT: 

3818 if self.answer_is_no(q, v): 

3819 r.decide( 

3820 "Cannot take mind off health worries by doing " 

3821 "something else. Incrementing hypochondria." 

3822 ) 

3823 r.hypochondria += 1 

3824 

3825 elif q == CQ.HYPO_DUR: 

3826 pass 

3827 

3828 # -------------------------------------------------------------------- 

3829 # Depression 

3830 # -------------------------------------------------------------------- 

3831 

3832 elif q == CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH: 

3833 if self.answer_is_no(q, v): 

3834 r.decide("Mood not low in past month. Moving to anhedonia.") 

3835 jump_to(CQ.DEPR_MAND2_ENJOYMENT_PAST_MONTH) 

3836 

3837 elif q == CQ.DEPR1_LOW_MOOD_PAST_WEEK: 

3838 pass 

3839 

3840 elif q == CQ.DEPR_MAND2_ENJOYMENT_PAST_MONTH: 

3841 if v == V_ANHEDONIA_ENJOYING_NORMALLY and self.answer_is_no( 

3842 CQ.DEPR1_LOW_MOOD_PAST_WEEK 

3843 ): 

3844 r.decide( 

3845 "Neither low mood nor anhedonia in past month. " 

3846 "Moving on." 

3847 ) 

3848 jump_to(CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH) 

3849 

3850 elif q == CQ.DEPR2_ENJOYMENT_PAST_WEEK: 

3851 if v == V_ANHEDONIA_ENJOYING_NORMALLY and self.answer_is_no( 

3852 CQ.DEPR_MAND1_LOW_MOOD_PAST_MONTH 

3853 ): 

3854 r.decide( 

3855 "No anhedonia in past week and no low mood in past " 

3856 "month. Moving on." 

3857 ) 

3858 jump_to(CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH) 

3859 elif v >= V_ANHEDONIA_ENJOYING_LESS: 

3860 r.decide( 

3861 "Partial or complete anhedonia in past week. " 

3862 "Incrementing depression. " 

3863 "Incrementing depr_crit_1_mood_anhedonia_energy. " 

3864 "Incrementing depr_crit_3_somatic_synd." 

3865 ) 

3866 r.depression += 1 

3867 r.depr_crit_1_mood_anhedonia_energy += 1 

3868 r.depr_crit_3_somatic_synd += 1 

3869 

3870 elif q == CQ.DEPR3_DAYS_PAST_WEEK: 

3871 if v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

3872 r.decide( 

3873 "Low mood or anhedonia on >=4 days in past week. " 

3874 "Incrementing depression." 

3875 ) 

3876 r.depression += 1 

3877 

3878 elif q == CQ.DEPR4_GT_3H_ANY_DAY: 

3879 if self.answer_is_yes(q, v): 

3880 r.decide( 

3881 "Low mood or anhedonia for >3h/day on at least one " 

3882 "day in past week. Incrementing depression." 

3883 ) 

3884 r.depression += 1 

3885 if self.int_value_for_question( 

3886 CQ.DEPR3_DAYS_PAST_WEEK 

3887 ) and self.answer_is_yes(CQ.DEPR1_LOW_MOOD_PAST_WEEK): 

3888 r.decide( 

3889 "(A) Low mood in past week, and " 

3890 "(B) low mood or anhedonia for >3h/day on at " 

3891 "least one day in past week, and " 

3892 "(C) low mood or anhedonia on >=4 days in past " 

3893 "week. " 

3894 "Incrementing depr_crit_1_mood_anhedonia_energy." 

3895 ) 

3896 r.depr_crit_1_mood_anhedonia_energy += 1 

3897 

3898 elif q == CQ.DEPR_CONTENT: 

3899 pass 

3900 

3901 elif q == CQ.DEPR5_COULD_CHEER_UP: 

3902 if v >= V_DEPR5_COULD_CHEER_UP_SOMETIMES: 

3903 r.decide( 

3904 "'Sometimes' or 'never' cheered up by nice things. " 

3905 "Incrementing depression. " 

3906 "Incrementing depr_crit_3_somatic_synd." 

3907 ) 

3908 r.depression += 1 

3909 r.depr_crit_3_somatic_synd += 1 

3910 

3911 elif q == CQ.DEPR_DUR: 

3912 if v >= V_DURATION_2W_6M: 

3913 r.decide( 

3914 "Depressive symptoms for >=2 weeks. " 

3915 "Setting depression_at_least_2_weeks." 

3916 ) 

3917 r.depression_at_least_2_weeks = True 

3918 # This code was at the start of DEPTH1, but involves skipping over 

3919 # DEPTH1; since we never get to DEPTH1 without coming here, we can 

3920 # move it here: 

3921 if r.depression == 0: 

3922 r.decide( 

3923 "Score for 'depression' is 0; skipping over " 

3924 "depressive thought content questions." 

3925 ) 

3926 jump_to(CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH) 

3927 

3928 elif q == CQ.DEPTH1_DIURNAL_VARIATION: 

3929 if ( 

3930 v == V_DEPTH1_DMV_WORSE_MORNING 

3931 or v == V_DEPTH1_DMV_WORSE_EVENING 

3932 ): 

3933 r.decide("Diurnal mood variation present.") 

3934 r.diurnal_mood_variation = ( 

3935 DIURNAL_MOOD_VAR_WORSE_MORNING 

3936 if v == V_DEPTH1_DMV_WORSE_MORNING 

3937 else DIURNAL_MOOD_VAR_WORSE_EVENING 

3938 ) 

3939 if v == V_DEPTH1_DMV_WORSE_MORNING: 

3940 r.decide( 

3941 "Diurnal mood variation, worse in the mornings. " 

3942 "Incrementing depr_crit_3_somatic_synd." 

3943 ) 

3944 r.depr_crit_3_somatic_synd += 1 

3945 

3946 elif q == CQ.DEPTH2_LIBIDO: 

3947 if v == V_DEPTH2_LIBIDO_DECREASED: 

3948 r.decide( 

3949 "Libido decreased over past month. " 

3950 "Setting libido_decreased. " 

3951 "Incrementing depr_crit_3_somatic_synd." 

3952 ) 

3953 r.libido_decreased = True 

3954 r.depr_crit_3_somatic_synd += 1 

3955 

3956 elif q == CQ.DEPTH3_RESTLESS: 

3957 if self.answer_is_yes(q): 

3958 r.decide("Psychomotor agitation.") 

3959 r.psychomotor_changes = PSYCHOMOTOR_AGITATION 

3960 

3961 elif q == CQ.DEPTH4_SLOWED: 

3962 if self.answer_is_yes(q): 

3963 r.decide("Psychomotor retardation.") 

3964 r.psychomotor_changes = PSYCHOMOTOR_RETARDATION 

3965 if r.psychomotor_changes > PSYCHOMOTOR_NONE: 

3966 r.decide( 

3967 "Psychomotor agitation or retardation. " 

3968 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui. " 

3969 "Incrementing depr_crit_3_somatic_synd." 

3970 ) 

3971 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3972 r.depr_crit_3_somatic_synd += 1 

3973 

3974 elif q == CQ.DEPTH5_GUILT: 

3975 if v >= V_DEPTH5_GUILT_SOMETIMES: 

3976 r.decide( 

3977 "Feel guilty when not at fault sometimes or often. " 

3978 "Incrementing depressive_thoughts. " 

3979 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3980 ) 

3981 r.depressive_thoughts += 1 

3982 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3983 

3984 elif q == CQ.DEPTH6_WORSE_THAN_OTHERS: 

3985 if self.answer_is_yes(q, v): 

3986 r.decide( 

3987 "Feeling not as good as other people. " 

3988 "Incrementing depressive_thoughts. " 

3989 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

3990 ) 

3991 r.depressive_thoughts += 1 

3992 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

3993 

3994 elif q == CQ.DEPTH7_HOPELESS: 

3995 if self.answer_is_yes(q, v): 

3996 r.decide( 

3997 "Hopelessness. " 

3998 "Incrementing depressive_thoughts. " 

3999 "Setting suicidality to " 

4000 "SUICIDE_INTENT_HOPELESS_NO_SUICIDAL_THOUGHTS." 

4001 ) 

4002 r.depressive_thoughts += 1 

4003 r.suicidality = SUICIDE_INTENT_HOPELESS_NO_SUICIDAL_THOUGHTS 

4004 

4005 elif q == CQ.DEPTH8_LNWL: 

4006 if v == V_DEPTH8_LNWL_NO: 

4007 r.decide( 

4008 "No thoughts of life not being worth living. " 

4009 "Skipping to end of depression section." 

4010 ) 

4011 jump_to(CQ.DEPR_OUTRO) 

4012 elif v >= V_DEPTH8_LNWL_SOMETIMES: 

4013 r.decide( 

4014 "Sometimes or always feeling life isn't worth living. " 

4015 "Incrementing depressive_thoughts. " 

4016 "Setting suicidality to " 

4017 "SUICIDE_INTENT_LIFE_NOT_WORTH_LIVING." 

4018 ) 

4019 r.depressive_thoughts += 1 

4020 r.suicidality = SUICIDE_INTENT_LIFE_NOT_WORTH_LIVING 

4021 

4022 elif q == CQ.DEPTH9_SUICIDE_THOUGHTS: 

4023 if v == V_DEPTH9_SUICIDAL_THOUGHTS_NO: 

4024 r.decide( 

4025 "No thoughts of suicide. Skipping to end of " 

4026 "depression section." 

4027 ) 

4028 jump_to(CQ.DEPR_OUTRO) 

4029 if v >= V_DEPTH9_SUICIDAL_THOUGHTS_YES_BUT_NEVER_WOULD: 

4030 r.decide( 

4031 "Suicidal thoughts present. " 

4032 "Setting suicidality to " 

4033 "SUICIDE_INTENT_SUICIDAL_THOUGHTS." 

4034 ) 

4035 r.suicidality = SUICIDE_INTENT_SUICIDAL_THOUGHTS 

4036 if v == V_DEPTH9_SUICIDAL_THOUGHTS_YES_BUT_NEVER_WOULD: 

4037 r.decide( 

4038 "Suicidal thoughts present but denies would ever act. " 

4039 "Skipping to talk-to-doctor section." 

4040 ) 

4041 jump_to(CQ.DOCTOR) 

4042 if v == V_DEPTH9_SUICIDAL_THOUGHTS_YES: 

4043 r.decide( 

4044 "Thoughts of suicide in past week. " 

4045 "Incrementing depressive_thoughts. " 

4046 "Incrementing depr_crit_2_app_cnc_slp_mtr_glt_wth_sui." 

4047 ) 

4048 r.depressive_thoughts += 1 

4049 r.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui += 1 

4050 

4051 elif q == CQ.DEPTH10_SUICIDE_METHOD: 

4052 if self.answer_is_yes(q, v): 

4053 r.decide( 

4054 "Suicidal thoughts without denying might ever act. " 

4055 "Setting suicidality to " 

4056 "SUICIDE_INTENT_SUICIDAL_PLANS." 

4057 ) 

4058 r.suicidality = SUICIDE_INTENT_SUICIDAL_PLANS 

4059 

4060 elif q == CQ.DOCTOR: 

4061 if v == V_DOCTOR_YES: 

4062 r.decide( 

4063 "Has spoken to doctor about suicidality. Skipping " 

4064 "exhortation to do so." 

4065 ) 

4066 jump_to(CQ.DEPR_OUTRO) 

4067 

4068 elif q == CQ.DOCTOR2_PLEASE_TALK_TO: 

4069 pass 

4070 

4071 elif q == CQ.DEPR_OUTRO: 

4072 pass 

4073 

4074 # -------------------------------------------------------------------- 

4075 # Worry/anxiety 

4076 # -------------------------------------------------------------------- 

4077 

4078 elif q == CQ.WORRY_MAND1_MORE_THAN_NEEDED_PAST_MONTH: 

4079 if v >= V_NSO_SOMETIMES: 

4080 r.decide( 

4081 "Worrying excessively 'sometimes' or 'often'. " 

4082 "Exploring further." 

4083 ) 

4084 jump_to(CQ.WORRY_CONT1) 

4085 

4086 elif q == CQ.WORRY_MAND2_ANY_WORRIES_PAST_MONTH: 

4087 if self.answer_is_no(q, v): 

4088 r.decide("No worries at all in the past month. Moving on.") 

4089 jump_to(CQ.ANX_MAND1_ANXIETY_PAST_MONTH) 

4090 

4091 elif q == CQ.WORRY_CONT1: 

4092 pass 

4093 

4094 elif q == CQ.WORRY1_INFO_ONLY: 

4095 pass 

4096 

4097 elif q == CQ.WORRY2_DAYS_PAST_WEEK: 

4098 if v == V_DAYS_IN_PAST_WEEK_0: 

4099 r.decide( 

4100 "Worry [other than re physical health] on 0 days in " 

4101 "past week. Moving on." 

4102 ) 

4103 jump_to(CQ.ANX_MAND1_ANXIETY_PAST_MONTH) 

4104 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4105 r.decide( 

4106 "Worry [other than re physical health] on >=4 days in " 

4107 "past week. Incrementing worry." 

4108 ) 

4109 r.worry += 1 

4110 

4111 elif q == CQ.WORRY3_TOO_MUCH: 

4112 if self.answer_is_yes(q, v): 

4113 r.decide("Worrying too much. Incrementing worry.") 

4114 r.worry += 1 

4115 

4116 elif q == CQ.WORRY4_HOW_UNPLEASANT: 

4117 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

4118 r.decide( 

4119 "Worry [other than re physical health] 'unpleasant' " 

4120 "or worse in past week. Incrementing worry." 

4121 ) 

4122 r.worry += 1 

4123 

4124 elif q == CQ.WORRY5_GT_3H_ANY_DAY: 

4125 if self.answer_is_yes(q, v): 

4126 r.decide( 

4127 "Worry [other than re physical health] for >3h on any " 

4128 "day in past week. Incrementing worry." 

4129 ) 

4130 r.worry += 1 

4131 

4132 elif q == CQ.WORRY_DUR: 

4133 pass 

4134 

4135 elif q == CQ.ANX_MAND1_ANXIETY_PAST_MONTH: 

4136 if self.answer_is_yes(q, v): 

4137 r.decide( 

4138 "Anxious/nervous in past month. " 

4139 "Skipping tension question." 

4140 ) 

4141 jump_to(CQ.ANX_PHOBIA1_SPECIFIC_PAST_MONTH) 

4142 

4143 elif q == CQ.ANX_MAND2_TENSION_PAST_MONTH: 

4144 if v == V_NSO_NO: 

4145 r.decide( 

4146 "No tension in past month (and no anxiety, from " 

4147 "previous question). Moving on." 

4148 ) 

4149 jump_to(CQ.PHOBIAS_MAND_AVOIDANCE_PAST_MONTH) 

4150 

4151 elif q == CQ.ANX_PHOBIA1_SPECIFIC_PAST_MONTH: 

4152 if self.answer_is_no(q, v): 

4153 r.decide("No phobias. Moving on to general anxiety.") 

4154 jump_to(CQ.ANX2_GENERAL_DAYS_PAST_WEEK) 

4155 elif self.answer_is_yes(q, v): 

4156 # This was in ANX_PHOBIA2; PHOBIAS_FLAG was set by arriving 

4157 # there (but that only happens when we get a 'yes' answer 

4158 # here). 

4159 r.decide("Phobias. Exploring further. Setting phobias flag.") 

4160 r.phobias_flag = True 

4161 

4162 elif q == CQ.ANX_PHOBIA2_SPECIFIC_OR_GENERAL: 

4163 if v == V_ANX_PHOBIA2_ALWAYS_SPECIFIC: 

4164 r.decide( 

4165 "Anxiety always specific. " "Skipping generalized anxiety." 

4166 ) 

4167 jump_to(CQ.PHOBIAS_TYPE1) 

4168 

4169 elif q == CQ.ANX1_INFO_ONLY: 

4170 pass 

4171 

4172 elif q == CQ.ANX2_GENERAL_DAYS_PAST_WEEK: 

4173 if v == V_DAYS_IN_PAST_WEEK_0: 

4174 if r.phobias_flag: 

4175 r.decide( 

4176 "No generalized anxiety in past week. " 

4177 "Skipping further generalized anxiety questions." 

4178 ) 

4179 jump_to(CQ.PHOBIAS1_DAYS_PAST_WEEK) 

4180 else: 

4181 r.decide("No generalized anxiety in past week. Moving on.") 

4182 jump_to(CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH) 

4183 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4184 r.decide( 

4185 "Generalized anxiety on >=4 days in past week. " 

4186 "Incrementing anxiety." 

4187 ) 

4188 r.anxiety += 1 

4189 

4190 elif q == CQ.ANX3_GENERAL_HOW_UNPLEASANT: 

4191 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

4192 r.decide( 

4193 "Anxiety 'unpleasant' or worse in past week. " 

4194 "Incrementing anxiety." 

4195 ) 

4196 r.anxiety += 1 

4197 

4198 elif q == CQ.ANX4_GENERAL_PHYSICAL_SYMPTOMS: 

4199 if self.answer_is_yes(q, v): 

4200 r.decide( 

4201 "Physical symptoms of anxiety. " 

4202 "Setting anxiety_physical_symptoms. " 

4203 "Incrementing anxiety." 

4204 ) 

4205 r.anxiety_physical_symptoms = True 

4206 r.anxiety += 1 

4207 

4208 elif q == CQ.ANX5_GENERAL_GT_3H_ANY_DAY: 

4209 if self.answer_is_yes(q, v): 

4210 r.decide( 

4211 "Anxiety for >3h on any day in past week. " 

4212 "Incrementing anxiety." 

4213 ) 

4214 r.anxiety += 1 

4215 

4216 elif q == CQ.ANX_DUR_GENERAL: 

4217 if v >= V_DURATION_2W_6M: 

4218 r.decide( 

4219 "Anxiety for >=2 weeks. " 

4220 "Setting anxiety_at_least_2_weeks." 

4221 ) 

4222 r.anxiety_at_least_2_weeks = True 

4223 if r.phobias_flag: 

4224 r.decide("Phobias flag set. Exploring further.") 

4225 jump_to(CQ.PHOBIAS_TYPE1) 

4226 else: 

4227 if r.anxiety <= 1: 

4228 r.decide("Anxiety score <=1. Moving on to compulsions.") 

4229 jump_to(CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH) 

4230 else: 

4231 r.decide("Anxiety score >=2. Exploring panic.") 

4232 jump_to(CQ.PANIC_MAND_PAST_MONTH) 

4233 

4234 elif q == CQ.PHOBIAS_MAND_AVOIDANCE_PAST_MONTH: 

4235 if self.answer_is_no(q, v): 

4236 if r.anxiety <= 1: 

4237 r.decide("Anxiety score <=1. Moving on to compulsions.") 

4238 jump_to(CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH) 

4239 else: 

4240 r.decide("Anxiety score >=2. Exploring panic.") 

4241 jump_to(CQ.PANIC_MAND_PAST_MONTH) 

4242 

4243 elif q == CQ.PHOBIAS_TYPE1: 

4244 if v in ( 

4245 V_PHOBIAS_TYPE1_ALONE_PUBLIC_TRANSPORT, 

4246 V_PHOBIAS_TYPE1_FAR_FROM_HOME, 

4247 V_PHOBIAS_TYPE1_CROWDED_SHOPS, 

4248 ): 

4249 r.decide("Phobia type category: agoraphobia.") 

4250 r.phobias_type = PHOBIATYPES_AGORAPHOBIA 

4251 

4252 elif v in ( 

4253 V_PHOBIAS_TYPE1_PUBLIC_SPEAKING_EATING, 

4254 V_PHOBIAS_TYPE1_BEING_WATCHED, 

4255 ): 

4256 r.decide("Phobia type category: social.") 

4257 r.phobias_type = PHOBIATYPES_SOCIAL 

4258 

4259 elif v == V_PHOBIAS_TYPE1_BLOOD: 

4260 r.decide("Phobia type category: blood/injury.") 

4261 r.phobias_type = PHOBIATYPES_BLOOD_INJURY 

4262 

4263 elif v in ( 

4264 V_PHOBIAS_TYPE1_ANIMALS, 

4265 V_PHOBIAS_TYPE1_ENCLOSED_SPACES_HEIGHTS, 

4266 ): 

4267 r.decide( 

4268 "Phobia type category: animals/enclosed spaces/" "heights." 

4269 ) 

4270 r.phobias_type = PHOBIATYPES_ANIMALS_ENCLOSED_HEIGHTS 

4271 

4272 elif v == V_PHOBIAS_TYPE1_OTHER: 

4273 r.decide("Phobia type category: other.") 

4274 r.phobias_type = PHOBIATYPES_OTHER 

4275 

4276 else: 

4277 pass 

4278 

4279 elif q == CQ.PHOBIAS1_DAYS_PAST_WEEK: 

4280 if v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4281 r.decide( 

4282 "Phobic anxiety on >=4 days in past week. " 

4283 "Incrementing phobias_score." 

4284 ) 

4285 r.phobias_score += 1 

4286 

4287 elif q == CQ.PHOBIAS2_PHYSICAL_SYMPTOMS: 

4288 if self.answer_is_yes(q, v): 

4289 r.decide( 

4290 "Physical symptoms during phobic anxiety in past " 

4291 "week. Incrementing phobias_score." 

4292 ) 

4293 r.phobias_score += 1 

4294 

4295 elif q == CQ.PHOBIAS3_AVOIDANCE: 

4296 if self.answer_is_no(q, v): # no avoidance in past week 

4297 if r.anxiety <= 1 and r.phobias_score == 0: 

4298 r.decide( 

4299 "No avoidance in past week; " 

4300 "anxiety <= 1 and phobias_score == 0. " 

4301 "Finishing anxiety section." 

4302 ) 

4303 jump_to(CQ.ANX_OUTRO) 

4304 else: 

4305 r.decide( 

4306 "No avoidance in past week; " 

4307 "anxiety >= 2 or phobias_score >= 1. " 

4308 "Moving to panic section." 

4309 ) 

4310 jump_to(CQ.PANIC_MAND_PAST_MONTH) 

4311 elif self.answer_is_yes(q, v): 

4312 r.decide("Setting phobic_avoidance.") 

4313 r.phobic_avoidance = True 

4314 

4315 elif q == CQ.PHOBIAS4_AVOIDANCE_DAYS_PAST_WEEK: 

4316 if v == V_DAYS_IN_PAST_WEEK_1_TO_3: 

4317 r.decide( 

4318 "Phobic avoidance on 1-3 days in past week. " 

4319 "Incrementing phobias_score." 

4320 ) 

4321 r.phobias_score += 1 

4322 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4323 r.decide( 

4324 "Phobic avoidance on >=4 days in past week. " 

4325 "Adding 2 to phobias_score." 

4326 ) 

4327 r.phobias_score += 2 

4328 if ( 

4329 r.anxiety <= 1 

4330 and self.int_value_for_question(CQ.PHOBIAS1_DAYS_PAST_WEEK) 

4331 == V_DAYS_IN_PAST_WEEK_0 

4332 ): 

4333 r.decide( 

4334 "anxiety <= 1 and no phobic anxiety in past week. " 

4335 "Finishing anxiety section." 

4336 ) 

4337 jump_to(CQ.ANX_OUTRO) 

4338 

4339 elif q == CQ.PHOBIAS_DUR: 

4340 pass 

4341 

4342 elif q == CQ.PANIC_MAND_PAST_MONTH: 

4343 if v == V_NSO_NO: 

4344 r.decide( 

4345 "No panic in the past month. Finishing anxiety " "section." 

4346 ) 

4347 jump_to(CQ.ANX_OUTRO) 

4348 

4349 elif q == CQ.PANIC1_NUM_PAST_WEEK: 

4350 if v == V_PANIC1_N_PANICS_PAST_WEEK_0: 

4351 r.decide("No panic in past week. Finishing anxiety section.") 

4352 jump_to(CQ.ANX_OUTRO) 

4353 elif v == V_PANIC1_N_PANICS_PAST_WEEK_1: 

4354 r.decide("One panic in past week. Incrementing panic.") 

4355 r.panic += 1 

4356 elif v == V_PANIC1_N_PANICS_PAST_WEEK_GT_1: 

4357 r.decide( 

4358 "More than one panic in past week. Adding 2 to panic." 

4359 ) 

4360 r.panic += 2 

4361 

4362 elif q == CQ.PANIC2_HOW_UNPLEASANT: 

4363 if v >= V_HOW_UNPLEASANT_UNPLEASANT: 

4364 r.decide( 

4365 "Panic 'unpleasant' or worse in past week. " 

4366 "Incrementing panic." 

4367 ) 

4368 r.panic += 1 

4369 

4370 elif q == CQ.PANIC3_PANIC_GE_10_MIN: 

4371 if v == V_PANIC3_WORST_GE_10_MIN: 

4372 r.decide( 

4373 "Worst panic in past week lasted >=10 min. " 

4374 "Incrementing panic." 

4375 ) 

4376 r.panic += 1 

4377 

4378 elif q == CQ.PANIC4_RAPID_ONSET: 

4379 if self.answer_is_yes(q, v): 

4380 r.decide( 

4381 "Rapid onset of panic symptoms. " 

4382 "Setting panic_rapid_onset." 

4383 ) 

4384 r.panic_rapid_onset = True 

4385 

4386 elif q == CQ.PANSYM: 

4387 # Multi-way answer. All are scored 1=no, 2=yes. 

4388 n_panic_symptoms = 0 

4389 for panic_fn in PANIC_SYMPTOM_FIELDNAMES: 

4390 panic_symptom = getattr(self, panic_fn) or 0 # force to int 

4391 yes_present = panic_symptom == 2 

4392 if yes_present: 

4393 n_panic_symptoms += 1 

4394 r.decide( 

4395 f"{n_panic_symptoms} out of " 

4396 f"{NUM_PANIC_SYMPTOMS} specific panic symptoms endorsed." 

4397 ) 

4398 # The next bit was coded in PANIC5, but lives more naturally here: 

4399 if self.answer_is_no(CQ.ANX_PHOBIA1_SPECIFIC_PAST_MONTH): 

4400 jump_to(CQ.PANIC_DUR) 

4401 

4402 elif q == CQ.PANIC5_ALWAYS_SPECIFIC_TRIGGER: 

4403 pass 

4404 

4405 elif q == CQ.PANIC_DUR: 

4406 pass 

4407 

4408 elif q == CQ.ANX_OUTRO: 

4409 pass 

4410 

4411 # -------------------------------------------------------------------- 

4412 # Compulsions and obsessions 

4413 # -------------------------------------------------------------------- 

4414 

4415 elif q == CQ.COMP_MAND1_COMPULSIONS_PAST_MONTH: 

4416 if v == V_NSO_NO: 

4417 r.decide("No compulsions in past month. Moving to obsessions.") 

4418 jump_to(CQ.OBSESS_MAND1_OBSESSIONS_PAST_MONTH) 

4419 

4420 elif q == CQ.COMP1_DAYS_PAST_WEEK: 

4421 if v == V_DAYS_IN_PAST_WEEK_0: 

4422 r.decide("No compulsions in past week. Moving to obesssions.") 

4423 jump_to(CQ.OBSESS_MAND1_OBSESSIONS_PAST_MONTH) 

4424 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4425 r.decide( 

4426 "Obsessions on >=4 days in past week. " 

4427 "Incrementing compulsions." 

4428 ) 

4429 r.compulsions += 1 

4430 

4431 elif q == CQ.COMP2_TRIED_TO_STOP: 

4432 if self.answer_is_yes(q, v): 

4433 r.decide( 

4434 "Attempts to stop compulsions in past week. " 

4435 "Setting compulsions_tried_to_stop. " 

4436 "Incrementing compulsions." 

4437 ) 

4438 r.compulsions_tried_to_stop = True 

4439 r.compulsions += 1 

4440 

4441 elif q == CQ.COMP3_UPSETTING: 

4442 if self.answer_is_yes(q, v): 

4443 r.decide( 

4444 "Compulsions upsetting/annoying. " 

4445 "Incrementing compulsions." 

4446 ) 

4447 r.compulsions += 1 

4448 

4449 elif q == CQ.COMP4_MAX_N_REPETITIONS: 

4450 if v == V_COMP4_MAX_N_REPEATS_GE_3: 

4451 r.decide("At worst, >=3 repeats. Incrementing compulsions.") 

4452 r.compulsions += 1 

4453 

4454 elif q == CQ.COMP_DUR: 

4455 if v >= V_DURATION_2W_6M: 

4456 r.decide( 

4457 "Compulsions for >=2 weeks. " 

4458 "Setting compulsions_at_least_2_weeks." 

4459 ) 

4460 r.compulsions_at_least_2_weeks = True 

4461 

4462 elif q == CQ.OBSESS_MAND1_OBSESSIONS_PAST_MONTH: 

4463 if v == V_NSO_NO: 

4464 r.decide("No obsessions in past month. Moving on.") 

4465 jump_to(r.get_final_page()) 

4466 

4467 elif q == CQ.OBSESS_MAND2_SAME_THOUGHTS_OR_GENERAL: 

4468 if v == V_OBSESS_MAND1_GENERAL_WORRIES: 

4469 r.decide( 

4470 "Worrying about something in general, not the same " 

4471 "thoughts over and over again. Moving on." 

4472 ) 

4473 jump_to(r.get_final_page()) 

4474 

4475 elif q == CQ.OBSESS1_DAYS_PAST_WEEK: 

4476 if v == V_DAYS_IN_PAST_WEEK_0: 

4477 r.decide("No obsessions in past week. Moving on.") 

4478 jump_to(r.get_final_page()) 

4479 elif v == V_DAYS_IN_PAST_WEEK_4_OR_MORE: 

4480 r.decide( 

4481 "Obsessions on >=4 days in past week. " 

4482 "Incrementing obsessions." 

4483 ) 

4484 r.obsessions += 1 

4485 

4486 elif q == CQ.OBSESS2_TRIED_TO_STOP: 

4487 if self.answer_is_yes(q, v): 

4488 r.decide( 

4489 "Tried to stop obsessional thoughts in past week. " 

4490 "Setting obsessions_tried_to_stop. " 

4491 "Incrementing obsessions." 

4492 ) 

4493 r.obsessions_tried_to_stop = True 

4494 r.obsessions += 1 

4495 

4496 elif q == CQ.OBSESS3_UPSETTING: 

4497 if self.answer_is_yes(q, v): 

4498 r.decide( 

4499 "Obsessions upsetting/annoying in past week. " 

4500 "Incrementing obsessions." 

4501 ) 

4502 r.obsessions += 1 

4503 

4504 elif q == CQ.OBSESS4_MAX_DURATION: 

4505 if v == V_OBSESS4_GE_15_MIN: 

4506 r.decide( 

4507 "Obsessions lasting >=15 min in past week. " 

4508 "Incrementing obsessions." 

4509 ) 

4510 r.obsessions += 1 

4511 

4512 elif q == CQ.OBSESS_DUR: 

4513 if v >= V_DURATION_2W_6M: 

4514 r.decide( 

4515 "Obsessions for >=2 weeks. " 

4516 "Setting obsessions_at_least_2_weeks." 

4517 ) 

4518 r.obsessions_at_least_2_weeks = True 

4519 

4520 # -------------------------------------------------------------------- 

4521 # End 

4522 # -------------------------------------------------------------------- 

4523 

4524 elif q == CQ.OVERALL1_INFO_ONLY: 

4525 pass 

4526 

4527 elif q == CQ.OVERALL2_IMPACT_PAST_WEEK: 

4528 if self.answered(q, v): 

4529 r.functional_impairment = v - 1 

4530 r.decide( 

4531 f"Setting functional_impairment to " 

4532 f"{r.functional_impairment}" 

4533 ) 

4534 

4535 elif q == CQ.THANKS_FINISHED: 

4536 pass 

4537 

4538 elif q == CQ.END_MARKER: # this is not a page 

4539 # we've reached the end; no point thinking further 

4540 return CQ.END_MARKER 

4541 

4542 else: 

4543 pass 

4544 

4545 if next_q == -1: 

4546 # Nothing has expressed an overriding preference, so increment... 

4547 next_q = enum_to_int(q) + 1 

4548 

4549 return int_to_enum(next_q) 

4550 

4551 def get_result(self, record_decisions: bool = False) -> CisrResult: 

4552 # internal_q = CQ.START_MARKER 

4553 internal_q = CQ.APPETITE1_LOSS_PAST_MONTH # skip the preamble etc. 

4554 result = CisrResult(record_decisions) 

4555 while (not result.incomplete) and internal_q != CQ.END_MARKER: 

4556 internal_q = self.next_q(internal_q, result) 

4557 # loop until we reach the end or have incomplete data 

4558 result.finalize() 

4559 return result 

4560 

4561 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]: 

4562 res = self.get_result() 

4563 if res.incomplete: 

4564 return CTV_INCOMPLETE 

4565 return [ 

4566 CtvInfo( 

4567 content=( 

4568 f"Probable primary diagnosis: " 

4569 f"{bold(res.diagnosis_1_name())} " 

4570 f"({res.diagnosis_1_icd10_code()})" 

4571 ) 

4572 ), 

4573 CtvInfo( 

4574 content=( 

4575 f"Probable secondary diagnosis: " 

4576 f"{bold(res.diagnosis_2_name())} " 

4577 f"({res.diagnosis_2_icd10_code()})" 

4578 ) 

4579 ), 

4580 CtvInfo( 

4581 content=( 

4582 f"CIS-R suicide intent: " 

4583 f"{self.get_suicide_intent(req, res, with_warning=False)}" 

4584 ) 

4585 ), 

4586 ] 

4587 

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

4589 result = self.get_result() 

4590 return self.standard_task_summary_fields() + [ 

4591 # Diagnoses 

4592 SummaryElement( 

4593 name="diagnosis_1_code", 

4594 coltype=Integer(), 

4595 value=result.diagnosis_1, 

4596 comment="Probable primary diagnosis (CIS-R code)", 

4597 ), 

4598 SummaryElement( 

4599 name="diagnosis_1_text", 

4600 coltype=UnicodeText(), 

4601 value=result.diagnosis_1_name(), 

4602 comment="Probable primary diagnosis (text)", 

4603 ), 

4604 SummaryElement( 

4605 name="diagnosis_1_icd10", 

4606 coltype=UnicodeText(), 

4607 value=result.diagnosis_1_icd10_code(), 

4608 comment="Probable primary diagnosis (ICD-10 code/codes)", 

4609 ), 

4610 SummaryElement( 

4611 name="diagnosis_2_code", 

4612 coltype=Integer(), 

4613 value=result.diagnosis_2, 

4614 comment="Probable secondary diagnosis (CIS-R code)", 

4615 ), 

4616 SummaryElement( 

4617 name="diagnosis_2_text", 

4618 coltype=UnicodeText(), 

4619 value=result.diagnosis_2_icd10_code(), 

4620 comment="Probable secondary diagnosis (text)", 

4621 ), 

4622 SummaryElement( 

4623 name="diagnosis_2_icd10", 

4624 coltype=UnicodeText(), 

4625 value=result.diagnosis_2_icd10_code(), 

4626 comment="Probable secondary diagnosis (ICD-10 code/codes)", 

4627 ), 

4628 # Suicidality/doctell: directly encoded in data 

4629 # Total score 

4630 SummaryElement( 

4631 name="score_total", 

4632 coltype=Integer(), 

4633 value=result.get_score(), 

4634 comment=f"CIS-R total score (max. {MAX_TOTAL})", 

4635 ), 

4636 # Functional impairment: directly encoded in data 

4637 # Subscores 

4638 SummaryElement( 

4639 name="score_somatic_symptoms", 

4640 coltype=Integer(), 

4641 value=result.somatic_symptoms, 

4642 comment="Score: somatic symptoms (max. 4)", 

4643 ), 

4644 SummaryElement( 

4645 name="score_hypochondria", 

4646 coltype=Integer(), 

4647 value=result.hypochondria, 

4648 comment="Score: worry over physical health (max. 4)", 

4649 ), 

4650 SummaryElement( 

4651 name="score_irritability", 

4652 coltype=Integer(), 

4653 value=result.irritability, 

4654 comment="Score: irritability (max. 4)", 

4655 ), 

4656 SummaryElement( 

4657 name="score_concentration_poor", 

4658 coltype=Integer(), 

4659 value=result.concentration_poor, 

4660 comment="Score: poor concentration (max. 4)", 

4661 ), 

4662 SummaryElement( 

4663 name="score_fatigue", 

4664 coltype=Integer(), 

4665 value=result.fatigue, 

4666 comment="Score: fatigue (max. 4)", 

4667 ), 

4668 SummaryElement( 

4669 name="score_sleep_problems", 

4670 coltype=Integer(), 

4671 value=result.sleep_problems, 

4672 comment="Score: sleep problems (max. 4)", 

4673 ), 

4674 SummaryElement( 

4675 name="score_depression", 

4676 coltype=Integer(), 

4677 value=result.depression, 

4678 comment="Score: depression (max. 4)", 

4679 ), 

4680 SummaryElement( 

4681 name="score_depressive_thoughts", 

4682 coltype=Integer(), 

4683 value=result.depressive_thoughts, 

4684 comment="Score: depressive ideas (max. 5)", 

4685 ), 

4686 SummaryElement( 

4687 name="score_phobias", 

4688 coltype=Integer(), 

4689 value=result.phobias_score, 

4690 comment="Score: phobias (max. 4)", 

4691 ), 

4692 SummaryElement( 

4693 name="score_worry", 

4694 coltype=Integer(), 

4695 value=result.worry, 

4696 comment="Score: worry (max. 4)", 

4697 ), 

4698 SummaryElement( 

4699 name="score_anxiety", 

4700 coltype=Integer(), 

4701 value=result.anxiety, 

4702 comment="Score: anxiety (max. 4)", 

4703 ), 

4704 SummaryElement( 

4705 name="score_panic", 

4706 coltype=Integer(), 

4707 value=result.panic, 

4708 comment="Score: panic (max. 4)", 

4709 ), 

4710 SummaryElement( 

4711 name="score_compulsions", 

4712 coltype=Integer(), 

4713 value=result.compulsions, 

4714 comment="Score: compulsions (max. 4)", 

4715 ), 

4716 SummaryElement( 

4717 name="score_obsessions", 

4718 coltype=Integer(), 

4719 value=result.obsessions, 

4720 comment="Score: obsessions (max. 4)", 

4721 ), 

4722 # Other 

4723 SummaryElement( 

4724 name="sleep_change", 

4725 coltype=Integer(), 

4726 value=result.sleep_change, 

4727 comment=DESC_SLEEP_CHANGE, 

4728 ), 

4729 SummaryElement( 

4730 name="weight_change", 

4731 coltype=Integer(), 

4732 value=result.weight_change, 

4733 comment=DESC_WEIGHT_CHANGE, 

4734 ), 

4735 SummaryElement( 

4736 name="depcrit1_score", 

4737 coltype=Integer(), 

4738 value=result.depr_crit_1_mood_anhedonia_energy, 

4739 comment=DESC_DEPCRIT1, 

4740 ), 

4741 SummaryElement( 

4742 name="depcrit2_score", 

4743 coltype=Integer(), 

4744 value=result.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui, 

4745 comment=DESC_DEPCRIT2, 

4746 ), 

4747 SummaryElement( 

4748 name="depcrit3_score", 

4749 coltype=Integer(), 

4750 value=result.depr_crit_3_somatic_synd, 

4751 comment=DESC_DEPCRIT3, 

4752 ), 

4753 SummaryElement( 

4754 name="depcrit3_met_somatic_syndrome", 

4755 coltype=Boolean(), 

4756 value=result.has_somatic_syndrome(), 

4757 comment=DESC_DEPCRIT3_MET, 

4758 ), 

4759 SummaryElement( 

4760 name="neurasthenia_score", 

4761 coltype=Integer(), 

4762 value=result.neurasthenia, 

4763 comment=DESC_NEURASTHENIA_SCORE, 

4764 ), 

4765 # Disorder flags 

4766 SummaryElement( 

4767 name="disorder_ocd", 

4768 coltype=Boolean(), 

4769 value=result.obsessive_compulsive_disorder, 

4770 comment=DISORDER_OCD, 

4771 ), 

4772 SummaryElement( 

4773 name="disorder_depression_mild", 

4774 coltype=Boolean(), 

4775 value=result.depression_mild, 

4776 comment=DISORDER_DEPR_MILD, 

4777 ), 

4778 SummaryElement( 

4779 name="disorder_depression_moderate", 

4780 coltype=Boolean(), 

4781 value=result.depression_moderate, 

4782 comment=DISORDER_DEPR_MOD, 

4783 ), 

4784 SummaryElement( 

4785 name="disorder_depression_severe", 

4786 coltype=Boolean(), 

4787 value=result.depression_severe, 

4788 comment=DISORDER_DEPR_SEV, 

4789 ), 

4790 SummaryElement( 

4791 name="disorder_cfs", 

4792 coltype=Boolean(), 

4793 value=result.chronic_fatigue_syndrome, 

4794 comment=DISORDER_CFS, 

4795 ), 

4796 SummaryElement( 

4797 name="disorder_gad", 

4798 coltype=Boolean(), 

4799 value=result.generalized_anxiety_disorder, 

4800 comment=DISORDER_GAD, 

4801 ), 

4802 SummaryElement( 

4803 name="disorder_agoraphobia", 

4804 coltype=Boolean(), 

4805 value=result.phobia_agoraphobia, 

4806 comment=DISORDER_AGORAPHOBIA, 

4807 ), 

4808 SummaryElement( 

4809 name="disorder_social_phobia", 

4810 coltype=Boolean(), 

4811 value=result.phobia_social, 

4812 comment=DISORDER_SOCIAL_PHOBIA, 

4813 ), 

4814 SummaryElement( 

4815 name="disorder_specific_phobia", 

4816 coltype=Boolean(), 

4817 value=result.phobia_specific, 

4818 comment=DISORDER_SPECIFIC_PHOBIA, 

4819 ), 

4820 SummaryElement( 

4821 name="disorder_panic_disorder", 

4822 coltype=Boolean(), 

4823 value=result.panic_disorder, 

4824 comment=DISORDER_PANIC, 

4825 ), 

4826 ] 

4827 

4828 def is_complete(self) -> bool: 

4829 result = self.get_result() 

4830 return not result.incomplete 

4831 

4832 def diagnosis_name(self, req: CamcopsRequest, diagnosis_code: int) -> str: 

4833 xstring_name = f"diag_{diagnosis_code}_desc" 

4834 return self.wxstring(req, xstring_name) 

4835 

4836 def diagnosis_reason( 

4837 self, req: CamcopsRequest, diagnosis_code: int 

4838 ) -> str: 

4839 xstring_name = f"diag_{diagnosis_code}_explan" 

4840 return self.wxstring(req, xstring_name) 

4841 

4842 def get_suicide_intent( 

4843 self, 

4844 req: CamcopsRequest, 

4845 result: CisrResult, 

4846 with_warning: bool = True, 

4847 ) -> str: 

4848 if result.incomplete: 

4849 html = "TASK INCOMPLETE. SO FAR: " 

4850 else: 

4851 html = "" 

4852 html += self.wxstring(req, f"suicid_{result.suicidality}") 

4853 if ( 

4854 with_warning 

4855 and result.suicidality >= SUICIDE_INTENT_LIFE_NOT_WORTH_LIVING 

4856 ): 

4857 html += f" <i>{self.wxstring(req, 'suicid_instruction')}</i>" 

4858 if result.suicidality != SUICIDE_INTENT_NONE: 

4859 html = bold(html) 

4860 return html 

4861 

4862 def get_doctell(self, req: CamcopsRequest) -> str: 

4863 if self.doctor is None: 

4864 return "" 

4865 return self.xstring(req, f"doctell_{self.doctor}") 

4866 # ... xstring() as may use HTML 

4867 

4868 def get_sleep_change(self, req: CamcopsRequest, result: CisrResult) -> str: 

4869 if result.sleep_change == SLEEPCHANGE_NONE: 

4870 return "" 

4871 return self.wxstring(req, f"sleepch_{result.sleep_change}") 

4872 

4873 def get_weight_change( 

4874 self, req: CamcopsRequest, result: CisrResult 

4875 ) -> str: 

4876 if result.weight_change in ( 

4877 WTCHANGE_NONE_OR_APPETITE_INCREASE, 

4878 WTCHANGE_APPETITE_LOSS, 

4879 ): 

4880 return "" 

4881 return self.wxstring(req, f"wtchange_{result.weight_change}") 

4882 

4883 def get_impairment(self, req: CamcopsRequest, result: CisrResult) -> str: 

4884 return self.wxstring(req, f"impair_{result.functional_impairment}") 

4885 

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

4887 # Iterate only once, for efficiency, so don't use get_result(). 

4888 

4889 def qa_row(q_: CisrQuestion, qtext: str, a_: Optional[str]) -> str: 

4890 return tr(f"{q_.value}. {qtext}", answer(a_)) 

4891 

4892 def max_text(maxval: int) -> str: 

4893 return f" (max. {maxval})" 

4894 

4895 demographics_html_list = [] # type: List[str] 

4896 question_html_list = [] # type: List[str] 

4897 q = CQ.ETHNIC # type: CisrQuestion 

4898 result = CisrResult(record_decisions=True) 

4899 while (not result.incomplete) and q != CQ.END_MARKER: 

4900 # Iterate until we get to the end or the result declares itself 

4901 # incomplete. 

4902 # noinspection PyTypeChecker 

4903 target_list = ( 

4904 demographics_html_list 

4905 if q.value < CQ.HEALTH_WELLBEING.value 

4906 else question_html_list 

4907 ) 

4908 if q in QUESTIONS_PROMPT_ONLY: 

4909 question = self.wxstring(req, QUESTIONS_PROMPT_ONLY[q]) 

4910 target_list.append(qa_row(q, question, NOT_APPLICABLE_TEXT)) 

4911 elif q == CQ.PANSYM: # special! 

4912 target_list.append( 

4913 qa_row( 

4914 q, 

4915 self.wxstring(req, "pansym_q_prefix"), 

4916 NOT_APPLICABLE_TEXT, 

4917 ) 

4918 ) 

4919 for fieldname in PANIC_SYMPTOM_FIELDNAMES: 

4920 question = self.wxstring(req, fieldname + "_q") 

4921 value = getattr(self, fieldname) 

4922 a = get_yes_no_none( 

4923 req, value == 2 if value is not None else None 

4924 ) 

4925 target_list.append(qa_row(q, question, a)) 

4926 else: 

4927 fieldname = fieldname_for_q(q) 

4928 assert fieldname, f"No fieldname for question {q}" 

4929 question = self.wxstring(req, fieldname + "_q") 

4930 a = self.get_textual_answer(req, q) 

4931 target_list.append(qa_row(q, question, a)) 

4932 

4933 q = self.next_q(q, result) 

4934 # loop until we reach the end or have incomplete data 

4935 result.finalize() 

4936 

4937 is_complete = not result.incomplete 

4938 is_complete_html_td = """{}<b>{}</b></td>""".format( 

4939 "<td>" 

4940 if is_complete 

4941 else f"""<td class="{CssClass.INCOMPLETE}">""", 

4942 get_yes_no(req, is_complete), 

4943 ) 

4944 

4945 summary_rows = [ 

4946 subheading_spanning_two_columns("Diagnoses"), 

4947 tr( 

4948 "Probable primary diagnosis", 

4949 ( 

4950 bold(self.diagnosis_name(req, result.diagnosis_1)) 

4951 + ( 

4952 f" ({result.diagnosis_1_icd10_code()})" 

4953 if result.has_diagnosis_1() 

4954 else "" 

4955 ) 

4956 ), 

4957 ), 

4958 tr( 

4959 italic("... summary of reasons/description"), 

4960 italic(self.diagnosis_reason(req, result.diagnosis_1)), 

4961 ), 

4962 tr( 

4963 "Probable secondary diagnosis", 

4964 ( 

4965 bold(self.diagnosis_name(req, result.diagnosis_2)) 

4966 + ( 

4967 f" ({result.diagnosis_2_icd10_code()})" 

4968 if result.has_diagnosis_2() 

4969 else "" 

4970 ) 

4971 ), 

4972 ), 

4973 tr( 

4974 italic("... summary of reasons/description"), 

4975 italic(self.diagnosis_reason(req, result.diagnosis_2)), 

4976 ), 

4977 subheading_spanning_two_columns("Suicidality"), 

4978 tr( 

4979 td(self.wxstring(req, "suicid_heading")), 

4980 td(self.get_suicide_intent(req, result)), 

4981 literal=True, 

4982 ), 

4983 tr("... spoken to doctor?", self.get_doctell(req)), 

4984 subheading_spanning_two_columns("Total score/overall impairment"), 

4985 tr( 

4986 f"CIS-R total score (max. {MAX_TOTAL}) <sup>[1]</sup>", 

4987 result.get_score(), 

4988 ), 

4989 tr( 

4990 self.wxstring(req, "impair_label"), 

4991 self.get_impairment(req, result), 

4992 ), 

4993 subheading_spanning_two_columns( 

4994 "Subscores contributing to total " "<sup>[2]</sup>" 

4995 ), 

4996 tr( 

4997 self.wxstring(req, "somatic_label") + max_text(MAX_SOMATIC), 

4998 result.somatic_symptoms, 

4999 ), 

5000 tr( 

5001 self.wxstring(req, "hypo_label") + max_text(MAX_HYPO), 

5002 result.hypochondria, 

5003 ), 

5004 tr( 

5005 self.wxstring(req, "irrit_label") + max_text(MAX_IRRIT), 

5006 result.irritability, 

5007 ), 

5008 tr( 

5009 self.wxstring(req, "conc_label") + max_text(MAX_CONC), 

5010 result.concentration_poor, 

5011 ), 

5012 tr( 

5013 self.wxstring(req, "fatigue_label") + max_text(MAX_FATIGUE), 

5014 result.fatigue, 

5015 ), 

5016 tr( 

5017 self.wxstring(req, "sleep_label") + max_text(MAX_SLEEP), 

5018 result.sleep_problems, 

5019 ), 

5020 tr( 

5021 self.wxstring(req, "depr_label") + max_text(MAX_DEPR), 

5022 result.depression, 

5023 ), 

5024 tr( 

5025 self.wxstring(req, "depthts_label") + max_text(MAX_DEPTHTS), 

5026 result.depressive_thoughts, 

5027 ), 

5028 tr( 

5029 self.wxstring(req, "phobias_label") + max_text(MAX_PHOBIAS), 

5030 result.phobias_score, 

5031 ), 

5032 tr( 

5033 self.wxstring(req, "worry_label") + max_text(MAX_WORRY), 

5034 result.worry, 

5035 ), 

5036 tr( 

5037 self.wxstring(req, "anx_label") + max_text(MAX_ANX), 

5038 result.anxiety, 

5039 ), 

5040 tr( 

5041 self.wxstring(req, "panic_label") + max_text(MAX_PANIC), 

5042 result.panic, 

5043 ), 

5044 tr( 

5045 self.wxstring(req, "comp_label") + max_text(MAX_COMP), 

5046 result.compulsions, 

5047 ), 

5048 tr( 

5049 self.wxstring(req, "obsess_label") + max_text(MAX_OBSESS), 

5050 result.obsessions, 

5051 ), 

5052 subheading_spanning_two_columns("Other"), 

5053 tr("Sleep change", self.get_sleep_change(req, result)), 

5054 tr("Weight change", self.get_weight_change(req, result)), 

5055 tr(DESC_DEPCRIT1, result.depr_crit_1_mood_anhedonia_energy), 

5056 tr(DESC_DEPCRIT2, result.depr_crit_2_app_cnc_slp_mtr_glt_wth_sui), 

5057 tr(DESC_DEPCRIT3, result.depr_crit_3_somatic_synd), 

5058 tr(DESC_DEPCRIT3_MET, result.has_somatic_syndrome()), # RNC 

5059 tr(DESC_NEURASTHENIA_SCORE, result.neurasthenia), 

5060 subheading_spanning_two_columns("Disorder flags"), 

5061 tr(DISORDER_OCD, result.obsessive_compulsive_disorder), 

5062 tr(DISORDER_DEPR_MILD, result.depression_mild), 

5063 tr(DISORDER_DEPR_MOD, result.depression_moderate), 

5064 tr(DISORDER_DEPR_SEV, result.depression_severe), 

5065 tr(DISORDER_CFS, result.chronic_fatigue_syndrome), 

5066 tr(DISORDER_GAD, result.generalized_anxiety_disorder), 

5067 tr(DISORDER_AGORAPHOBIA, result.phobia_agoraphobia), 

5068 tr(DISORDER_SOCIAL_PHOBIA, result.phobia_social), 

5069 tr(DISORDER_SPECIFIC_PHOBIA, result.phobia_specific), 

5070 tr(DISORDER_PANIC, result.panic_disorder), 

5071 ] 

5072 

5073 return f""" 

5074 <div class="{CssClass.HEADING}">{self.wxstring(req, "results_1")}</div> 

5075 <div>{self.wxstring(req, "results_2")}</div> 

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

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

5078 <tr> 

5079 <td width="50%">Completed?</td> 

5080 {is_complete_html_td} 

5081 </tr> 

5082 {"".join(summary_rows)} 

5083 </table> 

5084 </div> 

5085 

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

5087 [1] {self.wxstring(req, "score_note")} 

5088 [2] {self.wxstring(req, "symptom_score_note")} 

5089 </div> 

5090 

5091 <div class="{CssClass.HEADING}"> 

5092 Preamble/demographics (not contributing to diagnosis) 

5093 </div> 

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

5095 <tr> 

5096 <th width="75%">Page</th> 

5097 <th width="25%">Answer</td> 

5098 </tr> 

5099 {"".join(demographics_html_list)} 

5100 </table> 

5101 

5102 <div class="{CssClass.HEADING}"> 

5103 Data considered by algorithm (may be a subset of all data if 

5104 subject revised answers) 

5105 </div> 

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

5107 <tr> 

5108 <th width="75%">Page</th> 

5109 <th width="25%">Answer</td> 

5110 </tr> 

5111 {"".join(question_html_list)} 

5112 </table> 

5113 

5114 <div class="{CssClass.HEADING}">Decisions</div> 

5115 <pre>{"<br>".join(ws.webify("‣ " + x) for x in result.decisions)}</pre> 

5116 

5117 <div class="{CssClass.COPYRIGHT}"> 

5118 • Original papers: 

5119 

5120 ▶ Lewis G, Pelosi AJ, Aray R, Dunn G (1992). 

5121 Measuring psychiatric disorder in the community: a standardized 

5122 assessment for use by lay interviewers. 

5123 Psychological Medicine 22: 465-486. PubMed ID 

5124 <a href="https://www.ncbi.nlm.nih.gov/pubmed/1615114">1615114</a>. 

5125 

5126 ▶ Lewis G (1994). 

5127 Assessing psychiatric disorder with a human interviewer or a 

5128 computer. 

5129 J Epidemiol Community Health 48: 207-210. PubMed ID 

5130 <a href="https://www.ncbi.nlm.nih.gov/pubmed/8189180">8189180</a>. 

5131 

5132 • Source/copyright: Glyn Lewis. 

5133 

5134 ▶ The task itself is not in the reference publications, so 

5135 copyright presumed to rest with the authors (not the journals). 

5136 

5137 ▶ “There are no copyright issues with the CISR so please adapt 

5138 it for use.” — Prof. Glyn Lewis, personal communication to 

5139 Rudolf Cardinal, 27 Oct 2017. 

5140 </div> 

5141 """ # noqa