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,45 @@
1
+ """Mixin class for exporting results."""
2
+
3
+ from functools import wraps
4
+ from edsl.results.DatasetExportMixin import DatasetExportMixin
5
+
6
+
7
+ def to_dataset(func):
8
+ """Convert the object to a Dataset object before calling the function."""
9
+
10
+ @wraps(func)
11
+ def wrapper(self, *args, **kwargs):
12
+ """Return the function with the Results object converted to a Dataset object."""
13
+ if self.__class__.__name__ == "ScenarioList":
14
+ return func(self.to_dataset(), *args, **kwargs)
15
+ else:
16
+ raise Exception(
17
+ f"Class {self.__class__.__name__} not recognized as a Results or Dataset object."
18
+ )
19
+
20
+ return wrapper
21
+
22
+
23
+ def decorate_methods_from_mixin(cls, mixin_cls):
24
+ for attr_name, attr_value in mixin_cls.__dict__.items():
25
+ if callable(attr_value) and not attr_name.startswith("__"):
26
+ setattr(cls, attr_name, to_dataset(attr_value))
27
+ return cls
28
+
29
+
30
+ # @decorate_all_methods
31
+ class ScenarioListExportMixin(DatasetExportMixin):
32
+ """Mixin class for exporting Results objects."""
33
+
34
+ def __init_subclass__(cls, **kwargs):
35
+ super().__init_subclass__(**kwargs)
36
+ decorate_methods_from_mixin(cls, DatasetExportMixin)
37
+
38
+ def to_docx(self, filename: str):
39
+ """Export the ScenarioList to a .docx file."""
40
+ dataset = self.to_dataset()
41
+ from edsl.results.DatasetTree import Tree
42
+
43
+ tree = Tree(dataset)
44
+ tree.construct_tree()
45
+ tree.to_docx(filename)
@@ -0,0 +1,239 @@
1
+ import os
2
+ import re
3
+ import copy
4
+ import atexit
5
+ import tempfile
6
+ import subprocess
7
+
8
+
9
+ class GoogleDriveDownloader:
10
+ _temp_dir = None
11
+ _temp_file_path = None
12
+
13
+ @classmethod
14
+ def fetch_from_drive(cls, url, filename=None):
15
+ import requests
16
+
17
+ # Extract file ID from the URL
18
+ file_id = cls._extract_file_id(url)
19
+ if not file_id:
20
+ raise ValueError("Invalid Google Drive URL")
21
+
22
+ # Construct the download URL
23
+ download_url = f"https://drive.google.com/uc?export=download&id={file_id}"
24
+
25
+ # Send a GET request to the URL
26
+ session = requests.Session()
27
+ response = session.get(download_url, stream=True)
28
+ response.raise_for_status()
29
+
30
+ # Check for large file download prompt
31
+ for key, value in response.cookies.items():
32
+ if key.startswith("download_warning"):
33
+ params = {"id": file_id, "confirm": value}
34
+ response = session.get(download_url, params=params, stream=True)
35
+ break
36
+
37
+ # Create a temporary file to save the download
38
+ if not filename:
39
+ filename = "downloaded_file"
40
+
41
+ if cls._temp_dir is None:
42
+ cls._temp_dir = tempfile.TemporaryDirectory()
43
+ atexit.register(cls._cleanup)
44
+
45
+ cls._temp_file_path = os.path.join(cls._temp_dir.name, filename)
46
+
47
+ # Write the content to the temporary file
48
+ with open(cls._temp_file_path, "wb") as f:
49
+ for chunk in response.iter_content(32768):
50
+ if chunk:
51
+ f.write(chunk)
52
+
53
+ print(f"File saved to: {cls._temp_file_path}")
54
+
55
+ return cls._temp_file_path
56
+
57
+ @staticmethod
58
+ def _extract_file_id(url):
59
+ from urllib.parse import urlparse, parse_qs
60
+
61
+ # Try to extract file ID from '/file/d/' format
62
+ file_id_match = re.search(r"/d/([a-zA-Z0-9-_]+)", url)
63
+ if file_id_match:
64
+ return file_id_match.group(1)
65
+
66
+ # If not found, try to extract from 'open?id=' format
67
+ parsed_url = urlparse(url)
68
+ query_params = parse_qs(parsed_url.query)
69
+ if "id" in query_params:
70
+ return query_params["id"][0]
71
+
72
+ return None
73
+
74
+ @classmethod
75
+ def _cleanup(cls):
76
+ if cls._temp_dir:
77
+ cls._temp_dir.cleanup()
78
+
79
+ @classmethod
80
+ def get_temp_file_path(cls):
81
+ return cls._temp_file_path
82
+
83
+
84
+ def fetch_and_save_pdf(url, filename):
85
+ # Send a GET request to the URL
86
+ import requests
87
+
88
+ response = requests.get(url)
89
+
90
+ # Check if the request was successful
91
+ response.raise_for_status()
92
+
93
+ # Create a temporary directory
94
+ with tempfile.TemporaryDirectory() as temp_dir:
95
+ # Construct the full path for the file
96
+ temp_file_path = os.path.join(temp_dir, filename)
97
+
98
+ # Write the content to the temporary file
99
+ with open(temp_file_path, "wb") as file:
100
+ file.write(response.content)
101
+
102
+ print(f"PDF saved to: {temp_file_path}")
103
+
104
+ # Here you can perform operations with the file
105
+ # The file will be automatically deleted when you exit this block
106
+
107
+ return temp_file_path
108
+
109
+
110
+ class ScenarioListPdfMixin:
111
+ @classmethod
112
+ def from_pdf(cls, filename_or_url, collapse_pages=False):
113
+ # Check if the input is a URL
114
+ if cls.is_url(filename_or_url):
115
+ # Check if it's a Google Drive URL
116
+ if "drive.google.com" in filename_or_url:
117
+ temp_filename = GoogleDriveDownloader.fetch_from_drive(
118
+ filename_or_url, "temp_pdf.pdf"
119
+ )
120
+ else:
121
+ # For other URLs, use the previous fetch_and_save_pdf function
122
+ temp_filename = fetch_and_save_pdf(filename_or_url, "temp_pdf.pdf")
123
+
124
+ scenarios = list(cls.extract_text_from_pdf(temp_filename))
125
+ else:
126
+ # If it's not a URL, assume it's a local file path
127
+ scenarios = list(cls.extract_text_from_pdf(filename_or_url))
128
+ if not collapse_pages:
129
+ return cls(scenarios)
130
+ else:
131
+ txt = ""
132
+ for scenario in scenarios:
133
+ txt += scenario["text"]
134
+ from edsl.scenarios import Scenario
135
+
136
+ base_scenario = copy.copy(scenarios[0])
137
+ base_scenario["text"] = txt
138
+ return base_scenario
139
+
140
+ @staticmethod
141
+ def is_url(string):
142
+ from urllib.parse import urlparse
143
+
144
+ try:
145
+ result = urlparse(string)
146
+ return all([result.scheme, result.netloc])
147
+ except ValueError:
148
+ return False
149
+
150
+ @classmethod
151
+ def _from_pdf_to_image(cls, pdf_path, image_format="jpeg"):
152
+ """
153
+ Convert each page of a PDF into an image and create Scenario instances.
154
+
155
+ :param pdf_path: Path to the PDF file.
156
+ :param image_format: Format of the output images (default is 'jpeg').
157
+ :return: ScenarioList instance containing the Scenario instances.
158
+ """
159
+ import tempfile
160
+ from pdf2image import convert_from_path
161
+ from edsl.scenarios import Scenario
162
+
163
+ with tempfile.TemporaryDirectory() as output_folder:
164
+ # Convert PDF to images
165
+ images = convert_from_path(pdf_path)
166
+
167
+ scenarios = []
168
+
169
+ # Save each page as an image and create Scenario instances
170
+ for i, image in enumerate(images):
171
+ image_path = os.path.join(output_folder, f"page_{i+1}.{image_format}")
172
+ image.save(image_path, image_format.upper())
173
+
174
+ scenario = Scenario._from_filepath_image(image_path)
175
+ scenarios.append(scenario)
176
+
177
+ # print(f"Saved {len(images)} pages as images in {output_folder}")
178
+ return cls(scenarios)
179
+
180
+ @staticmethod
181
+ def extract_text_from_pdf(pdf_path):
182
+ from edsl.scenarios.Scenario import Scenario
183
+ import fitz # PyMuPDF
184
+
185
+ # TODO: Add test case
186
+ # Ensure the file exists
187
+ if not os.path.exists(pdf_path):
188
+ raise FileNotFoundError(f"The file {pdf_path} does not exist.")
189
+
190
+ # Open the PDF file
191
+ document = fitz.open(pdf_path)
192
+
193
+ # Get the filename from the path
194
+ filename = os.path.basename(pdf_path)
195
+
196
+ # Iterate through each page and extract text
197
+ for page_num in range(len(document)):
198
+ page = document.load_page(page_num)
199
+ text = page.get_text()
200
+
201
+ # Create a dictionary for the current page
202
+ page_info = {"filename": filename, "page": page_num + 1, "text": text}
203
+ yield Scenario(page_info)
204
+
205
+ def create_hello_world_pdf(pdf_path):
206
+ # LaTeX content
207
+ latex_content = r"""
208
+ \documentclass{article}
209
+ \title{Hello World}
210
+ \author{John}
211
+ \date{\today}
212
+ \begin{document}
213
+ \maketitle
214
+ \section{Hello, World!}
215
+ This is a simple hello world example created with LaTeX and Python.
216
+ \end{document}
217
+ """
218
+
219
+ # Create a .tex file
220
+ tex_filename = pdf_path + ".tex"
221
+ with open(tex_filename, "w") as tex_file:
222
+ tex_file.write(latex_content)
223
+
224
+ # Compile the .tex file to PDF
225
+ subprocess.run(["pdflatex", tex_filename], check=True)
226
+
227
+ # Optionally, clean up auxiliary files generated by pdflatex
228
+ aux_files = [pdf_path + ext for ext in [".aux", ".log"]]
229
+ for aux_file in aux_files:
230
+ try:
231
+ os.remove(aux_file)
232
+ except FileNotFoundError:
233
+ pass
234
+
235
+
236
+ if __name__ == "__main__":
237
+ import doctest
238
+
239
+ doctest.testmod()
@@ -1 +1,3 @@
1
1
  from edsl.scenarios.Scenario import Scenario
