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
@@ -1,115 +0,0 @@
1
- from typing import List
2
- import asyncio
3
-
4
- from rich.table import Table
5
- from rich.text import Text
6
- from rich.box import SIMPLE
7
-
8
- from edsl.jobs.token_tracking import TokenPricing
9
-
10
- pricing = {
11
- "gpt-3.5-turbo": TokenPricing(
12
- model_name="gpt-3.5-turbo",
13
- prompt_token_price_per_k=0.0005,
14
- completion_token_price_per_k=0.0015,
15
- ),
16
- "gpt-4-1106-preview": TokenPricing(
17
- model_name="gpt-4",
18
- prompt_token_price_per_k=0.01,
19
- completion_token_price_per_k=0.03,
20
- ),
21
- "test": TokenPricing(
22
- model_name="test",
23
- prompt_token_price_per_k=0.0,
24
- completion_token_price_per_k=0.0,
25
- ),
26
- "gemini_pro": TokenPricing(
27
- model_name="gemini_pro",
28
- prompt_token_price_per_k=0.0,
29
- completion_token_price_per_k=0.0,
30
- ),
31
- "llama-2-13b-chat-hf": TokenPricing(
32
- model_name="llama-2-13b-chat-hf",
33
- prompt_token_price_per_k=0.0,
34
- completion_token_price_per_k=0.0,
35
- ),
36
- "llama-2-70b-chat-hf": TokenPricing(
37
- model_name="llama-2-70b-chat-hf",
38
- prompt_token_price_per_k=0.0,
39
- completion_token_price_per_k=0.0,
40
- ),
41
- "mixtral-8x7B-instruct-v0.1": TokenPricing(
42
- model_name="mixtral-8x7B-instruct-v0.1",
43
- prompt_token_price_per_k=0.0,
44
- completion_token_price_per_k=0.0,
45
- ),
46
- }
47
-
48
-
49
- class ModelStatus:
50
- def __init__(self, model, TPM, RPM):
51
- self.model = model
52
- self.TPM = TPM
53
- self.RPM = RPM
54
-
55
-
56
- from edsl.jobs.token_tracking import InterviewTokenUsage
57
- from edsl.jobs.task_management import InterviewStatusDictionary
58
-
59
- from collections import defaultdict
60
-
61
-
62
- class JobsRunnerStatusMixin:
63
- def _generate_status_table(self, data: List[asyncio.Task], elapsed_time):
64
- models_to_tokens = defaultdict(InterviewTokenUsage)
65
- model_to_status = defaultdict(InterviewStatusDictionary)
66
-
67
- for interview in self.interviews:
68
- model = interview.model
69
- models_to_tokens[model] += interview.token_usage
70
- model_to_status[model] += interview.interview_status
71
-
72
- pct_complete = len(data) / len(self.interviews) * 100
73
- average_time = elapsed_time / len(data) if len(data) > 0 else 0
74
-
75
- table = Table(
76
- title="Job Status",
77
- show_header=True,
78
- header_style="bold magenta",
79
- box=SIMPLE,
80
- )
81
- table.add_column("Key", style="dim", no_wrap=True)
82
- table.add_column("Value")
83
-
84
- # Add rows for each key-value pair
85
- table.add_row(Text("Task status", style="bold red"), "")
86
- table.add_row("Total interviews requested", str(len(self.interviews)))
87
- table.add_row("Completed interviews", str(len(data)))
88
- # table.add_row("Interviews from cache", str(num_from_cache))
89
- table.add_row("Percent complete", f"{pct_complete:.2f}%")
90
- table.add_row("", "")
91
-
92
- # table.add_row(Text("Timing", style = "bold red"), "")
93
- # table.add_row("Elapsed time (seconds)", f"{elapsed_time:.3f}")
94
- # table.add_row("Average time/interview (seconds)", f"{average_time:.3f}")
95
- # table.add_row("", "")
96
-
97
- # table.add_row(Text("Model Queues", style = "bold red"), "")
98
- # for model, num_waiting in waiting_dict.items():
99
- # if model.model not in pricing:
100
- # raise ValueError(f"Model {model.model} not found in pricing")
101
- # prices = pricing[model.model]
102
- # table.add_row(Text(f"{model.model}", style="blue"),"")
103
- # table.add_row(f"-TPM limit (k)", str(model.TPM/1000))
104
- # table.add_row(f"-RPM limit (k)", str(model.RPM/1000))
105
- # table.add_row(f"-Num tasks waiting", str(num_waiting))
106
- # token_usage = models_to_tokens[model]
107
- # for cache_status in ['new_token_usage', 'cached_token_usage']:
108
- # table.add_row(Text(f"{cache_status}", style="bold"), "")
109
- # token_usage = getattr(models_to_tokens[model], cache_status)
110
- # for token_type in ["prompt_tokens", "completion_tokens"]:
111
- # tokens = getattr(token_usage, token_type)
112
- # table.add_row(f"-{token_type}", str(tokens))
113
- # table.add_row("Cost", f"${token_usage.cost(prices):.5f}")
114
-
115
- return table
edsl/jobs/base.py DELETED
@@ -1,47 +0,0 @@
1
- from collections import UserDict
2
- import importlib
3
-
4
- from edsl.jobs.runners.JobsRunnerAsyncio import JobsRunnerAsyncio
5
- from edsl.jobs.runners.JobsRunnerDryRun import JobsRunnerDryRun
6
-
7
- from edsl.exceptions import JobsRunError
8
- from edsl.jobs.JobsRunner import RegisterJobsRunnerMeta
9
-
10
-
11
- class JobsRunnersRegistryDict(UserDict):
12
- def __getitem__(self, key):
13
- try:
14
- return super().__getitem__(key)
15
- except KeyError:
16
- raise JobsRunError(f"JobsRunner '{key}' not found in registry.")
17
-
18
-
19
- registry_data = RegisterJobsRunnerMeta.lookup()
20
- JobsRunnersRegistry = JobsRunnersRegistryDict(registry_data)
21
-
22
-
23
- class JobsRunnerDescriptor:
24
- def validate(self, value: str) -> None:
25
- """Validates the value. If it is invalid, raises an exception. If it is valid, does nothing."""
26
- if value not in JobsRunnersRegistry:
27
- raise ValueError(
28
- f"JobsRunner must be one of {list(JobsRunnersRegistry.keys())}"
29
- )
30
-
31
- def __get__(self, instance, owner):
32
- """"""
33
- if self.name not in instance.__dict__:
34
- return None
35
- else:
36
- return instance.__dict__[self.name]
37
-
38
- def __set__(self, instance, value: str) -> None:
39
- self.validate(value, instance)
40
- instance.__dict__[self.name] = value
41
-
42
- def __set_name__(self, owner, name: str) -> None:
43
- self.name = "_" + name
44
-
45
-
46
- if __name__ == "__main__":
47
- pass
edsl/jobs/buckets.py DELETED
@@ -1,178 +0,0 @@
1
- from typing import Union
2
- import asyncio
3
- import time
4
- from collections import UserDict
5
- from matplotlib import pyplot as plt
6
-
7
-
8
- class TokenBucket:
9
- """This is a token bucket used to respect rate limits to services."""
10
-
11
- def __init__(
12
- self,
13
- *,
14
- bucket_name,
15
- bucket_type: str,
16
- capacity: Union[int, float],
17
- refill_rate: Union[int, float],
18
- ):
19
- self.bucket_name = bucket_name
20
- self.bucket_type = bucket_type
21
- self.capacity = capacity # Maximum number of tokens
22
- self.tokens = capacity # Current number of available tokens
23
- self.refill_rate = refill_rate # Rate at which tokens are refilled
24
- self.last_refill = time.monotonic() # Last refill time
25
-
26
- self.log = []
27
-
28
- def __add__(self, other) -> "TokenBucket":
29
- """Combine two token buckets. The resulting bucket has the minimum capacity and refill rate of the two buckets.
30
- This is useful, for example, if we have two calls to the same model on the same service but have different temperatures.
31
- """
32
- return TokenBucket(
33
- bucket_name=self.bucket_name,
34
- bucket_type=self.bucket_type,
35
- capacity=min(self.capacity, other.capacity),
36
- refil_rate=min(self.refill_rate, other.refill_rate),
37
- )
38
-
39
- def __repr__(self):
40
- return f"TokenBucket(bucket_name={self.bucket_name}, bucket_type='{self.bucket_type}', capacity={self.capacity}, refill_rate={self.refill_rate})"
41
-
42
- def add_tokens(self, tokens: Union[int, float]) -> None:
43
- """Add tokens to the bucket, up to the maximum capacity."""
44
- self.tokens = min(self.capacity, self.tokens + tokens)
45
- self.log.append((time.monotonic(), self.tokens))
46
-
47
- def refill(self) -> None:
48
- """Refill the bucket with new tokens based on elapsed time."""
49
- now = time.monotonic()
50
- elapsed = now - self.last_refill
51
- refill_amount = elapsed * self.refill_rate
52
- self.tokens = min(self.capacity, self.tokens + refill_amount)
53
- self.last_refill = now
54
-
55
- self.log.append((now, self.tokens))
56
-
57
- def wait_time(self, requested_tokens) -> float:
58
- """Calculate the time to wait for the requested number of tokens."""
59
- now = time.monotonic()
60
- elapsed = now - self.last_refill
61
- refill_amount = elapsed * self.refill_rate
62
- available_tokens = min(self.capacity, self.tokens + refill_amount)
63
- return max(0, requested_tokens - available_tokens) / self.refill_rate
64
-
65
- async def get_tokens(self, amount=1) -> None:
66
- """Wait for the specified number of tokens to become available.
67
- Note that this method is a coroutine.
68
- """
69
- if amount > self.capacity:
70
- raise ValueError(
71
- f"Requested tokens exceed bucket capacity. Bucket capacity: {self.capacity}, requested amount: {amount}"
72
- )
73
- while self.tokens < amount:
74
- self.refill()
75
- await asyncio.sleep(0.1) # Sleep briefly to prevent busy waiting
76
- self.tokens -= amount
77
-
78
- now = time.monotonic()
79
- self.log.append((now, self.tokens))
80
-
81
- def get_log(self) -> list[tuple]:
82
- return self.log
83
-
84
- def visualize(self):
85
- """Visualize the token bucket over time."""
86
- times, tokens = zip(*self.get_log())
87
- start_time = times[0]
88
- times = [t - start_time for t in times] # Normalize time to start from 0
89
-
90
- plt.figure(figsize=(10, 6))
91
- plt.plot(times, tokens, label="Tokens Available")
92
- plt.xlabel("Time (seconds)", fontsize=12)
93
- plt.ylabel("Number of Tokens", fontsize=12)
94
- details = f"{self.bucket_name} ({self.bucket_type}) Bucket Usage Over Time\nCapacity: {self.capacity:.1f}, Refill Rate: {self.refill_rate:.1f}/second"
95
- plt.title(details, fontsize=14)
96
-
97
- plt.legend()
98
- plt.grid(True)
99
- plt.tight_layout()
100
- plt.show()
101
-
102
-
103
- class ModelBuckets:
104
- """A class to represent the token and request buckets for a model.
105
- Most LLM model services have limits both on requests-per-minute (RPM) and tokens-per-minute (TPM).
106
- A request is one call to the service. The number of tokens required for a request depends on parameters.
107
- """
108
-
109
- def __init__(self, requests_bucket: TokenBucket, tokens_bucket: TokenBucket):
110
- self.requests_bucket = requests_bucket
111
- self.tokens_bucket = tokens_bucket
112
-
113
- def __add__(self, other):
114
- return ModelBuckets(
115
- requests_bucket=self.requests_bucket + other.requests_bucket,
116
- tokens_bucket=self.tokens_bucket + other.tokens_bucket,
117
- )
118
-
119
- @classmethod
120
- def infinity_bucket(cls, model_name: str = "not_specified") -> "ModelBuckets":
121
- """Create a bucket with infinite capacity and refill rate."""
122
- return cls(
123
- requests_bucket=TokenBucket(
124
- bucket_name=model_name, bucket_type="requests", capacity=float("inf"), refill_rate=float("inf")
125
- ),
126
- tokens_bucket=TokenBucket(
127
- bucket_name=model_name, bucket_type="tokens", capacity=float("inf"), refill_rate=float("inf")
128
- ),
129
- )
130
-
131
- def visualize(self):
132
- plot1 = self.requests_bucket.visualize()
133
- plot2 = self.tokens_bucket.visualize()
134
- return plot1, plot2
135
-
136
- def __repr__(self):
137
- return f"ModelBuckets(requests_bucket={self.requests_bucket}, tokens_bucket={self.tokens_bucket})"
138
-
139
-
140
- class BucketCollection(UserDict):
141
- """A jobs object will have a whole collection of model buckets, as multiple models could be used.
142
- The keys here are the models, and the values are the ModelBuckets objects.
143
- Models themselves are hashable, so this works.
144
- """
145
-
146
- def __init__(self):
147
- super().__init__()
148
-
149
- def __repr__(self):
150
- return f"BucketCollection({self.data})"
151
-
152
- def add_model(self, model) -> None:
153
- """Adds a model to the bucket collection. This will create the token and request buckets for the model."""
154
- # compute the TPS and RPS from the model
155
- TPS = model.TPM / 60.0
156
- RPS = model.RPM / 60.0
157
- # create the buckets
158
- requests_bucket = TokenBucket(
159
- bucket_name=model.model,
160
- bucket_type="requests",
161
- capacity=RPS,
162
- refill_rate=RPS,
163
- )
164
- tokens_bucket = TokenBucket(
165
- bucket_name=model.model, bucket_type="tokens", capacity=TPS, refill_rate=TPS
166
- )
167
- model_buckets = ModelBuckets(requests_bucket, tokens_bucket)
168
- if model in self:
169
- # it if already exists, combine the buckets
170
- self[model] += model_buckets
171
- else:
172
- self[model] = model_buckets
173
-
174
- def visualize(self) -> dict:
175
- plots = {}
176
- for model in self:
177
- plots[model] = self[model].visualize()
178
- return plots
@@ -1,19 +0,0 @@
1
- import asyncio
2
-
3
- from edsl.jobs import Jobs
4
- from edsl.results import Results, Result
5
- from edsl.jobs.JobsRunner import JobsRunner
6
-
7
-
8
- class JobsRunnerDryRun(JobsRunner):
9
- runner_name = "dryrun"
10
-
11
- def __init__(self, jobs: Jobs):
12
- super().__init__(jobs)
13
-
14
- def run(
15
- self, n=1, verbose=False, sleep=0, debug=False, progress_bar=False
16
- ) -> Results:
17
- """Runs a collection of interviews."""
18
-
19
- print(f"This will run {len(self.interviews)} interviews.")
@@ -1,54 +0,0 @@
1
- import json
2
- import threading
3
- import time
4
- import uuid
5
- from edsl.data import CRUD
6
- from edsl.jobs.JobsRunner import JobsRunner
7
- from edsl.results import Results
8
-
9
-
10
- class JobsRunnerStreaming(JobsRunner):
11
- """This JobRunner conducts interviews serially."""
12
-
13
- runner_name = "streaming"
14
-
15
- def run(
16
- self,
17
- debug: bool = False,
18
- sleep: int = 0,
19
- n: int = 1,
20
- verbose: bool = False,
21
- progress_bar: bool = False,
22
- ) -> Results:
23
- """
24
- Conducts Interviews **serially** and returns their results.
25
- - `n`: how many times to run each interview
26
- - `debug`: prints debug messages
27
- - `verbose`: prints messages
28
- - `progress_bar`: shows a progress bar
29
- """
30
- job_uuid = str(uuid.uuid4())
31
- total_results = len(self.interviews)
32
-
33
- def conduct_and_save_interviews():
34
- for i, interview in enumerate(self.interviews):
35
- answer = interview.conduct_interview(debug=debug)
36
- CRUD.write_result(
37
- job_uuid=job_uuid,
38
- result_uuid=str(i),
39
- agent=json.dumps(interview.agent.to_dict()),
40
- scenario=json.dumps(interview.scenario.to_dict()),
41
- model=json.dumps(interview.model.to_dict()),
42
- answer=json.dumps(answer),
43
- )
44
- time.sleep(sleep)
45
-
46
- interview_thread = threading.Thread(target=conduct_and_save_interviews)
47
- interview_thread.start()
48
-
49
- return Results(
50
- survey=self.jobs.survey,
51
- data=[],
52
- job_uuid=job_uuid,
53
- total_results=total_results,
54
- )
@@ -1,215 +0,0 @@
1
- import asyncio
2
- import enum
3
- from typing import Callable
4
- from collections import UserDict, UserList
5
-
6
- from edsl.jobs.buckets import ModelBuckets
7
- from edsl.jobs.token_tracking import TokenUsage
8
- from edsl.questions import Question
9
-
10
- from edsl.exceptions import InterviewErrorPriorTaskCanceled
11
-
12
-
13
- class TaskStatus(enum.Enum):
14
- "These are the possible statuses for a task."
15
- NOT_STARTED = enum.auto()
16
- WAITING_ON_DEPENDENCIES = enum.auto()
17
- CANCELLED = enum.auto()
18
- PARENT_FAILED = enum.auto()
19
- DEPENDENCIES_COMPLETE = enum.auto()
20
- WAITING_FOR_REQUEST_CAPCITY = enum.auto()
21
- REQUEST_CAPACITY_ACQUIRED = enum.auto()
22
- WAITING_FOR_TOKEN_CAPCITY = enum.auto()
23
- TOKEN_CAPACITY_ACQUIRED = enum.auto()
24
- API_CALL_IN_PROGRESS = enum.auto()
25
- API_CALL_COMPLETE = enum.auto()
26
-
27
-
28
- class InterviewStatusDictionary(UserDict):
29
- def __init__(self, data=None):
30
- if data:
31
- assert all([task_status in data for task_status in TaskStatus])
32
- super().__init__(data)
33
- else:
34
- d = {}
35
- for task_status in TaskStatus:
36
- d[task_status] = 0
37
- d["number_from_cache"] = 0
38
- super().__init__(d)
39
-
40
- def __add__(
41
- self, other: "InterviewStatusDictionary"
42
- ) -> "InterviewStatusDictionary":
43
- if not isinstance(other, InterviewStatusDictionary):
44
- raise ValueError(f"Can't add {type(other)} to InterviewStatusDictionary")
45
- new_dict = {}
46
- for key in self.keys():
47
- new_dict[key] = self[key] + other[key]
48
- return InterviewStatusDictionary(new_dict)
49
-
50
- def __repr__(self):
51
- return f"InterviewStatusDictionary({self.data})"
52
-
53
-
54
-
55
- class TaskStatusDescriptor:
56
- def __init__(self):
57
- self._task_status = None
58
-
59
- def __get__(self, instance, owner):
60
- return self._task_status
61
-
62
- def __set__(self, instance, value):
63
- if not isinstance(value, TaskStatus):
64
- raise ValueError("Value must be an instance of TaskStatus enum")
65
- # logging.info(f"TaskStatus changed for {instance} from {self._task_status} to {value}")
66
- self._task_status = value
67
-
68
- def __delete__(self, instance):
69
- self._task_status = None
70
-
71
-
72
- class QuestionTaskCreator(UserList):
73
- """Class to create and manage question tasks with dependencies.
74
- It is a UserList with all the tasks that must be completed before the focal task can be run.
75
- When called, it returns an asyncio.Task that depends on the tasks that must be completed before it can be run.
76
- """
77
-
78
- task_status = TaskStatusDescriptor()
79
-
80
- def __init__(
81
- self,
82
- *,
83
- question: Question,
84
- answer_question_func: Callable,
85
- model_buckets: ModelBuckets,
86
- token_estimator: Callable = None,
87
- ):
88
- super().__init__([])
89
- self.answer_question_func = answer_question_func
90
- self.question = question
91
-
92
- self.model_buckets = model_buckets
93
- self.requests_bucket = self.model_buckets.requests_bucket
94
- self.tokens_bucket = self.model_buckets.tokens_bucket
95
- self.token_estimator = token_estimator
96
-
97
- self.from_cache = False
98
-
99
- self.cached_token_usage = TokenUsage(from_cache=True)
100
- self.new_token_usage = TokenUsage(from_cache=False)
101
-
102
- self.task_status = TaskStatus.NOT_STARTED
103
-
104
- def add_dependency(self, task) -> None:
105
- """Adds a task dependency to the list of dependencies."""
106
- self.append(task)
107
-
108
- def __repr__(self):
109
- return f"QuestionTaskCreator for {self.question.question_name}"
110
-
111
- def generate_task(self, debug) -> asyncio.Task:
112
- """Creates a task that depends on the passed-in dependencies."""
113
- task = asyncio.create_task(self._run_task_async(debug))
114
- task.edsl_name = self.question.question_name
115
- task.depends_on = [x.edsl_name for x in self]
116
- return task
117
-
118
- def estimated_tokens(self) -> int:
119
- """Estimates the number of tokens that will be required to run the focal task."""
120
- token_estimate = self.token_estimator(self.question)
121
- return token_estimate
122
-
123
- def token_usage(self) -> dict:
124
- """Returns the token usage for the task."""
125
- return {
126
- "cached_tokens": self.cached_token_usage,
127
- "new_tokens": self.new_token_usage,
128
- }
129
-
130
- async def _run_focal_task(self, debug) -> "Answers":
131
- """Runs the focal task i.e., the question that we are interested in answering.
132
- It is only called after all the dependency tasks are completed.
133
- """
134
-
135
- requested_tokens = self.estimated_tokens()
136
- if (estimated_wait_time := self.tokens_bucket.wait_time(requested_tokens)) > 0:
137
- self.task_status = TaskStatus.WAITING_FOR_TOKEN_CAPCITY
138
-
139
- await self.tokens_bucket.get_tokens(requested_tokens)
140
- self.task_status = TaskStatus.TOKEN_CAPACITY_ACQUIRED
141
-
142
- if (estimated_wait_time := self.requests_bucket.wait_time(1)) > 0:
143
- self.waiting = True
144
- self.task_status = TaskStatus.WAITING_FOR_REQUEST_CAPCITY
145
-
146
- await self.requests_bucket.get_tokens(1)
147
- self.task_status = TaskStatus.REQUEST_CAPACITY_ACQUIRED
148
-
149
- self.task_status = TaskStatus.API_CALL_IN_PROGRESS
150
- results = await self.answer_question_func(self.question, debug)
151
- self.task_status = TaskStatus.API_CALL_COMPLETE
152
-
153
- if "cached_response" in results:
154
- if results["cached_response"]:
155
- self.tokens_bucket.add_tokens(requested_tokens)
156
- self.requests_bucket.add_tokens(1)
157
- self.from_cache = True
158
-
159
- tracker = self.cached_token_usage if self.from_cache else self.new_token_usage
160
-
161
- # TODO: This is hacky. The 'func' call should return an object that definitely has a 'usage' key.
162
-
163
- usage = results.get("usage", {"prompt_tokens": 0, "completion_tokens": 0})
164
- prompt_tokens = usage.get("prompt_tokens", 0)
165
- completion_tokens = usage.get("completion_tokens", 0)
166
- tracker.add_tokens(
167
- prompt_tokens=prompt_tokens, completion_tokens=completion_tokens
168
- )
169
-
170
- return results
171
-
172
- async def _run_task_async(self, debug) -> None:
173
- """Runs the task asynchronously, awaiting the tasks that must be completed before this one can be run."""
174
- # logger.info(f"Running task for {self.question.question_name}")
175
- try:
176
- # This is waiting for the tasks that must be completed before this one can be run.
177
- # This does *not* use the return_exceptions = True flag, so if any of the tasks fail,
178
- # it throws the exception immediately, which is what we want.
179
- self.task_status = TaskStatus.WAITING_ON_DEPENDENCIES
180
- await asyncio.gather(*self)
181
- except asyncio.CancelledError:
182
- self.status = TaskStatus.CANCELLED
183
- # logger.info(f"Task for {self.question.question_name} was cancelled, most likely because it was skipped.")
184
- raise
185
- except Exception as e:
186
- self.task_status = TaskStatus.PARENT_FAILED
187
- # logger.error(f"Required tasks for {self.question.question_name} failed: {e}")
188
- # turns the parent exception into a custom exception
189
- # So the task gets canceled but this InterviewErrorPriorTaskCanceled exception
190
- # So we never get the question details we need.
191
- raise InterviewErrorPriorTaskCanceled(
192
- f"Required tasks failed for {self.question.question_name}"
193
- ) from e
194
- else:
195
- # logger.info(f"Tasks for {self.question.question_name} completed")
196
- # This is the actual task that we want to run.
197
- self.task_status = TaskStatus.DEPENDENCIES_COMPLETE
198
- return await self._run_focal_task(debug)
199
-
200
-
201
- class TasksList(UserList):
202
- def status(self, debug=False):
203
- if debug:
204
- for task in self:
205
- print(f"Task {task.edsl_name}")
206
- print(f"\t DEPENDS ON: {task.depends_on}")
207
- print(f"\t DONE: {task.done()}")
208
- print(f"\t CANCELLED: {task.cancelled()}")
209
- if not task.cancelled():
210
- if task.done():
211
- print(f"\t RESULT: {task.result()}")
212
- else:
213
- print(f"\t RESULT: None - Not done yet")
214
-
215
- print("---------------------")