edsl 0.1.15__py3-none-any.whl → 0.1.40__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. edsl/Base.py +348 -38
  2. edsl/BaseDiff.py +260 -0
  3. edsl/TemplateLoader.py +24 -0
  4. edsl/__init__.py +45 -10
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +842 -144
  7. edsl/agents/AgentList.py +521 -25
  8. edsl/agents/Invigilator.py +250 -374
  9. edsl/agents/InvigilatorBase.py +257 -0
  10. edsl/agents/PromptConstructor.py +272 -0
  11. edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
  12. edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
  13. edsl/agents/descriptors.py +43 -13
  14. edsl/agents/prompt_helpers.py +129 -0
  15. edsl/agents/question_option_processor.py +172 -0
  16. edsl/auto/AutoStudy.py +130 -0
  17. edsl/auto/StageBase.py +243 -0
  18. edsl/auto/StageGenerateSurvey.py +178 -0
  19. edsl/auto/StageLabelQuestions.py +125 -0
  20. edsl/auto/StagePersona.py +61 -0
  21. edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
  22. edsl/auto/StagePersonaDimensionValues.py +74 -0
  23. edsl/auto/StagePersonaDimensions.py +69 -0
  24. edsl/auto/StageQuestions.py +74 -0
  25. edsl/auto/SurveyCreatorPipeline.py +21 -0
  26. edsl/auto/utilities.py +218 -0
  27. edsl/base/Base.py +279 -0
  28. edsl/config.py +115 -113
  29. edsl/conversation/Conversation.py +290 -0
  30. edsl/conversation/car_buying.py +59 -0
  31. edsl/conversation/chips.py +95 -0
  32. edsl/conversation/mug_negotiation.py +81 -0
  33. edsl/conversation/next_speaker_utilities.py +93 -0
  34. edsl/coop/CoopFunctionsMixin.py +15 -0
  35. edsl/coop/ExpectedParrotKeyHandler.py +125 -0
  36. edsl/coop/PriceFetcher.py +54 -0
  37. edsl/coop/__init__.py +1 -0
  38. edsl/coop/coop.py +1029 -134
  39. edsl/coop/utils.py +131 -0
  40. edsl/data/Cache.py +560 -89
  41. edsl/data/CacheEntry.py +230 -0
  42. edsl/data/CacheHandler.py +168 -0
  43. edsl/data/RemoteCacheSync.py +186 -0
  44. edsl/data/SQLiteDict.py +292 -0
  45. edsl/data/__init__.py +5 -3
  46. edsl/data/orm.py +6 -33
  47. edsl/data_transfer_models.py +74 -27
  48. edsl/enums.py +165 -8
  49. edsl/exceptions/BaseException.py +21 -0
  50. edsl/exceptions/__init__.py +52 -46
  51. edsl/exceptions/agents.py +33 -15
  52. edsl/exceptions/cache.py +5 -0
  53. edsl/exceptions/coop.py +8 -0
  54. edsl/exceptions/general.py +34 -0
  55. edsl/exceptions/inference_services.py +5 -0
  56. edsl/exceptions/jobs.py +15 -0
  57. edsl/exceptions/language_models.py +46 -1
  58. edsl/exceptions/questions.py +80 -5
  59. edsl/exceptions/results.py +16 -5
  60. edsl/exceptions/scenarios.py +29 -0
  61. edsl/exceptions/surveys.py +13 -10
  62. edsl/inference_services/AnthropicService.py +106 -0
  63. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  64. edsl/inference_services/AvailableModelFetcher.py +215 -0
  65. edsl/inference_services/AwsBedrock.py +118 -0
  66. edsl/inference_services/AzureAI.py +215 -0
  67. edsl/inference_services/DeepInfraService.py +18 -0
  68. edsl/inference_services/GoogleService.py +143 -0
  69. edsl/inference_services/GroqService.py +20 -0
  70. edsl/inference_services/InferenceServiceABC.py +80 -0
  71. edsl/inference_services/InferenceServicesCollection.py +138 -0
  72. edsl/inference_services/MistralAIService.py +120 -0
  73. edsl/inference_services/OllamaService.py +18 -0
  74. edsl/inference_services/OpenAIService.py +236 -0
  75. edsl/inference_services/PerplexityService.py +160 -0
  76. edsl/inference_services/ServiceAvailability.py +135 -0
  77. edsl/inference_services/TestService.py +90 -0
  78. edsl/inference_services/TogetherAIService.py +172 -0
  79. edsl/inference_services/data_structures.py +134 -0
  80. edsl/inference_services/models_available_cache.py +118 -0
  81. edsl/inference_services/rate_limits_cache.py +25 -0
  82. edsl/inference_services/registry.py +41 -0
  83. edsl/inference_services/write_available.py +10 -0
  84. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  85. edsl/jobs/Answers.py +21 -20
  86. edsl/jobs/FetchInvigilator.py +47 -0
  87. edsl/jobs/InterviewTaskManager.py +98 -0
  88. edsl/jobs/InterviewsConstructor.py +50 -0
  89. edsl/jobs/Jobs.py +684 -206
  90. edsl/jobs/JobsChecks.py +172 -0
  91. edsl/jobs/JobsComponentConstructor.py +189 -0
  92. edsl/jobs/JobsPrompts.py +270 -0
  93. edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
  94. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  95. edsl/jobs/RequestTokenEstimator.py +30 -0
  96. edsl/jobs/async_interview_runner.py +138 -0
  97. edsl/jobs/buckets/BucketCollection.py +104 -0
  98. edsl/jobs/buckets/ModelBuckets.py +65 -0
  99. edsl/jobs/buckets/TokenBucket.py +283 -0
  100. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  101. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  102. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  103. edsl/jobs/data_structures.py +120 -0
  104. edsl/jobs/decorators.py +35 -0
  105. edsl/jobs/interviews/Interview.py +392 -0
  106. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
  107. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
  108. edsl/jobs/interviews/InterviewStatistic.py +63 -0
  109. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
  110. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
  111. edsl/jobs/interviews/InterviewStatusLog.py +92 -0
  112. edsl/jobs/interviews/ReportErrors.py +66 -0
  113. edsl/jobs/interviews/interview_status_enum.py +9 -0
  114. edsl/jobs/jobs_status_enums.py +9 -0
  115. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  116. edsl/jobs/results_exceptions_handler.py +98 -0
  117. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -110
  118. edsl/jobs/runners/JobsRunnerStatus.py +298 -0
  119. edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
  120. edsl/jobs/tasks/TaskCreators.py +64 -0
  121. edsl/jobs/tasks/TaskHistory.py +470 -0
  122. edsl/jobs/tasks/TaskStatusLog.py +23 -0
  123. edsl/jobs/tasks/task_status_enum.py +161 -0
  124. edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
  125. edsl/jobs/tokens/TokenUsage.py +34 -0
  126. edsl/language_models/ComputeCost.py +63 -0
  127. edsl/language_models/LanguageModel.py +507 -386
  128. edsl/language_models/ModelList.py +164 -0
  129. edsl/language_models/PriceManager.py +127 -0
  130. edsl/language_models/RawResponseHandler.py +106 -0
  131. edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
  132. edsl/language_models/__init__.py +1 -8
  133. edsl/language_models/fake_openai_call.py +15 -0
  134. edsl/language_models/fake_openai_service.py +61 -0
  135. edsl/language_models/key_management/KeyLookup.py +63 -0
  136. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  137. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  138. edsl/language_models/key_management/__init__.py +0 -0
  139. edsl/language_models/key_management/models.py +131 -0
  140. edsl/language_models/model.py +256 -0
  141. edsl/language_models/repair.py +109 -41
  142. edsl/language_models/utilities.py +65 -0
  143. edsl/notebooks/Notebook.py +263 -0
  144. edsl/notebooks/NotebookToLaTeX.py +142 -0
  145. edsl/notebooks/__init__.py +1 -0
  146. edsl/prompts/Prompt.py +222 -93
  147. edsl/prompts/__init__.py +1 -1
  148. edsl/questions/ExceptionExplainer.py +77 -0
  149. edsl/questions/HTMLQuestion.py +103 -0
  150. edsl/questions/QuestionBase.py +518 -0
  151. edsl/questions/QuestionBasePromptsMixin.py +221 -0
  152. edsl/questions/QuestionBudget.py +164 -67
  153. edsl/questions/QuestionCheckBox.py +281 -62
  154. edsl/questions/QuestionDict.py +343 -0
  155. edsl/questions/QuestionExtract.py +136 -50
  156. edsl/questions/QuestionFreeText.py +79 -55
  157. edsl/questions/QuestionFunctional.py +138 -41
  158. edsl/questions/QuestionList.py +184 -57
  159. edsl/questions/QuestionMatrix.py +265 -0
  160. edsl/questions/QuestionMultipleChoice.py +293 -69
  161. edsl/questions/QuestionNumerical.py +109 -56
  162. edsl/questions/QuestionRank.py +244 -49
  163. edsl/questions/Quick.py +41 -0
  164. edsl/questions/SimpleAskMixin.py +74 -0
  165. edsl/questions/__init__.py +9 -6
  166. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
  167. edsl/questions/compose_questions.py +13 -7
  168. edsl/questions/data_structures.py +20 -0
  169. edsl/questions/decorators.py +21 -0
  170. edsl/questions/derived/QuestionLikertFive.py +28 -26
  171. edsl/questions/derived/QuestionLinearScale.py +41 -28
  172. edsl/questions/derived/QuestionTopK.py +34 -26
  173. edsl/questions/derived/QuestionYesNo.py +40 -27
  174. edsl/questions/descriptors.py +228 -74
  175. edsl/questions/loop_processor.py +149 -0
  176. edsl/questions/prompt_templates/question_budget.jinja +13 -0
  177. edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
  178. edsl/questions/prompt_templates/question_extract.jinja +11 -0
  179. edsl/questions/prompt_templates/question_free_text.jinja +3 -0
  180. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
  181. edsl/questions/prompt_templates/question_list.jinja +17 -0
  182. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
  183. edsl/questions/prompt_templates/question_numerical.jinja +37 -0
  184. edsl/questions/question_base_gen_mixin.py +168 -0
  185. edsl/questions/question_registry.py +130 -46
  186. edsl/questions/register_questions_meta.py +71 -0
  187. edsl/questions/response_validator_abc.py +188 -0
  188. edsl/questions/response_validator_factory.py +34 -0
  189. edsl/questions/settings.py +5 -2
  190. edsl/questions/templates/__init__.py +0 -0
  191. edsl/questions/templates/budget/__init__.py +0 -0
  192. edsl/questions/templates/budget/answering_instructions.jinja +7 -0
  193. edsl/questions/templates/budget/question_presentation.jinja +7 -0
  194. edsl/questions/templates/checkbox/__init__.py +0 -0
  195. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
  196. edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
  197. edsl/questions/templates/dict/__init__.py +0 -0
  198. edsl/questions/templates/dict/answering_instructions.jinja +21 -0
  199. edsl/questions/templates/dict/question_presentation.jinja +1 -0
  200. edsl/questions/templates/extract/__init__.py +0 -0
  201. edsl/questions/templates/extract/answering_instructions.jinja +7 -0
  202. edsl/questions/templates/extract/question_presentation.jinja +1 -0
  203. edsl/questions/templates/free_text/__init__.py +0 -0
  204. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  205. edsl/questions/templates/free_text/question_presentation.jinja +1 -0
  206. edsl/questions/templates/likert_five/__init__.py +0 -0
  207. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
  208. edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
  209. edsl/questions/templates/linear_scale/__init__.py +0 -0
  210. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
  211. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
  212. edsl/questions/templates/list/__init__.py +0 -0
  213. edsl/questions/templates/list/answering_instructions.jinja +4 -0
  214. edsl/questions/templates/list/question_presentation.jinja +5 -0
  215. edsl/questions/templates/matrix/__init__.py +1 -0
  216. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  217. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  218. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  219. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
  220. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  221. edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
  222. edsl/questions/templates/numerical/__init__.py +0 -0
  223. edsl/questions/templates/numerical/answering_instructions.jinja +7 -0
  224. edsl/questions/templates/numerical/question_presentation.jinja +7 -0
  225. edsl/questions/templates/rank/__init__.py +0 -0
  226. edsl/questions/templates/rank/answering_instructions.jinja +11 -0
  227. edsl/questions/templates/rank/question_presentation.jinja +15 -0
  228. edsl/questions/templates/top_k/__init__.py +0 -0
  229. edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
  230. edsl/questions/templates/top_k/question_presentation.jinja +22 -0
  231. edsl/questions/templates/yes_no/__init__.py +0 -0
  232. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
  233. edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
  234. edsl/results/CSSParameterizer.py +108 -0
  235. edsl/results/Dataset.py +550 -19
  236. edsl/results/DatasetExportMixin.py +594 -0
  237. edsl/results/DatasetTree.py +295 -0
  238. edsl/results/MarkdownToDocx.py +122 -0
  239. edsl/results/MarkdownToPDF.py +111 -0
  240. edsl/results/Result.py +477 -173
  241. edsl/results/Results.py +987 -269
  242. edsl/results/ResultsExportMixin.py +28 -125
  243. edsl/results/ResultsGGMixin.py +83 -15
  244. edsl/results/TableDisplay.py +125 -0
  245. edsl/results/TextEditor.py +50 -0
  246. edsl/results/__init__.py +1 -1
  247. edsl/results/file_exports.py +252 -0
  248. edsl/results/results_fetch_mixin.py +33 -0
  249. edsl/results/results_selector.py +145 -0
  250. edsl/results/results_tools_mixin.py +98 -0
  251. edsl/results/smart_objects.py +96 -0
  252. edsl/results/table_data_class.py +12 -0
  253. edsl/results/table_display.css +78 -0
  254. edsl/results/table_renderers.py +118 -0
  255. edsl/results/tree_explore.py +115 -0
  256. edsl/scenarios/ConstructDownloadLink.py +109 -0
  257. edsl/scenarios/DocumentChunker.py +102 -0
  258. edsl/scenarios/DocxScenario.py +16 -0
  259. edsl/scenarios/FileStore.py +543 -0
  260. edsl/scenarios/PdfExtractor.py +40 -0
  261. edsl/scenarios/Scenario.py +431 -62
  262. edsl/scenarios/ScenarioHtmlMixin.py +65 -0
  263. edsl/scenarios/ScenarioList.py +1415 -45
  264. edsl/scenarios/ScenarioListExportMixin.py +45 -0
  265. edsl/scenarios/ScenarioListPdfMixin.py +239 -0
  266. edsl/scenarios/__init__.py +2 -0
  267. edsl/scenarios/directory_scanner.py +96 -0
  268. edsl/scenarios/file_methods.py +85 -0
  269. edsl/scenarios/handlers/__init__.py +13 -0
  270. edsl/scenarios/handlers/csv.py +49 -0
  271. edsl/scenarios/handlers/docx.py +76 -0
  272. edsl/scenarios/handlers/html.py +37 -0
  273. edsl/scenarios/handlers/json.py +111 -0
  274. edsl/scenarios/handlers/latex.py +5 -0
  275. edsl/scenarios/handlers/md.py +51 -0
  276. edsl/scenarios/handlers/pdf.py +68 -0
  277. edsl/scenarios/handlers/png.py +39 -0
  278. edsl/scenarios/handlers/pptx.py +105 -0
  279. edsl/scenarios/handlers/py.py +294 -0
  280. edsl/scenarios/handlers/sql.py +313 -0
  281. edsl/scenarios/handlers/sqlite.py +149 -0
  282. edsl/scenarios/handlers/txt.py +33 -0
  283. edsl/scenarios/scenario_join.py +131 -0
  284. edsl/scenarios/scenario_selector.py +156 -0
  285. edsl/shared.py +1 -0
  286. edsl/study/ObjectEntry.py +173 -0
  287. edsl/study/ProofOfWork.py +113 -0
  288. edsl/study/SnapShot.py +80 -0
  289. edsl/study/Study.py +521 -0
  290. edsl/study/__init__.py +4 -0
  291. edsl/surveys/ConstructDAG.py +92 -0
  292. edsl/surveys/DAG.py +92 -11
  293. edsl/surveys/EditSurvey.py +221 -0
  294. edsl/surveys/InstructionHandler.py +100 -0
  295. edsl/surveys/Memory.py +9 -4
  296. edsl/surveys/MemoryManagement.py +72 -0
  297. edsl/surveys/MemoryPlan.py +156 -35
  298. edsl/surveys/Rule.py +221 -74
  299. edsl/surveys/RuleCollection.py +241 -61
  300. edsl/surveys/RuleManager.py +172 -0
  301. edsl/surveys/Simulator.py +75 -0
  302. edsl/surveys/Survey.py +1079 -339
  303. edsl/surveys/SurveyCSS.py +273 -0
  304. edsl/surveys/SurveyExportMixin.py +235 -40
  305. edsl/surveys/SurveyFlowVisualization.py +181 -0
  306. edsl/surveys/SurveyQualtricsImport.py +284 -0
  307. edsl/surveys/SurveyToApp.py +141 -0
  308. edsl/surveys/__init__.py +4 -2
  309. edsl/surveys/base.py +19 -3
  310. edsl/surveys/descriptors.py +17 -6
  311. edsl/surveys/instructions/ChangeInstruction.py +48 -0
  312. edsl/surveys/instructions/Instruction.py +56 -0
  313. edsl/surveys/instructions/InstructionCollection.py +82 -0
  314. edsl/surveys/instructions/__init__.py +0 -0
  315. edsl/templates/error_reporting/base.html +24 -0
  316. edsl/templates/error_reporting/exceptions_by_model.html +35 -0
  317. edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
  318. edsl/templates/error_reporting/exceptions_by_type.html +17 -0
  319. edsl/templates/error_reporting/interview_details.html +116 -0
  320. edsl/templates/error_reporting/interviews.html +19 -0
  321. edsl/templates/error_reporting/overview.html +5 -0
  322. edsl/templates/error_reporting/performance_plot.html +2 -0
  323. edsl/templates/error_reporting/report.css +74 -0
  324. edsl/templates/error_reporting/report.html +118 -0
  325. edsl/templates/error_reporting/report.js +25 -0
  326. edsl/tools/__init__.py +1 -0
  327. edsl/tools/clusters.py +192 -0
  328. edsl/tools/embeddings.py +27 -0
  329. edsl/tools/embeddings_plotting.py +118 -0
  330. edsl/tools/plotting.py +112 -0
  331. edsl/tools/summarize.py +18 -0
  332. edsl/utilities/PrettyList.py +56 -0
  333. edsl/utilities/SystemInfo.py +5 -0
  334. edsl/utilities/__init__.py +21 -20
  335. edsl/utilities/ast_utilities.py +3 -0
  336. edsl/utilities/data/Registry.py +2 -0
  337. edsl/utilities/decorators.py +41 -0
  338. edsl/utilities/gcp_bucket/__init__.py +0 -0
  339. edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
  340. edsl/utilities/interface.py +310 -60
  341. edsl/utilities/is_notebook.py +18 -0
  342. edsl/utilities/is_valid_variable_name.py +11 -0
  343. edsl/utilities/naming_utilities.py +263 -0
  344. edsl/utilities/remove_edsl_version.py +24 -0
  345. edsl/utilities/repair_functions.py +28 -0
  346. edsl/utilities/restricted_python.py +70 -0
  347. edsl/utilities/utilities.py +203 -13
  348. edsl-0.1.40.dist-info/METADATA +111 -0
  349. edsl-0.1.40.dist-info/RECORD +362 -0
  350. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
  351. edsl/agents/AgentListExportMixin.py +0 -24
  352. edsl/coop/old.py +0 -31
  353. edsl/data/Database.py +0 -141
  354. edsl/data/crud.py +0 -121
  355. edsl/jobs/Interview.py +0 -435
  356. edsl/jobs/JobsRunner.py +0 -63
  357. edsl/jobs/JobsRunnerStatusMixin.py +0 -115
  358. edsl/jobs/base.py +0 -47
  359. edsl/jobs/buckets.py +0 -178
  360. edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
  361. edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
  362. edsl/jobs/task_management.py +0 -215
  363. edsl/jobs/token_tracking.py +0 -78
  364. edsl/language_models/DeepInfra.py +0 -69
  365. edsl/language_models/OpenAI.py +0 -98
  366. edsl/language_models/model_interfaces/GeminiPro.py +0 -66
  367. edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
  368. edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
  369. edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
  370. edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
  371. edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
  372. edsl/language_models/registry.py +0 -81
  373. edsl/language_models/schemas.py +0 -15
  374. edsl/language_models/unused/ReplicateBase.py +0 -83
  375. edsl/prompts/QuestionInstructionsBase.py +0 -6
  376. edsl/prompts/library/agent_instructions.py +0 -29
  377. edsl/prompts/library/agent_persona.py +0 -17
  378. edsl/prompts/library/question_budget.py +0 -26
  379. edsl/prompts/library/question_checkbox.py +0 -32
  380. edsl/prompts/library/question_extract.py +0 -19
  381. edsl/prompts/library/question_freetext.py +0 -14
  382. edsl/prompts/library/question_linear_scale.py +0 -20
  383. edsl/prompts/library/question_list.py +0 -22
  384. edsl/prompts/library/question_multiple_choice.py +0 -44
  385. edsl/prompts/library/question_numerical.py +0 -31
  386. edsl/prompts/library/question_rank.py +0 -21
  387. edsl/prompts/prompt_config.py +0 -33
  388. edsl/prompts/registry.py +0 -185
  389. edsl/questions/Question.py +0 -240
  390. edsl/report/InputOutputDataTypes.py +0 -134
  391. edsl/report/RegressionMixin.py +0 -28
  392. edsl/report/ReportOutputs.py +0 -1228
  393. edsl/report/ResultsFetchMixin.py +0 -106
  394. edsl/report/ResultsOutputMixin.py +0 -14
  395. edsl/report/demo.ipynb +0 -645
  396. edsl/results/ResultsDBMixin.py +0 -184
  397. edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
  398. edsl/trackers/Tracker.py +0 -91
  399. edsl/trackers/TrackerAPI.py +0 -196
  400. edsl/trackers/TrackerTasks.py +0 -70
  401. edsl/utilities/pastebin.py +0 -141
  402. edsl-0.1.15.dist-info/METADATA +0 -69
  403. edsl-0.1.15.dist-info/RECORD +0 -142
  404. /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
  405. /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
  406. /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
  407. {edsl-0.1.15.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -0,0 +1,74 @@
1
+ import math
2
+
3
+
4
+ def logprob_to_prob(logprob):
5
+ if logprob is None:
6
+ return None
7
+ return math.exp(logprob)
8
+
9
+
10
+ def format_output(data):
11
+ from rich.table import Table
12
+ from rich.console import Console
13
+
14
+ content = data["choices"][0]["logprobs"]["content"]
15
+ table = Table(show_header=True, header_style="bold magenta")
16
+
17
+ # First pass to determine the maximum number of top tokens
18
+ max_tokens = max(len(item["top_logprobs"]) for item in content)
19
+
20
+ # Set up the table columns
21
+ table.add_column("Token", style="bold")
22
+ for i in range(max_tokens):
23
+ table.add_column(f"Top Token {i+1}")
24
+
25
+ for item in content:
26
+ token = item["token"].strip()
27
+ top_tokens = [
28
+ (top["token"].strip(), logprob_to_prob(top.get("logprob")))
29
+ for top in item["top_logprobs"]
30
+ ]
31
+
32
+ # Row data starts with the main token
33
+ row = [token]
34
+
35
+ # Add each top token with coloring based on probability
36
+ for token, probability in top_tokens:
37
+ if probability is not None:
38
+ # Assign color based on probability value
39
+ if probability > 0.5:
40
+ color = "green"
41
+ elif probability > 0.2:
42
+ color = "yellow"
43
+ else:
44
+ color = "red"
45
+ formatted_token = f"[{color}]{token} ({probability:.2f})[/]"
46
+ else:
47
+ formatted_token = f"{token} (N/A)"
48
+ row.append(formatted_token)
49
+
50
+ # Ensure row has enough columns
51
+ while len(row) < max_tokens + 1:
52
+ row.append("")
53
+
54
+ table.add_row(*row)
55
+
56
+ console = Console()
57
+ console.print(table)
58
+
59
+
60
+ class SimpleAskMixin:
61
+ # def simple_ask(self, question: QuestionBase, system_prompt = "You are a helpful agent pretending to be a human.", top_logprobs = 2):
62
+
63
+ def simple_ask(
64
+ self,
65
+ model=None,
66
+ system_prompt="You are a helpful agent pretending to be a human. Do not break character",
67
+ top_logprobs=4,
68
+ ):
69
+ from edsl.language_models.model import Model
70
+
71
+ if model is None:
72
+ model = Model()
73
+ response = model.simple_ask(self, system_prompt, top_logprobs)
74
+ return format_output(response)
@@ -1,25 +1,28 @@
1
1
  # Schemas
2
2
  from edsl.questions.settings import Settings
3
+ from edsl.questions.register_questions_meta import RegisterQuestionsMeta
3
4
 
4
5
  # Base Class
5
- from edsl.questions.Question import Question
6
+ from edsl.questions.QuestionBase import QuestionBase
6
7
 
7
8
  # Core Questions
8
- from edsl.questions.QuestionBudget import QuestionBudget
9
9
  from edsl.questions.QuestionCheckBox import QuestionCheckBox
10
10
  from edsl.questions.QuestionExtract import QuestionExtract
11
11
  from edsl.questions.QuestionFreeText import QuestionFreeText
12
12
  from edsl.questions.QuestionFunctional import QuestionFunctional
13
13
  from edsl.questions.QuestionList import QuestionList
14
+ from edsl.questions.QuestionMatrix import QuestionMatrix
15
+ from edsl.questions.QuestionDict import QuestionDict
14
16
  from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
15
17
  from edsl.questions.QuestionNumerical import QuestionNumerical
18
+ from edsl.questions.QuestionBudget import QuestionBudget
16
19
  from edsl.questions.QuestionRank import QuestionRank
17
20
 
18
- # Questions derived from core questions
21
+ # # # Questions derived from core questions
19
22
  from edsl.questions.derived.QuestionLikertFive import QuestionLikertFive
20
23
  from edsl.questions.derived.QuestionLinearScale import QuestionLinearScale
21
- from edsl.questions.derived.QuestionTopK import QuestionTopK
22
24
  from edsl.questions.derived.QuestionYesNo import QuestionYesNo
25
+ from edsl.questions.derived.QuestionTopK import QuestionTopK
23
26
 
24
- # Compose Questions
25
- from edsl.questions.compose_questions import compose_questions
27
+ # # Compose Questions
28
+ # from edsl.questions.compose_questions import compose_questions
@@ -1,24 +1,42 @@
1
+ """Mixin with validators for LLM answers to questions."""
2
+
1
3
  import re
2
4
  from typing import Any, Type, Union
3
- from edsl.exceptions import (
5
+ from edsl.exceptions.questions import (
4
6
  QuestionAnswerValidationError,
5
7
  )
6
8
 
7
9
 
8
10
  class AnswerValidatorMixin:
9
11
  """
10
- Mixin with validators for LLM answers to questions
12
+ Mixin with validators for LLM answers to questions.
13
+
11
14
  - Template validation: validators for the entire answer object format
12
15
  - Value validation: validators for specific values
13
16
  - Question specific validation: validators for specific question types
14
17
  """
15
18
 
19
+ def failing_job(self):
20
+ from edsl import Agent
21
+
22
+ a = Agent()
23
+
24
+ def f(self, question, scenario):
25
+ return []
26
+
27
+ a.add_direct_question_answering_method(f, validate_response=True)
28
+ from edsl import QuestionNumerical
29
+
30
+ q = QuestionNumerical.example()
31
+ results = q.by(a).run()
32
+ return results
33
+
16
34
  #####################
17
35
  # TEMPLATE VALIDATION
18
36
  #####################
19
- def validate_answer_template_basic(self, answer: Any) -> None:
20
- """
21
- Checks that the answer (i) is a dictionary (ii) has an 'answer' key
37
+ def _validate_answer_template_basic(self, answer: Any) -> None:
38
+ """Check that the answer (i) is a dictionary (ii) has an 'answer' key.
39
+
22
40
  - E.g., both {'answer': 1} and {'answer': {'a': 1}, 'other_key'=[1,2,3]} are valid
23
41
  """
24
42
  if not isinstance(answer, dict):
@@ -33,21 +51,25 @@ class AnswerValidatorMixin:
33
51
  #####################
34
52
  # VALUE VALIDATION
35
53
  #####################
36
- def validate_answer_key_value(
54
+ def _validate_answer_key_value(
37
55
  self, answer: dict[str, Any], key: str, of_type: Type
38
56
  ) -> None:
39
- """Checks that the value of a key is of the specified type"""
57
+ """Check that the value of a key is of the specified type."""
40
58
  if not isinstance(answer.get(key), of_type):
41
59
  raise QuestionAnswerValidationError(
42
60
  f"""Answer key '{key}' must be of type {of_type.__name__};
43
61
  (got {answer.get(key)}) which is of type {type(answer.get(key))}."""
44
62
  )
45
63
 
46
- def validate_answer_key_value_numeric(
64
+ def _validate_answer_key_value_numeric(
47
65
  self, answer: dict[str, Any], key: str
48
66
  ) -> None:
49
- """Checks that the value of a key is numeric (int or float)"""
67
+ """Check that the value is numeric (int or float).
68
+ Can also deal with strings that contain commas and other characters.
69
+
70
+ """
50
71
  value = answer.get(key)
72
+ initial_value = value
51
73
  if type(value) == str:
52
74
  value = value.replace(",", "")
53
75
  value = "".join(re.findall(r"[-+]?\d*\.\d+|\d+", value))
@@ -59,7 +81,7 @@ class AnswerValidatorMixin:
59
81
  value = float(value)
60
82
  except ValueError:
61
83
  raise QuestionAnswerValidationError(
62
- f"Answer should be numerical (int or float)."
84
+ f"Answer should be numerical (int or float). Got '{initial_value}'"
63
85
  )
64
86
  return None
65
87
  elif type(value) == int or type(value) == float:
@@ -72,9 +94,10 @@ class AnswerValidatorMixin:
72
94
  #####################
73
95
  # QUESTION SPECIFIC VALIDATION
74
96
  #####################
75
- def validate_answer_budget(self, answer: dict[str, Any]) -> None:
76
- """
77
- QuestionBudget-specific answer validation. Checks that answer["answer"]:
97
+ def _validate_answer_budget(self, answer: dict[str, Any]) -> None:
98
+ """Validate QuestionBudget-specific answer.
99
+
100
+ Check that answer["answer"]:
78
101
  - has keys that are in the range of the number of options
79
102
  - has values that are non-negative integers
80
103
  - has values that sum to `budget_sum`
@@ -95,17 +118,21 @@ class AnswerValidatorMixin:
95
118
  )
96
119
  if any([int(key) not in acceptable_answer_keys for key in answer.keys()]):
97
120
  raise QuestionAnswerValidationError(
98
- f"Budget keys must be in {acceptable_answer_keys}, but got {answer_keys}"
121
+ f"Budget keys must be in {acceptable_answer_keys}, but got {answer_keys}."
99
122
  )
100
123
  if acceptable_answer_keys != answer_keys:
101
124
  missing_keys = acceptable_answer_keys - answer_keys
102
125
  raise QuestionAnswerValidationError(
103
- f"All but keys must be represented in the answer. Missing: {missing_keys}"
126
+ f"All but keys must be represented in the answer. Missing: {missing_keys}."
104
127
  )
105
128
 
106
- def validate_answer_checkbox(self, answer: dict[str, Union[str, int]]) -> None:
107
- """
108
- QuestionCheckbox-specific answer validation. Checks that answer["answer"]:
129
+ def _validate_answer_checkbox(self, answer: dict[str, Union[str, int]]) -> None:
130
+ """Validate QuestionCheckbox-specific answer.
131
+
132
+ :param answer: Answer to validate
133
+
134
+
135
+ Check that answer["answer"]:
109
136
  - has elements that are strings, bytes-like objects or real numbers evaluating to integers
110
137
  - has elements that are in the range of the number of options
111
138
  - has at least `min_selections` elements, if provided
@@ -126,16 +153,17 @@ class AnswerValidatorMixin:
126
153
  )
127
154
  if self.min_selections is not None and len(answer_codes) < self.min_selections:
128
155
  raise QuestionAnswerValidationError(
129
- f"Answer {answer_codes} has fewer than {self.min_selections} options selected."
156
+ f"Answer codes, {answer_codes}, has fewer than {self.min_selections} options selected."
130
157
  )
131
158
  if self.max_selections is not None and len(answer_codes) > self.max_selections:
132
159
  raise QuestionAnswerValidationError(
133
- f"Answer {answer_codes} has more than {self.max_selections} options selected."
160
+ f"Answer codes, {answer_codes}, has more than {self.max_selections} options selected."
134
161
  )
135
162
 
136
- def validate_answer_extract(self, answer: dict[str, Any]) -> None:
137
- """
138
- QuestionExtract-specific answer validation. Checks that answer["answer"]:
163
+ def _validate_answer_extract(self, answer: dict[str, Any]) -> None:
164
+ """Validate QuestionExtract-specific answer.
165
+
166
+ Check that answer["answer"]:
139
167
  - does not have keys that are not in the answer template
140
168
  - has all keys that are in the answer template
141
169
  """
@@ -143,16 +171,17 @@ class AnswerValidatorMixin:
143
171
  acceptable_answer_keys = set(self.answer_template.keys())
144
172
  if any([key not in acceptable_answer_keys for key in value.keys()]):
145
173
  raise QuestionAnswerValidationError(
146
- f"Answer keys must be in {acceptable_answer_keys}, but got {value.keys()}"
174
+ f"Answer keys must be in {acceptable_answer_keys}, but got {value.keys()}."
147
175
  )
148
176
  if any([key not in value.keys() for key in acceptable_answer_keys]):
149
177
  raise QuestionAnswerValidationError(
150
- f"Answer must have all keys in {acceptable_answer_keys}, but got {value.keys()}"
178
+ f"Answer must have all keys in {acceptable_answer_keys}, but got {value.keys()}."
151
179
  )
152
180
 
153
- def validate_answer_list(self, answer: dict[str, Union[list, str]]) -> None:
154
- """
155
- QuestionList-specific answer validation. Checks that answer["answer"]:
181
+ def _validate_answer_list(self, answer: dict[str, Union[list, str]]) -> None:
182
+ """Validate QuestionList-specific answer.
183
+
184
+ Check that answer["answer"]:
156
185
  - is not empty, if `allow_nonresponse` is False
157
186
  - has no more than `max_list_items` elements
158
187
  - has no empty strings
@@ -177,13 +206,19 @@ class AnswerValidatorMixin:
177
206
  f"Answer cannot contain empty strings, but got {value}."
178
207
  )
179
208
 
180
- def validate_answer_numerical(self, answer: dict) -> None:
181
- """
182
- QuestionNumerical-specific answer validation. Checks that answer["answer"]:
209
+ def _validate_answer_numerical(self, answer: dict) -> None:
210
+ """Validate QuestionNumerical-specific answer.
211
+
212
+ Check that answer["answer"]:
183
213
  - is not less than `min_value`
184
214
  - is not greater than `max_value`
185
215
  """
186
- value = float(answer.get("answer"))
216
+ try:
217
+ value = float(answer.get("answer"))
218
+ except ValueError:
219
+ raise QuestionAnswerValidationError(
220
+ f"Answer must real number or convertible to a real number (got {answer.get('answer')})."
221
+ )
187
222
  if self.min_value is not None and value < self.min_value:
188
223
  raise QuestionAnswerValidationError(
189
224
  f"Value {value} is less than {self.min_value}"
@@ -194,11 +229,12 @@ class AnswerValidatorMixin:
194
229
  )
195
230
  return value
196
231
 
197
- def validate_answer_multiple_choice(
232
+ def _validate_answer_multiple_choice(
198
233
  self, answer: dict[str, Union[str, int]]
199
234
  ) -> None:
200
- """
201
- QuestionMultipleChoice-specific answer validation. Checks that answer["answer"]:
235
+ """Validate QuestionMultipleChoice-specific answer.
236
+
237
+ Check that answer["answer"]:
202
238
  - is a string, bytes-like object or real number
203
239
  - is a non-negative integer
204
240
  - is in the range of the number of options
@@ -218,9 +254,10 @@ class AnswerValidatorMixin:
218
254
  f"Answer code {value} must be in {list(range(len(self.question_options)))}."
219
255
  )
220
256
 
221
- def validate_answer_rank(self, answer: dict[str, Union[str, int]]) -> None:
222
- """
223
- QuestionRank-specific answer validation. Checks that answer["answer"]:
257
+ def _validate_answer_rank(self, answer: dict[str, Union[str, int]]) -> None:
258
+ """Validate QuestionRank-specific answer.
259
+
260
+ Check that answer["answer"]:
224
261
  - contains only integers
225
262
  - contains only integers in the range of the number of options
226
263
  - has the correct number of elements
@@ -246,3 +283,81 @@ class AnswerValidatorMixin:
246
283
  raise QuestionAnswerValidationError(
247
284
  f"Rank answer {value}, but exactly {self.num_selections} selections required."
248
285
  )
286
+
287
+ def _validate_answer_matrix(self, answer: dict[str, Any]) -> None:
288
+ """Validate QuestionMatrix-specific answer.
289
+
290
+ Check that answer["answer"]:
291
+ - is a dictionary
292
+ - has all required question_items as keys
293
+ - has values that are valid options from question_options
294
+ - has the correct number of responses (one per item)
295
+ """
296
+ value = answer.get("answer")
297
+
298
+ # Check that answer is a dictionary
299
+ if not isinstance(value, dict):
300
+ raise QuestionAnswerValidationError(
301
+ f"Matrix answer must be a dictionary mapping items to responses (got {value})"
302
+ )
303
+
304
+ # Check that all required items are present
305
+ required_items = set(self.question_items)
306
+ provided_items = set(value.keys())
307
+
308
+ if missing_items := (required_items - provided_items):
309
+ raise QuestionAnswerValidationError(
310
+ f"Missing responses for items: {missing_items}"
311
+ )
312
+
313
+ if extra_items := (provided_items - required_items):
314
+ raise QuestionAnswerValidationError(
315
+ f"Unexpected responses for items: {extra_items}"
316
+ )
317
+
318
+ # Check that all responses are valid options
319
+ valid_options = set(self.question_options)
320
+ for item, response in value.items():
321
+ if response not in valid_options:
322
+ raise QuestionAnswerValidationError(
323
+ f"Invalid response '{response}' for item '{item}'. "
324
+ f"Must be one of: {valid_options}"
325
+ )
326
+
327
+ def _validate_answer_dict(self, answer: dict[str, Any]) -> None:
328
+ """Validate QuestionDict-specific answer.
329
+
330
+ Check that answer["answer"]:
331
+ - is a dictionary
332
+ - has all required answer_keys as keys
333
+ """
334
+ value = answer.get("answer")
335
+
336
+ # Check that answer is a dictionary
337
+ if not isinstance(value, dict):
338
+ raise QuestionAnswerValidationError(
339
+ f"Dict answer must be a dictionary mapping values to specified keys (got {value})"
340
+ )
341
+
342
+ # Check that all required answer keys are present
343
+ required_keys = set(self.answer_keys)
344
+ provided_keys = set(value.keys())
345
+
346
+ if missing_keys := (required_keys - provided_keys):
347
+ raise QuestionAnswerValidationError(
348
+ f"Missing required keys: {missing_keys}"
349
+ )
350
+
351
+ if extra_keys := (provided_keys - required_keys):
352
+ raise QuestionAnswerValidationError(
353
+ f"Unexpected keys: {extra_keys}"
354
+ )
355
+
356
+
357
+ if __name__ == "__main__":
358
+ pass
359
+ # import doctest
360
+
361
+ # doctest.testmod(optionflags=doctest.ELLIPSIS)
362
+
363
+ # results = AnswerValidatorMixin().failing_job()
@@ -1,17 +1,20 @@
1
- from edsl.questions import Question, QuestionFunctional
2
- from edsl.agents import Agent
1
+ """Compose two questions where the answer to q1 is used as an input to q2."""
2
+
3
+ from edsl.questions import QuestionFunctional
4
+ from edsl.questions.QuestionBase import QuestionBase
3
5
  from edsl.scenarios.Scenario import Scenario
4
6
 
5
7
 
6
8
  def compose_questions(
7
- q1: Question, q2: Question, question_name: str = None
9
+ q1: QuestionBase, q2: QuestionBase, question_name: str = None
8
10
  ) -> QuestionFunctional:
9
11
  """
10
- Composes two questions. The answer to q1 is used as the input to q2.
12
+ Compose two questions where the answer to q1 is used as an input to q2.
13
+
11
14
  The resulting question is a question that can be used like other questions.
12
- Note:
13
- - One way the same result can be achieved is through q1+q2.
14
- Please see the __add__ method in Question.
15
+ Note that the same result can also be achieved in other ways:
16
+ - Using the `add_targeted_memory(q2, q1)` method in Survey
17
+ - Using the __add__ method in Question
15
18
  """
16
19
  if question_name is None:
17
20
  question_name = f"{q1.question_name}_{q2.question_name}"
@@ -24,7 +27,10 @@ def compose_questions(
24
27
  def combo(
25
28
  scenario: Scenario, agent_traits: dict[str, str] = None
26
29
  ) -> QuestionFunctional:
30
+ """Return the answer to the second question given the answer to the first question."""
27
31
  # get the answer to the first question
32
+ from edsl.agents.Agent import Agent
33
+
28
34
  first_answer = (
29
35
  q1.by(scenario)
30
36
  .by(Agent(traits=agent_traits))
@@ -0,0 +1,20 @@
1
+ from typing import Any, Optional, TypedDict
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class RawEdslAnswerDict(TypedDict):
6
+ answer: Any
7
+ comment: Optional[str]
8
+ generated_tokens: Optional[str]
9
+
10
+
11
+ class BaseResponse(BaseModel):
12
+ answer: Any
13
+ comment: Optional[str] = None
14
+ generated_tokens: Optional[str] = None
15
+
16
+
17
+ class EdslAnswerDict(TypedDict):
18
+ answer: Any
19
+ comment: Optional[str]
20
+ generated_tokens: Optional[str]
@@ -0,0 +1,21 @@
1
+ from typing import Optional, Callable, TypeVar
2
+
3
+ T = TypeVar("T")
4
+
5
+
6
+ def inject_exception(func: Callable[..., T]) -> Callable[..., T]:
7
+ def wrapper(
8
+ cls,
9
+ exception_to_throw: Optional[Exception] = None,
10
+ override_answer: Optional[dict] = None,
11
+ *args,
12
+ **kwargs
13
+ ) -> T:
14
+ base_instance = func(cls, *args, **kwargs)
15
+ if exception_to_throw:
16
+ base_instance.exception_to_throw = exception_to_throw
17
+ if override_answer:
18
+ base_instance.override_answer = override_answer
19
+ return base_instance
20
+
21
+ return wrapper
@@ -2,22 +2,11 @@ from __future__ import annotations
2
2
  from typing import Optional
3
3
  from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
4
4
 
5
+ from edsl.questions.decorators import inject_exception
5
6
 
6
- class QuestionLikertFive(QuestionMultipleChoice):
7
- """
8
- This question asks the user to respond to a statement on a 5-point Likert scale.
9
-
10
- Arguments:
11
- - `question_name` is the name of the question (string)
12
- - `question_text` is the text of the question (string)
13
7
 
14
- Optional arguments:
15
- - `instructions` are the instructions for the question (string). If not provided, the default instructions are used. To view them, run `QuestionLikertFive.default_instructions`
16
- - `question_options` are the options the user should select from (list of strings). If not provided, the default likert options are used. To view them, run `QuestionLikertFive.likert_options`
17
- - `short_names_dict` maps question_options to short names (dictionary mapping strings to strings)
18
-
19
- For an example, see `QuestionLikertFive.example()`
20
- """
8
+ class QuestionLikertFive(QuestionMultipleChoice):
9
+ """This question prompts the agent to respond to a statement on a 5-point Likert scale."""
21
10
 
22
11
  question_type = "likert_five"
23
12
  likert_options: list[str] = [
@@ -27,27 +16,36 @@ class QuestionLikertFive(QuestionMultipleChoice):
27
16
  "Agree",
28
17
  "Strongly agree",
29
18
  ]
30
- # default_instructions = QuestionMultipleChoice.default_instructions
31
19
 
32
20
  def __init__(
33
21
  self,
34
22
  question_name: str,
35
23
  question_text: str,
36
24
  question_options: Optional[list[str]] = likert_options,
37
- short_names_dict: Optional[dict[str, str]] = None,
25
+ answering_instructions: Optional[str] = None,
26
+ question_presentation: Optional[str] = None,
27
+ include_comment: bool = True,
38
28
  ):
29
+ """Initialize the question.
30
+
31
+ :param question_name: The name of the question.
32
+ :param question_text: The text of the question.
33
+ :param question_options: The options the respondent should select from (list of strings). If not provided, the default Likert options are used (['Strongly disagree', 'Disagree', 'Neutral', 'Agree', 'Strongly agree']). To view them, run `QuestionLikertFive.likert_options`.
34
+ """
39
35
  super().__init__(
40
36
  question_name=question_name,
41
37
  question_text=question_text,
42
38
  question_options=question_options,
43
- short_names_dict=short_names_dict,
39
+ use_code=False,
40
+ include_comment=include_comment,
41
+ answering_instructions=answering_instructions,
42
+ question_presentation=question_presentation,
44
43
  )
45
44
 
46
- ################
47
- # Helpful
48
- ################
49
45
  @classmethod
46
+ @inject_exception
50
47
  def example(cls) -> QuestionLikertFive:
48
+ """Return an example question."""
51
49
  return cls(
52
50
  question_name="happy_raining",
53
51
  question_text="I'm only happy when it rains.",
@@ -55,20 +53,24 @@ class QuestionLikertFive(QuestionMultipleChoice):
55
53
 
56
54
 
57
55
  def main():
56
+ """Test QuestionLikertFive."""
58
57
  from edsl.questions.derived.QuestionLikertFive import QuestionLikertFive
59
58
 
60
59
  q = QuestionLikertFive.example()
61
60
  q.question_text
62
61
  q.question_options
63
62
  q.question_name
64
- q.short_names_dict
65
63
  # validate an answer
66
- q.validate_answer({"answer": 0, "comment": "I like custard"})
64
+ q._validate_answer({"answer": 0, "comment": "I like custard"})
67
65
  # translate answer code
68
- q.translate_answer_code_to_answer(0, {})
69
- q.simulate_answer()
70
- q.simulate_answer(human_readable=False)
71
- q.validate_answer(q.simulate_answer(human_readable=False))
66
+ q._translate_answer_code_to_answer(0, {})
67
+ q._simulate_answer()
68
+ q._simulate_answer(human_readable=False)
69
+ q._validate_answer(q._simulate_answer(human_readable=False))
72
70
  # serialization (inherits from Question)
73
71
  q.to_dict()
74
72
  assert q.from_dict(q.to_dict()) == q
73
+
74
+ import doctest
75
+
76
+ doctest.testmod(optionflags=doctest.ELLIPSIS)