edsl 0.1.14__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 +46 -10
  5. edsl/__version__.py +1 -0
  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 +121 -104
  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 -204
  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.14.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 -417
  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 -166
  360. edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
  361. edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
  362. edsl/jobs/task_management.py +0 -218
  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.14.dist-info/METADATA +0 -69
  403. edsl-0.1.14.dist-info/RECORD +0 -141
  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.14.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -0,0 +1,313 @@
1
+ from edsl.scenarios.file_methods import FileMethods
2
+ import tempfile
3
+ import re
4
+ from typing import List, Optional
5
+ import textwrap
6
+
7
+
8
+ class SqlMethods(FileMethods):
9
+ suffix = "sql"
10
+
11
+ def view_system(self):
12
+ import os
13
+ import subprocess
14
+
15
+ if os.path.exists(self.path):
16
+ try:
17
+ if (os_name := os.name) == "posix":
18
+ subprocess.run(["open", self.path], check=True) # macOS
19
+ elif os_name == "nt":
20
+ os.startfile(self.path) # Windows
21
+ else:
22
+ subprocess.run(["xdg-open", self.path], check=True) # Linux
23
+ except Exception as e:
24
+ print(f"Error opening SQL file: {e}")
25
+ else:
26
+ print("SQL file was not found.")
27
+
28
+ def view_notebook(self):
29
+ from IPython.display import FileLink, display, HTML
30
+ import pygments
31
+ from pygments.lexers import SqlLexer
32
+ from pygments.formatters import HtmlFormatter
33
+
34
+ try:
35
+ with open(self.path, "r", encoding="utf-8") as f:
36
+ content = f.read()
37
+
38
+ formatter = HtmlFormatter(style="monokai")
39
+ highlighted_sql = pygments.highlight(content, SqlLexer(), formatter)
40
+ css = formatter.get_style_defs(".highlight")
41
+ display(HTML(f"<style>{css}</style>{highlighted_sql}"))
42
+ display(FileLink(self.path))
43
+ except Exception as e:
44
+ print(f"Error displaying SQL: {e}")
45
+
46
+ def _format_keywords(self, sql: str) -> str:
47
+ """Capitalize SQL keywords."""
48
+ keywords = {
49
+ "select",
50
+ "from",
51
+ "where",
52
+ "and",
53
+ "or",
54
+ "insert",
55
+ "update",
56
+ "delete",
57
+ "create",
58
+ "drop",
59
+ "alter",
60
+ "table",
61
+ "into",
62
+ "values",
63
+ "group",
64
+ "by",
65
+ "having",
66
+ "order",
67
+ "limit",
68
+ "join",
69
+ "left",
70
+ "right",
71
+ "inner",
72
+ "outer",
73
+ "on",
74
+ "as",
75
+ "distinct",
76
+ "count",
77
+ "sum",
78
+ "avg",
79
+ "max",
80
+ "min",
81
+ "between",
82
+ "like",
83
+ "in",
84
+ "is",
85
+ "null",
86
+ "not",
87
+ "case",
88
+ "when",
89
+ "then",
90
+ "else",
91
+ "end",
92
+ }
93
+
94
+ words = sql.split()
95
+ formatted_words = []
96
+ for word in words:
97
+ lower_word = word.lower()
98
+ if lower_word in keywords:
99
+ formatted_words.append(word.upper())
100
+ else:
101
+ formatted_words.append(word.lower())
102
+ return " ".join(formatted_words)
103
+
104
+ def _indent_sql(self, sql: str) -> str:
105
+ """Add basic indentation to SQL statement."""
106
+ lines = sql.split("\n")
107
+ indented_lines = []
108
+ indent_level = 0
109
+
110
+ for line in lines:
111
+ line = line.strip()
112
+
113
+ # Decrease indent for closing parentheses
114
+ if line.startswith(")"):
115
+ indent_level = max(0, indent_level - 1)
116
+
117
+ # Add indentation
118
+ if line:
119
+ indented_lines.append(" " * indent_level + line)
120
+ else:
121
+ indented_lines.append("")
122
+
123
+ # Increase indent after opening parentheses
124
+ if line.endswith("("):
125
+ indent_level += 1
126
+
127
+ # Special cases for common SQL clauses
128
+ lower_line = line.lower()
129
+ if any(
130
+ clause in lower_line
131
+ for clause in [
132
+ "select",
133
+ "from",
134
+ "where",
135
+ "group by",
136
+ "having",
137
+ "order by",
138
+ ]
139
+ ):
140
+ indent_level = 1
141
+
142
+ return "\n".join(indented_lines)
143
+
144
+ def format_sql(self) -> bool:
145
+ """Format the SQL file with proper indentation and keyword capitalization."""
146
+ try:
147
+ with open(self.path, "r", encoding="utf-8") as f:
148
+ content = f.read()
149
+
150
+ # Remove extra whitespace and format
151
+ content = " ".join(content.split())
152
+ content = self._format_keywords(content)
153
+ content = self._indent_sql(content)
154
+
155
+ # Wrap long lines
156
+ wrapped_content = []
157
+ for line in content.split("\n"):
158
+ if len(line) > 80:
159
+ wrapped_line = textwrap.fill(
160
+ line, width=80, subsequent_indent=" "
161
+ )
162
+ wrapped_content.append(wrapped_line)
163
+ else:
164
+ wrapped_content.append(line)
165
+
166
+ formatted_sql = "\n".join(wrapped_content)
167
+
168
+ with open(self.path, "w", encoding="utf-8") as f:
169
+ f.write(formatted_sql)
170
+
171
+ return True
172
+ except Exception as e:
173
+ print(f"Error formatting SQL: {e}")
174
+ return False
175
+
176
+ def split_statements(self) -> List[str]:
177
+ """Split the SQL file into individual statements."""
178
+ try:
179
+ with open(self.path, "r", encoding="utf-8") as f:
180
+ content = f.read()
181
+
182
+ # Handle both semicolon and GO statement terminators
183
+ statements = []
184
+ current_stmt = []
185
+
186
+ for line in content.split("\n"):
187
+ line = line.strip()
188
+
189
+ # Skip empty lines and comments
190
+ if not line or line.startswith("--"):
191
+ continue
192
+
193
+ if line.endswith(";"):
194
+ current_stmt.append(line[:-1]) # Remove semicolon
195
+ statements.append(" ".join(current_stmt))
196
+ current_stmt = []
197
+ elif line.upper() == "GO":
198
+ if current_stmt:
199
+ statements.append(" ".join(current_stmt))
200
+ current_stmt = []
201
+ else:
202
+ current_stmt.append(line)
203
+
204
+ # Add any remaining statement
205
+ if current_stmt:
206
+ statements.append(" ".join(current_stmt))
207
+
208
+ return [stmt.strip() for stmt in statements if stmt.strip()]
209
+ except Exception as e:
210
+ print(f"Error splitting SQL statements: {e}")
211
+ return []
212
+
213
+ def validate_basic_syntax(self) -> bool:
214
+ """
215
+ Perform basic SQL syntax validation.
216
+ This is a simple check and doesn't replace proper SQL parsing.
217
+ """
218
+ try:
219
+ with open(self.path, "r", encoding="utf-8") as f:
220
+ content = f.read()
221
+
222
+ statements = self.split_statements()
223
+ for stmt in statements:
224
+ # Check for basic SQL keywords
225
+ stmt_upper = stmt.upper()
226
+ if not any(
227
+ keyword in stmt_upper
228
+ for keyword in [
229
+ "SELECT",
230
+ "INSERT",
231
+ "UPDATE",
232
+ "DELETE",
233
+ "CREATE",
234
+ "DROP",
235
+ "ALTER",
236
+ ]
237
+ ):
238
+ print(f"Warning: Statement might be incomplete: {stmt}")
239
+
240
+ # Check for basic parentheses matching
241
+ if stmt.count("(") != stmt.count(")"):
242
+ print(f"Error: Unmatched parentheses in statement: {stmt}")
243
+ return False
244
+
245
+ # Check for basic quote matching
246
+ if stmt.count("'") % 2 != 0:
247
+ print(f"Error: Unmatched quotes in statement: {stmt}")
248
+ return False
249
+
250
+ return True
251
+ except Exception as e:
252
+ print(f"Error validating SQL: {e}")
253
+ return False
254
+
255
+ def extract_table_names(self) -> List[str]:
256
+ """Extract table names from the SQL file."""
257
+ tables = set()
258
+ try:
259
+ with open(self.path, "r", encoding="utf-8") as f:
260
+ content = f.read()
261
+
262
+ patterns = [
263
+ r"FROM\s+([a-zA-Z_][a-zA-Z0-9_]*)",
264
+ r"JOIN\s+([a-zA-Z_][a-zA-Z0-9_]*)",
265
+ r"UPDATE\s+([a-zA-Z_][a-zA-Z0-9_]*)",
266
+ r"INSERT\s+INTO\s+([a-zA-Z_][a-zA-Z0-9_]*)",
267
+ r"CREATE\s+TABLE\s+([a-zA-Z_][a-zA-Z0-9_]*)",
268
+ ]
269
+
270
+ for pattern in patterns:
271
+ tables.update(re.findall(pattern, content, re.IGNORECASE))
272
+
273
+ return sorted(list(tables))
274
+ except Exception as e:
275
+ print(f"Error extracting table names: {e}")
276
+ return []
277
+
278
+ def example(self):
279
+ sample_sql = """-- Sample SQL file with common operations
280
+ CREATE TABLE employees (
281
+ id INTEGER PRIMARY KEY,
282
+ name VARCHAR(100) NOT NULL,
283
+ department VARCHAR(50),
284
+ salary DECIMAL(10,2),
285
+ hire_date DATE
286
+ );
287
+
288
+ INSERT INTO employees (name, department, salary, hire_date)
289
+ VALUES
290
+ ('John Doe', 'Engineering', 75000.00, '2023-01-15'),
291
+ ('Jane Smith', 'Marketing', 65000.00, '2023-02-01');
292
+
293
+ -- Query to analyze employee data
294
+ SELECT
295
+ department,
296
+ COUNT(*) as employee_count,
297
+ AVG(salary) as avg_salary
298
+ FROM employees
299
+ GROUP BY department
300
+ HAVING COUNT(*) > 0
301
+ ORDER BY avg_salary DESC;
302
+
303
+ -- Update salary with conditions
304
+ UPDATE employees
305
+ SET salary = salary * 1.1
306
+ WHERE department = 'Engineering'
307
+ AND hire_date < '2024-01-01';
308
+ """
309
+ with tempfile.NamedTemporaryFile(
310
+ delete=False, suffix=".sql", mode="w", encoding="utf-8"
311
+ ) as f:
312
+ f.write(sample_sql)
313
+ return f.name
@@ -0,0 +1,149 @@
1
+ from edsl.scenarios.file_methods import FileMethods
2
+ import os
3
+ import tempfile
4
+ import sqlite3
5
+
6
+
7
+ class SQLiteMethods(FileMethods):
8
+ suffix = "db" # or "sqlite", depending on your preference
9
+
10
+ def extract_text(self):
11
+ """
12
+ Extracts a text representation of the database schema and table contents.
13
+ """
14
+ with sqlite3.connect(self.path) as conn:
15
+ cursor = conn.cursor()
16
+
17
+ # Get all table names
18
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
19
+ tables = cursor.fetchall()
20
+
21
+ full_text = []
22
+
23
+ # For each table, get schema and contents
24
+ for (table_name,) in tables:
25
+ # Get table schema
26
+ cursor.execute(
27
+ f"SELECT sql FROM sqlite_master WHERE type='table' AND name='{table_name}';"
28
+ )
29
+ schema = cursor.fetchone()[0]
30
+ full_text.append(f"Table: {table_name}")
31
+ full_text.append(f"Schema: {schema}")
32
+
33
+ # Get table contents
34
+ cursor.execute(f"SELECT * FROM {table_name};")
35
+ rows = cursor.fetchall()
36
+
37
+ # Get column names
38
+ column_names = [description[0] for description in cursor.description]
39
+ full_text.append(f"Columns: {', '.join(column_names)}")
40
+
41
+ # Add row data
42
+ for row in rows:
43
+ full_text.append(str(row))
44
+ full_text.append("\n")
45
+
46
+ return "\n".join(full_text)
47
+
48
+ def view_system(self):
49
+ """
50
+ Opens the database with the system's default SQLite viewer if available.
51
+ """
52
+ import os
53
+ import subprocess
54
+
55
+ if os.path.exists(self.path):
56
+ try:
57
+ if (os_name := os.name) == "posix":
58
+ # Try DB Browser for SQLite on macOS
59
+ subprocess.run(
60
+ ["open", "-a", "DB Browser for SQLite", self.path], check=True
61
+ )
62
+ elif os_name == "nt":
63
+ # Try DB Browser for SQLite on Windows
64
+ subprocess.run(["DB Browser for SQLite.exe", self.path], check=True)
65
+ else:
66
+ # Try sqlitebrowser on Linux
67
+ subprocess.run(["sqlitebrowser", self.path], check=True)
68
+ except Exception as e:
69
+ print(f"Error opening SQLite database: {e}")
70
+ else:
71
+ print("SQLite database file was not found.")
72
+
73
+ def view_notebook(self):
74
+ """
75
+ Displays database contents in a Jupyter notebook.
76
+ """
77
+ import pandas as pd
78
+ from IPython.display import HTML, display
79
+
80
+ with sqlite3.connect(self.path) as conn:
81
+ # Get all table names
82
+ cursor = conn.cursor()
83
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
84
+ tables = cursor.fetchall()
85
+
86
+ html_parts = []
87
+ for (table_name,) in tables:
88
+ # Read table into pandas DataFrame
89
+ df = pd.read_sql_query(f"SELECT * FROM {table_name}", conn)
90
+
91
+ # Convert to HTML with styling
92
+ table_html = f"""
93
+ <div style="margin-bottom: 20px;">
94
+ <h3>{table_name}</h3>
95
+ {df.to_html(index=False)}
96
+ </div>
97
+ """
98
+ html_parts.append(table_html)
99
+
100
+ # Combine all tables into one scrollable div
101
+ html = f"""
102
+ <div style="width: 800px; height: 800px; padding: 20px;
103
+ border: 1px solid #ccc; overflow-y: auto;">
104
+ {''.join(html_parts)}
105
+ </div>
106
+ """
107
+ display(HTML(html))
108
+
109
+ def example(self):
110
+ """
111
+ Creates an example SQLite database for testing.
112
+ """
113
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".db") as tmp:
114
+ conn = sqlite3.connect(tmp.name)
115
+ cursor = conn.cursor()
116
+
117
+ # Create a sample table
118
+ cursor.execute(
119
+ """
120
+ CREATE TABLE survey_responses (
121
+ id INTEGER PRIMARY KEY,
122
+ question TEXT,
123
+ response TEXT
124
+ )
125
+ """
126
+ )
127
+
128
+ # Insert some sample data
129
+ sample_data = [
130
+ (1, "First Survey Question", "Response 1"),
131
+ (2, "Second Survey Question", "Response 2"),
132
+ ]
133
+ cursor.executemany(
134
+ "INSERT INTO survey_responses (id, question, response) VALUES (?, ?, ?)",
135
+ sample_data,
136
+ )
137
+
138
+ conn.commit()
139
+ conn.close()
140
+ tmp.close()
141
+
142
+ return tmp.name
143
+
144
+
145
+ if __name__ == "__main__":
146
+ sqlite_temp = SQLiteMethods.example()
147
+ from edsl.scenarios.FileStore import FileStore
148
+
149
+ fs = FileStore(sqlite_temp)
@@ -0,0 +1,33 @@
1
+ from edsl.scenarios.file_methods import FileMethods
2
+ import tempfile
3
+
4
+
5
+ class TxtMethods(FileMethods):
6
+ suffix = "txt"
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 TXT: {e}")
22
+ else:
23
+ print("TXT file was not found.")
24
+
25
+ def view_notebook(self):
26
+ from IPython.display import FileLink, display
27
+
28
+ display(FileLink(self.path))
29
+
30
+ def example(self):
31
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as f:
32
+ f.write(b"Hello, World!")
33
+ return f.name
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+ from typing import Union, TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from edsl.scenarios.ScenarioList import ScenarioList
6
+ from edsl.scenarios.Scenario import Scenario
7
+
8
+
9
+ class ScenarioJoin:
10
+ """Handles join operations between two ScenarioLists.
11
+
12
+ This class encapsulates all join-related logic, making it easier to maintain
13
+ and extend with other join types (inner, right, full) in the future.
14
+ """
15
+
16
+ def __init__(self, left: "ScenarioList", right: "ScenarioList"):
17
+ """Initialize join operation with two ScenarioLists.
18
+
19
+ Args:
20
+ left: The left ScenarioList
21
+ right: The right ScenarioList
22
+ """
23
+ self.left = left
24
+ self.right = right
25
+
26
+ def left_join(self, by: Union[str, list[str]]) -> "ScenarioList":
27
+ """Perform a left join between the two ScenarioLists.
28
+
29
+ Args:
30
+ by: String or list of strings representing the key(s) to join on. Cannot be empty.
31
+
32
+ Returns:
33
+ A new ScenarioList containing the joined scenarios
34
+
35
+ Raises:
36
+ ValueError: If by is empty or if any join keys don't exist in both ScenarioLists
37
+ """
38
+ from edsl.scenarios.ScenarioList import ScenarioList
39
+
40
+ self._validate_join_keys(by)
41
+ by_keys = [by] if isinstance(by, str) else by
42
+
43
+ other_dict = self._create_lookup_dict(self.right, by_keys)
44
+ all_keys = self._get_all_keys()
45
+
46
+ return ScenarioList(
47
+ self._create_joined_scenarios(by_keys, other_dict, all_keys)
48
+ )
49
+
50
+ def _validate_join_keys(self, by: Union[str, list[str]]) -> None:
51
+ """Validate join keys exist in both ScenarioLists."""
52
+ if not by:
53
+ raise ValueError(
54
+ "Join keys cannot be empty. Please specify at least one key to join on."
55
+ )
56
+
57
+ by_keys = [by] if isinstance(by, str) else by
58
+ left_keys = set(next(iter(self.left)).keys()) if self.left else set()
59
+ right_keys = set(next(iter(self.right)).keys()) if self.right else set()
60
+
61
+ missing_left = set(by_keys) - left_keys
62
+ missing_right = set(by_keys) - right_keys
63
+ if missing_left or missing_right:
64
+ missing = missing_left | missing_right
65
+ raise ValueError(f"Join key(s) {missing} not found in both ScenarioLists")
66
+
67
+ @staticmethod
68
+ def _get_key_tuple(scenario: Scenario, keys: list[str]) -> tuple:
69
+ """Create a tuple of values for the join keys."""
70
+ return tuple(scenario[k] for k in keys)
71
+
72
+ def _create_lookup_dict(self, scenarios: ScenarioList, by_keys: list[str]) -> dict:
73
+ """Create a lookup dictionary for the right scenarios."""
74
+ return {
75
+ self._get_key_tuple(scenario, by_keys): scenario for scenario in scenarios
76
+ }
77
+
78
+ def _get_all_keys(self) -> set:
79
+ """Get all unique keys from both ScenarioLists."""
80
+ all_keys = set()
81
+ for scenario in self.left:
82
+ all_keys.update(scenario.keys())
83
+ for scenario in self.right:
84
+ all_keys.update(scenario.keys())
85
+ return all_keys
86
+
87
+ def _create_joined_scenarios(
88
+ self, by_keys: list[str], other_dict: dict, all_keys: set
89
+ ) -> list[Scenario]:
90
+ """Create the joined scenarios."""
91
+ from edsl.scenarios.Scenario import Scenario
92
+
93
+ new_scenarios = []
94
+
95
+ for scenario in self.left:
96
+ new_scenario = {key: None for key in all_keys}
97
+ new_scenario.update(scenario)
98
+
99
+ key_tuple = self._get_key_tuple(scenario, by_keys)
100
+ if matching_scenario := other_dict.get(key_tuple):
101
+ self._handle_matching_scenario(
102
+ new_scenario, scenario, matching_scenario, by_keys
103
+ )
104
+
105
+ new_scenarios.append(Scenario(new_scenario))
106
+
107
+ return new_scenarios
108
+
109
+ def _handle_matching_scenario(
110
+ self,
111
+ new_scenario: dict,
112
+ left_scenario: "Scenario",
113
+ right_scenario: "Scenario",
114
+ by_keys: list[str],
115
+ ) -> None:
116
+ """Handle merging of matching scenarios and conflict warnings."""
117
+ overlapping_keys = set(left_scenario.keys()) & set(right_scenario.keys())
118
+
119
+ for key in overlapping_keys:
120
+ if key not in by_keys and left_scenario[key] != right_scenario[key]:
121
+ join_conditions = [f"{k}='{left_scenario[k]}'" for k in by_keys]
122
+ print(
123
+ f"Warning: Conflicting values for key '{key}' where "
124
+ f"{' AND '.join(join_conditions)}. "
125
+ f"Keeping left value: {left_scenario[key]} "
126
+ f"(discarding: {right_scenario[key]})"
127
+ )
128
+
129
+ # Only update with non-overlapping keys from matching scenario
130
+ new_keys = set(right_scenario.keys()) - set(left_scenario.keys())
131
+ new_scenario.update({k: right_scenario[k] for k in new_keys})