2
+ from edsl.scenarios.ScenarioList import ScenarioList
3
+ from edsl.scenarios.FileStore import FileStore
@@ -0,0 +1,96 @@
1
+ # directory_scanner.py
2
+ from dataclasses import dataclass
3
+ from typing import Optional, List, Iterator, TypeVar, Generic, Callable, Any
4
+ import os
5
+
6
+ T = TypeVar("T")
7
+
8
+
9
+ @dataclass
10
+ class DirectoryScanner:
11
+ """
12
+ Scanner for finding files in a directory based on various criteria.
13
+ """
14
+
15
+ directory_path: str
16
+
17
+ def scan(
18
+ self,
19
+ factory: Callable[[str], T],
20
+ recursive: bool = False,
21
+ suffix_allow_list: Optional[List[str]] = None,
22
+ suffix_exclude_list: Optional[List[str]] = None,
23
+ example_suffix: Optional[str] = None,
24
+ include_no_extension: bool = True,
25
+ ) -> List[T]:
26
+ """
27
+ Eagerly scan directory and return list of objects created by factory.
28
+
29
+ Args:
30
+ factory: Callable that creates objects from file paths
31
+ recursive: If True, recursively traverse subdirectories
32
+ suffix_allow_list: List of allowed file extensions (without dots)
33
+ suffix_exclude_list: List of excluded file extensions (takes precedence over allow list)
34
+ example_suffix: If provided, only include files with this example suffix
35
+ include_no_extension: Whether to include files without extensions
36
+ """
37
+ return list(
38
+ self.iter_scan(
39
+ factory,
40
+ recursive=recursive,
41
+ suffix_allow_list=suffix_allow_list,
42
+ suffix_exclude_list=suffix_exclude_list,
43
+ example_suffix=example_suffix,
44
+ include_no_extension=include_no_extension,
45
+ )
46
+ )
47
+
48
+ def iter_scan(
49
+ self,
50
+ factory: Callable[[str], T],
51
+ recursive: bool = False,
52
+ suffix_allow_list: Optional[List[str]] = None,
53
+ suffix_exclude_list: Optional[List[str]] = None,
54
+ example_suffix: Optional[str] = None,
55
+ include_no_extension: bool = True,
56
+ ) -> Iterator[T]:
57
+ """
58
+ Lazily scan directory and yield objects created by factory.
59
+ """
60
+
61
+ def should_include_file(filepath: str) -> bool:
62
+ _, ext = os.path.splitext(filepath)
63
+ ext = ext[1:] if ext else ""
64
+
65
+ # Handle no extension case
66
+ if not ext:
67
+ return include_no_extension
68
+
69
+ # Check exclusions first (they take precedence)
70
+ if suffix_exclude_list and ext in suffix_exclude_list:
71
+ return False
72
+
73
+ # Check example suffix if specified
74
+ if example_suffix and not filepath.endswith(example_suffix):
75
+ return False
76
+
77
+ # Check allowed suffixes if specified
78
+ if suffix_allow_list and ext not in suffix_allow_list:
79
+ return False
80
+
81
+ return True
82
+
83
+ def iter_files():
84
+ if recursive:
85
+ for root, _, files in os.walk(self.directory_path):
86
+ for file in files:
87
+ yield os.path.join(root, file)
88
+ else:
89
+ for file in os.listdir(self.directory_path):
90
+ file_path = os.path.join(self.directory_path, file)
91
+ if os.path.isfile(file_path):
92
+ yield file_path
93
+
94
+ for file_path in iter_files():
95
+ if should_include_file(file_path):
96
+ yield factory(file_path)
@@ -0,0 +1,85 @@
1
+ from typing import Optional, Dict, Type
2
+ from abc import ABC, abstractmethod
3
+ import importlib.metadata
4
+ import importlib.util
5
+
6
+ from edsl.utilities.is_notebook import is_notebook
7
+
8
+
9
+ class FileMethods(ABC):
10
+ _handlers: Dict[str, Type["FileMethods"]] = {}
11
+
12
+ def __init__(self, path: Optional[str] = None):
13
+ self.path = path
14
+
15
+ def __init_subclass__(cls) -> None:
16
+ """Register subclasses automatically when they're defined."""
17
+ super().__init_subclass__()
18
+ if hasattr(cls, "suffix"):
19
+ FileMethods._handlers[cls.suffix] = cls
20
+
21
+ @classmethod
22
+ def get_handler(cls, suffix: str) -> Optional[Type["FileMethods"]]:
23
+ """Get the appropriate handler class for a given suffix."""
24
+ # Load plugins if they haven't been loaded yet
25
+ if not cls._handlers:
26
+ cls.load_plugins()
27
+ return cls._handlers.get(suffix.lower())
28
+
29
+ @classmethod
30
+ def load_plugins(cls):
31
+ """Load all file handler plugins including built-ins and external plugins."""
32
+
33
+ from edsl.scenarios import handlers
34
+
35
+ # Then load any external plugins
36
+ try:
37
+ entries = importlib.metadata.entry_points(group="file_handlers")
38
+ except TypeError: # some Python 3.9 bullshit
39
+ # entries = importlib.metadata.entry_points()
40
+ entries = []
41
+
42
+ for ep in entries:
43
+ try:
44
+ handler_class = ep.load()
45
+ # Registration happens automatically via __init_subclass__
46
+ except Exception as e:
47
+ print(f"Failed to load external handler {ep.name}: {e}")
48
+
49
+ @classmethod
50
+ def get_handler_for_path(cls, path: str) -> Optional[Type["FileMethods"]]:
51
+ """Get the appropriate handler class for a file path."""
52
+ suffix = path.split(".")[-1].lower() if "." in path else ""
53
+ return cls.get_handler(suffix)
54
+
55
+ @classmethod
56
+ def create(cls, path: str) -> Optional["FileMethods"]:
57
+ """Create an appropriate handler instance for the given path."""
58
+ handler_class = cls.get_handler_for_path(path)
59
+ if handler_class:
60
+ return handler_class(path)
61
+ return None
62
+
63
+ @classmethod
64
+ def supported_file_types(cls):
65
+ if not cls._handlers:
66
+ cls.load_plugins()
67
+ return list(cls._handlers.keys())
68
+
69
+ @abstractmethod
70
+ def view_system(self):
71
+ ...
72
+
73
+ @abstractmethod
74
+ def view_notebook(self):
75
+ ...
76
+
77
+ def view(self):
78
+ if is_notebook():
79
+ self.view_notebook()
80
+ else:
81
+ self.view_system()
82
+
83
+ @abstractmethod
84
+ def example(self):
85
+ ...
@@ -0,0 +1,13 @@
1
+ from .pdf import PdfMethods
2
+ from .docx import DocxMethods
3
+ from .png import PngMethods
4
+ from .txt import TxtMethods
5
+ from .html import HtmlMethods
6
+ from .md import MarkdownMethods
7
+ from .csv import CsvMethods
8
+ from .json import JsonMethods
9
+ from .sql import SqlMethods
10
+ from .pptx import PptxMethods
11
+ from .latex import LaTeXMethods
12
+ from .py import PyMethods
13
+ from .sqlite import SQLiteMethods
@@ -0,0 +1,49 @@
1
+ import tempfile
2
+ from edsl.scenarios.file_methods import FileMethods
3
+
4
+
5
+ class CsvMethods(FileMethods):
6
+ suffix = "csv"
7
+
8
+ def view_system(self):
9
+ import os
10
+ import subprocess
11
+
12
+ if os.path.exists(self.path):
13
+ try:
14
+ if (os_name := os.name) == "posix":
15
+ subprocess.run(["open", self.path], check=True) # macOS
16
+ elif os_name == "nt":
17
+ os.startfile(self.path) # Windows
18
+ else:
19
+ subprocess.run(["xdg-open", self.path], check=True) # Linux
20
+ except Exception as e:
21
+ print(f"Error opening CSV: {e}")
22
+ else:
23
+ print("CSV file was not found.")
24
+
25
+ def view_notebook(self):
26
+ import pandas as pd
27
+ from IPython.display import display
28
+
29
+ df = pd.read_csv(self.path)
30
+ display(df)
31
+
32
+ def example(self):
33
+ import pandas as pd
34
+
35
+ df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
36
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".csv") as f:
37
+ df.to_csv(f.name, index=False)
38
+ return f.name
39
+
40
+ def to_pandas(self):
41
+ """
42
+ Convert the CSV file to a pandas DataFrame.
43
+
44
+ Returns:
45
+ pandas.DataFrame: The data from the CSV as a DataFrame
46
+ """
47
+ import pandas as pd
48
+
49
+ return pd.read_csv(self.path)
@@ -0,0 +1,76 @@
1
+ from edsl.scenarios.file_methods import FileMethods
2
+ import os
3
+ import tempfile
4
+
5
+
6
+ class DocxMethods(FileMethods):
7
+ suffix = "docx"
8
+
9
+ def extract_text(self):
10
+ from docx import Document
11
+
12
+ self.doc = Document(self.path)
13
+
14
+ # Extract all text
15
+ full_text = []
16
+ for para in self.doc.paragraphs:
17
+ full_text.append(para.text)
18
+
19
+ text = "\n".join(full_text)
20
+ return text
21
+
22
+ def view_system(self):
23
+ import os
24
+ import subprocess
25
+
26
+ if os.path.exists(self.path):
27
+ try:
28
+ if (os_name := os.name) == "posix":
29
+ subprocess.run(["open", self.path], check=True) # macOS
30
+ elif os_name == "nt":
31
+ os.startfile(self.path) # Windows
32
+ else:
33
+ subprocess.run(["xdg-open", self.path], check=True) # Linux
34
+ except Exception as e:
35
+ print(f"Error opening DOCX: {e}")
36
+ else:
37
+ print("DOCX file was not found.")
38
+
39
+ def view_notebook(self):
40
+ import mammoth
41
+ from IPython.display import HTML, display
42
+
43
+ with open(self.path, "rb") as docx_file:
44
+ result = mammoth.convert_to_html(docx_file)
45
+ html = f"""
46
+ <div style="width: 800px; height: 800px; padding: 20px;
47
+ border: 1px solid #ccc; overflow-y: auto;">
48
+ {result.value}
49
+ </div>
50
+ """
51
+ display(HTML(html))
52
+
53
+ def example(self):
54
+ from docx import Document
55
+ from edsl.scenarios.Scenario import Scenario
56
+ from edsl.scenarios.ScenarioList import ScenarioList
57
+
58
+ os.makedirs("test_dir", exist_ok=True)
59
+ doc1 = Document()
60
+ _ = doc1.add_heading("First Survey")
61
+ doc1.save("test_dir/test1.docx")
62
+ doc2 = Document()
63
+ _ = doc2.add_heading("Second Survey")
64
+
65
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp:
66
+ doc2.save(tmp.name)
67
+ tmp.close()
68
+
69
+ return tmp.name
70
+
71
+
72
+ if __name__ == "__main__":
73
+ docx_temp = DocxMethods.example()
74
+ from edsl.scenarios.FileStore import FileStore
75
+
76
+ fs = FileStore(docx_temp)
@@ -0,0 +1,37 @@
1
+ from edsl.scenarios.file_methods import FileMethods
2
+ import tempfile
3
+
4
+
5
+ class HtmlMethods(FileMethods):
6
+ suffix = "html"
7
+
8
+ def view_system(self):
9
+ import webbrowser
10
+
11
+ # with open(self.path, "r") as f:
12
+ # html_string = f.read()
13
+
14
+ # html_path = self.to_tempfile()
15
+ # webbrowser.open("file://" + html_path)
16
+ webbrowser.open("file://" + self.path)
17
+
18
+ def view_notebook(self):
19
+ from IPython.display import IFrame, display
20
+
21
+ display(IFrame(self.path, width=800, height=800))
22
+
23
+ def example(self):
24
+ html_string = b"""
25
+ <html>
26
+ <head>
27
+ <title>Test</title>
28
+ </head>
29
+ <body>
30
+ <h1>Hello, World!</h1>
31
+ </body>
32
+ </html>
33
+ """
34
+
35
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".html") as f:
36
+ f.write(html_string)
37
+ return f.name