edsl 0.1.39.dev2__py3-none-any.whl → 0.1.39.dev3__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 (334) hide show
  1. edsl/Base.py +332 -385
  2. edsl/BaseDiff.py +260 -260
  3. edsl/TemplateLoader.py +24 -24
  4. edsl/__init__.py +49 -57
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +867 -1079
  7. edsl/agents/AgentList.py +413 -551
  8. edsl/agents/Invigilator.py +233 -285
  9. edsl/agents/InvigilatorBase.py +270 -254
  10. edsl/agents/PromptConstructor.py +354 -252
  11. edsl/agents/__init__.py +3 -2
  12. edsl/agents/descriptors.py +99 -99
  13. edsl/agents/prompt_helpers.py +129 -129
  14. edsl/auto/AutoStudy.py +117 -117
  15. edsl/auto/StageBase.py +230 -230
  16. edsl/auto/StageGenerateSurvey.py +178 -178
  17. edsl/auto/StageLabelQuestions.py +125 -125
  18. edsl/auto/StagePersona.py +61 -61
  19. edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
  20. edsl/auto/StagePersonaDimensionValues.py +74 -74
  21. edsl/auto/StagePersonaDimensions.py +69 -69
  22. edsl/auto/StageQuestions.py +73 -73
  23. edsl/auto/SurveyCreatorPipeline.py +21 -21
  24. edsl/auto/utilities.py +224 -224
  25. edsl/base/Base.py +279 -279
  26. edsl/config.py +157 -177
  27. edsl/conversation/Conversation.py +290 -290
  28. edsl/conversation/car_buying.py +58 -59
  29. edsl/conversation/chips.py +95 -95
  30. edsl/conversation/mug_negotiation.py +81 -81
  31. edsl/conversation/next_speaker_utilities.py +93 -93
  32. edsl/coop/PriceFetcher.py +54 -54
  33. edsl/coop/__init__.py +2 -2
  34. edsl/coop/coop.py +1028 -1090
  35. edsl/coop/utils.py +131 -131
  36. edsl/data/Cache.py +555 -562
  37. edsl/data/CacheEntry.py +233 -230
  38. edsl/data/CacheHandler.py +149 -170
  39. edsl/data/RemoteCacheSync.py +78 -78
  40. edsl/data/SQLiteDict.py +292 -292
  41. edsl/data/__init__.py +4 -5
  42. edsl/data/orm.py +10 -10
  43. edsl/data_transfer_models.py +73 -74
  44. edsl/enums.py +175 -195
  45. edsl/exceptions/BaseException.py +21 -21
  46. edsl/exceptions/__init__.py +54 -54
  47. edsl/exceptions/agents.py +42 -54
  48. edsl/exceptions/cache.py +5 -5
  49. edsl/exceptions/configuration.py +16 -16
  50. edsl/exceptions/coop.py +10 -10
  51. edsl/exceptions/data.py +14 -14
  52. edsl/exceptions/general.py +34 -34
  53. edsl/exceptions/jobs.py +33 -33
  54. edsl/exceptions/language_models.py +63 -63
  55. edsl/exceptions/prompts.py +15 -15
  56. edsl/exceptions/questions.py +91 -109
  57. edsl/exceptions/results.py +29 -29
  58. edsl/exceptions/scenarios.py +22 -29
  59. edsl/exceptions/surveys.py +37 -37
  60. edsl/inference_services/AnthropicService.py +87 -84
  61. edsl/inference_services/AwsBedrock.py +120 -118
  62. edsl/inference_services/AzureAI.py +217 -215
  63. edsl/inference_services/DeepInfraService.py +18 -18
  64. edsl/inference_services/GoogleService.py +148 -139
  65. edsl/inference_services/GroqService.py +20 -20
  66. edsl/inference_services/InferenceServiceABC.py +147 -80
  67. edsl/inference_services/InferenceServicesCollection.py +97 -122
  68. edsl/inference_services/MistralAIService.py +123 -120
  69. edsl/inference_services/OllamaService.py +18 -18
  70. edsl/inference_services/OpenAIService.py +224 -221
  71. edsl/inference_services/PerplexityService.py +163 -160
  72. edsl/inference_services/TestService.py +89 -92
  73. edsl/inference_services/TogetherAIService.py +170 -170
  74. edsl/inference_services/models_available_cache.py +118 -118
  75. edsl/inference_services/rate_limits_cache.py +25 -25
  76. edsl/inference_services/registry.py +41 -41
  77. edsl/inference_services/write_available.py +10 -10
  78. edsl/jobs/Answers.py +56 -43
  79. edsl/jobs/Jobs.py +898 -757
  80. edsl/jobs/JobsChecks.py +147 -172
  81. edsl/jobs/JobsPrompts.py +268 -270
  82. edsl/jobs/JobsRemoteInferenceHandler.py +239 -287
  83. edsl/jobs/__init__.py +1 -1
  84. edsl/jobs/buckets/BucketCollection.py +63 -104
  85. edsl/jobs/buckets/ModelBuckets.py +65 -65
  86. edsl/jobs/buckets/TokenBucket.py +251 -283
  87. edsl/jobs/interviews/Interview.py +661 -358
  88. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
  89. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
  90. edsl/jobs/interviews/InterviewStatistic.py +63 -63
  91. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
  92. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
  93. edsl/jobs/interviews/InterviewStatusLog.py +92 -92
  94. edsl/jobs/interviews/ReportErrors.py +66 -66
  95. edsl/jobs/interviews/interview_status_enum.py +9 -9
  96. edsl/jobs/runners/JobsRunnerAsyncio.py +466 -421
  97. edsl/jobs/runners/JobsRunnerStatus.py +330 -330
  98. edsl/jobs/tasks/QuestionTaskCreator.py +242 -244
  99. edsl/jobs/tasks/TaskCreators.py +64 -64
  100. edsl/jobs/tasks/TaskHistory.py +450 -449
  101. edsl/jobs/tasks/TaskStatusLog.py +23 -23
  102. edsl/jobs/tasks/task_status_enum.py +163 -161
  103. edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
  104. edsl/jobs/tokens/TokenUsage.py +34 -34
  105. edsl/language_models/KeyLookup.py +30 -0
  106. edsl/language_models/LanguageModel.py +668 -571
  107. edsl/language_models/ModelList.py +155 -153
  108. edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
  109. edsl/language_models/__init__.py +3 -2
  110. edsl/language_models/fake_openai_call.py +15 -15
  111. edsl/language_models/fake_openai_service.py +61 -61
  112. edsl/language_models/registry.py +190 -180
  113. edsl/language_models/repair.py +156 -156
  114. edsl/language_models/unused/ReplicateBase.py +83 -0
  115. edsl/language_models/utilities.py +64 -65
  116. edsl/notebooks/Notebook.py +258 -263
  117. edsl/notebooks/__init__.py +1 -1
  118. edsl/prompts/Prompt.py +362 -352
  119. edsl/prompts/__init__.py +2 -2
  120. edsl/questions/AnswerValidatorMixin.py +289 -334
  121. edsl/questions/QuestionBase.py +664 -509
  122. edsl/questions/QuestionBaseGenMixin.py +161 -165
  123. edsl/questions/QuestionBasePromptsMixin.py +217 -221
  124. edsl/questions/QuestionBudget.py +227 -227
  125. edsl/questions/QuestionCheckBox.py +359 -359
  126. edsl/questions/QuestionExtract.py +182 -182
  127. edsl/questions/QuestionFreeText.py +114 -113
  128. edsl/questions/QuestionFunctional.py +166 -166
  129. edsl/questions/QuestionList.py +231 -229
  130. edsl/questions/QuestionMultipleChoice.py +286 -330
  131. edsl/questions/QuestionNumerical.py +153 -151
  132. edsl/questions/QuestionRank.py +324 -314
  133. edsl/questions/Quick.py +41 -41
  134. edsl/questions/RegisterQuestionsMeta.py +71 -71
  135. edsl/questions/ResponseValidatorABC.py +174 -200
  136. edsl/questions/SimpleAskMixin.py +73 -74
  137. edsl/questions/__init__.py +26 -27
  138. edsl/questions/compose_questions.py +98 -98
  139. edsl/questions/decorators.py +21 -21
  140. edsl/questions/derived/QuestionLikertFive.py +76 -76
  141. edsl/questions/derived/QuestionLinearScale.py +87 -90
  142. edsl/questions/derived/QuestionTopK.py +93 -93
  143. edsl/questions/derived/QuestionYesNo.py +82 -82
  144. edsl/questions/descriptors.py +413 -427
  145. edsl/questions/prompt_templates/question_budget.jinja +13 -13
  146. edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
  147. edsl/questions/prompt_templates/question_extract.jinja +11 -11
  148. edsl/questions/prompt_templates/question_free_text.jinja +3 -3
  149. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
  150. edsl/questions/prompt_templates/question_list.jinja +17 -17
  151. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
  152. edsl/questions/prompt_templates/question_numerical.jinja +36 -36
  153. edsl/questions/question_registry.py +177 -177
  154. edsl/questions/settings.py +12 -12
  155. edsl/questions/templates/budget/answering_instructions.jinja +7 -7
  156. edsl/questions/templates/budget/question_presentation.jinja +7 -7
  157. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
  158. edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
  159. edsl/questions/templates/extract/answering_instructions.jinja +7 -7
  160. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
  161. edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
  162. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
  163. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
  164. edsl/questions/templates/list/answering_instructions.jinja +3 -3
  165. edsl/questions/templates/list/question_presentation.jinja +5 -5
  166. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
  167. edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
  168. edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
  169. edsl/questions/templates/numerical/question_presentation.jinja +6 -6
  170. edsl/questions/templates/rank/answering_instructions.jinja +11 -11
  171. edsl/questions/templates/rank/question_presentation.jinja +15 -15
  172. edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
  173. edsl/questions/templates/top_k/question_presentation.jinja +22 -22
  174. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
  175. edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
  176. edsl/results/CSSParameterizer.py +108 -108
  177. edsl/results/Dataset.py +424 -587
  178. edsl/results/DatasetExportMixin.py +731 -653
  179. edsl/results/DatasetTree.py +275 -295
  180. edsl/results/Result.py +465 -451
  181. edsl/results/Results.py +1165 -1172
  182. edsl/results/ResultsDBMixin.py +238 -0
  183. edsl/results/ResultsExportMixin.py +43 -45
  184. edsl/results/ResultsFetchMixin.py +33 -33
  185. edsl/results/ResultsGGMixin.py +121 -121
  186. edsl/results/ResultsToolsMixin.py +98 -98
  187. edsl/results/Selector.py +135 -145
  188. edsl/results/TableDisplay.py +198 -125
  189. edsl/results/__init__.py +2 -2
  190. edsl/results/table_display.css +77 -77
  191. edsl/results/tree_explore.py +115 -115
  192. edsl/scenarios/FileStore.py +632 -511
  193. edsl/scenarios/Scenario.py +601 -498
  194. edsl/scenarios/ScenarioHtmlMixin.py +64 -65
  195. edsl/scenarios/ScenarioJoin.py +127 -131
  196. edsl/scenarios/ScenarioList.py +1287 -1430
  197. edsl/scenarios/ScenarioListExportMixin.py +52 -45
  198. edsl/scenarios/ScenarioListPdfMixin.py +261 -239
  199. edsl/scenarios/__init__.py +4 -3
  200. edsl/shared.py +1 -1
  201. edsl/study/ObjectEntry.py +173 -173
  202. edsl/study/ProofOfWork.py +113 -113
  203. edsl/study/SnapShot.py +80 -80
  204. edsl/study/Study.py +528 -521
  205. edsl/study/__init__.py +4 -4
  206. edsl/surveys/DAG.py +148 -148
  207. edsl/surveys/Memory.py +31 -31
  208. edsl/surveys/MemoryPlan.py +244 -244
  209. edsl/surveys/Rule.py +326 -327
  210. edsl/surveys/RuleCollection.py +387 -385
  211. edsl/surveys/Survey.py +1801 -1229
  212. edsl/surveys/SurveyCSS.py +261 -273
  213. edsl/surveys/SurveyExportMixin.py +259 -259
  214. edsl/surveys/{SurveyFlowVisualization.py → SurveyFlowVisualizationMixin.py} +179 -181
  215. edsl/surveys/SurveyQualtricsImport.py +284 -284
  216. edsl/surveys/__init__.py +3 -5
  217. edsl/surveys/base.py +53 -53
  218. edsl/surveys/descriptors.py +56 -60
  219. edsl/surveys/instructions/ChangeInstruction.py +49 -48
  220. edsl/surveys/instructions/Instruction.py +65 -56
  221. edsl/surveys/instructions/InstructionCollection.py +77 -82
  222. edsl/templates/error_reporting/base.html +23 -23
  223. edsl/templates/error_reporting/exceptions_by_model.html +34 -34
  224. edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
  225. edsl/templates/error_reporting/exceptions_by_type.html +16 -16
  226. edsl/templates/error_reporting/interview_details.html +115 -115
  227. edsl/templates/error_reporting/interviews.html +19 -19
  228. edsl/templates/error_reporting/overview.html +4 -4
  229. edsl/templates/error_reporting/performance_plot.html +1 -1
  230. edsl/templates/error_reporting/report.css +73 -73
  231. edsl/templates/error_reporting/report.html +117 -117
  232. edsl/templates/error_reporting/report.js +25 -25
  233. edsl/tools/__init__.py +1 -1
  234. edsl/tools/clusters.py +192 -192
  235. edsl/tools/embeddings.py +27 -27
  236. edsl/tools/embeddings_plotting.py +118 -118
  237. edsl/tools/plotting.py +112 -112
  238. edsl/tools/summarize.py +18 -18
  239. edsl/utilities/SystemInfo.py +28 -28
  240. edsl/utilities/__init__.py +22 -22
  241. edsl/utilities/ast_utilities.py +25 -25
  242. edsl/utilities/data/Registry.py +6 -6
  243. edsl/utilities/data/__init__.py +1 -1
  244. edsl/utilities/data/scooter_results.json +1 -1
  245. edsl/utilities/decorators.py +77 -77
  246. edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
  247. edsl/utilities/interface.py +627 -627
  248. edsl/utilities/naming_utilities.py +263 -263
  249. edsl/utilities/repair_functions.py +28 -28
  250. edsl/utilities/restricted_python.py +70 -70
  251. edsl/utilities/utilities.py +424 -436
  252. {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/LICENSE +21 -21
  253. {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/METADATA +10 -12
  254. edsl-0.1.39.dev3.dist-info/RECORD +277 -0
  255. edsl/agents/QuestionInstructionPromptBuilder.py +0 -128
  256. edsl/agents/QuestionOptionProcessor.py +0 -172
  257. edsl/agents/QuestionTemplateReplacementsBuilder.py +0 -137
  258. edsl/coop/CoopFunctionsMixin.py +0 -15
  259. edsl/coop/ExpectedParrotKeyHandler.py +0 -125
  260. edsl/exceptions/inference_services.py +0 -5
  261. edsl/inference_services/AvailableModelCacheHandler.py +0 -184
  262. edsl/inference_services/AvailableModelFetcher.py +0 -209
  263. edsl/inference_services/ServiceAvailability.py +0 -135
  264. edsl/inference_services/data_structures.py +0 -62
  265. edsl/jobs/AnswerQuestionFunctionConstructor.py +0 -188
  266. edsl/jobs/FetchInvigilator.py +0 -40
  267. edsl/jobs/InterviewTaskManager.py +0 -98
  268. edsl/jobs/InterviewsConstructor.py +0 -48
  269. edsl/jobs/JobsComponentConstructor.py +0 -189
  270. edsl/jobs/JobsRemoteInferenceLogger.py +0 -239
  271. edsl/jobs/RequestTokenEstimator.py +0 -30
  272. edsl/jobs/buckets/TokenBucketAPI.py +0 -211
  273. edsl/jobs/buckets/TokenBucketClient.py +0 -191
  274. edsl/jobs/decorators.py +0 -35
  275. edsl/jobs/jobs_status_enums.py +0 -9
  276. edsl/jobs/loggers/HTMLTableJobLogger.py +0 -304
  277. edsl/language_models/ComputeCost.py +0 -63
  278. edsl/language_models/PriceManager.py +0 -127
  279. edsl/language_models/RawResponseHandler.py +0 -106
  280. edsl/language_models/ServiceDataSources.py +0 -0
  281. edsl/language_models/key_management/KeyLookup.py +0 -63
  282. edsl/language_models/key_management/KeyLookupBuilder.py +0 -273
  283. edsl/language_models/key_management/KeyLookupCollection.py +0 -38
  284. edsl/language_models/key_management/__init__.py +0 -0
  285. edsl/language_models/key_management/models.py +0 -131
  286. edsl/notebooks/NotebookToLaTeX.py +0 -142
  287. edsl/questions/ExceptionExplainer.py +0 -77
  288. edsl/questions/HTMLQuestion.py +0 -103
  289. edsl/questions/LoopProcessor.py +0 -149
  290. edsl/questions/QuestionMatrix.py +0 -265
  291. edsl/questions/ResponseValidatorFactory.py +0 -28
  292. edsl/questions/templates/matrix/__init__.py +0 -1
  293. edsl/questions/templates/matrix/answering_instructions.jinja +0 -5
  294. edsl/questions/templates/matrix/question_presentation.jinja +0 -20
  295. edsl/results/MarkdownToDocx.py +0 -122
  296. edsl/results/MarkdownToPDF.py +0 -111
  297. edsl/results/TextEditor.py +0 -50
  298. edsl/results/smart_objects.py +0 -96
  299. edsl/results/table_data_class.py +0 -12
  300. edsl/results/table_renderers.py +0 -118
  301. edsl/scenarios/ConstructDownloadLink.py +0 -109
  302. edsl/scenarios/DirectoryScanner.py +0 -96
  303. edsl/scenarios/DocumentChunker.py +0 -102
  304. edsl/scenarios/DocxScenario.py +0 -16
  305. edsl/scenarios/PdfExtractor.py +0 -40
  306. edsl/scenarios/ScenarioSelector.py +0 -156
  307. edsl/scenarios/file_methods.py +0 -85
  308. edsl/scenarios/handlers/__init__.py +0 -13
  309. edsl/scenarios/handlers/csv.py +0 -38
  310. edsl/scenarios/handlers/docx.py +0 -76
  311. edsl/scenarios/handlers/html.py +0 -37
  312. edsl/scenarios/handlers/json.py +0 -111
  313. edsl/scenarios/handlers/latex.py +0 -5
  314. edsl/scenarios/handlers/md.py +0 -51
  315. edsl/scenarios/handlers/pdf.py +0 -68
  316. edsl/scenarios/handlers/png.py +0 -39
  317. edsl/scenarios/handlers/pptx.py +0 -105
  318. edsl/scenarios/handlers/py.py +0 -294
  319. edsl/scenarios/handlers/sql.py +0 -313
  320. edsl/scenarios/handlers/sqlite.py +0 -149
  321. edsl/scenarios/handlers/txt.py +0 -33
  322. edsl/surveys/ConstructDAG.py +0 -92
  323. edsl/surveys/EditSurvey.py +0 -221
  324. edsl/surveys/InstructionHandler.py +0 -100
  325. edsl/surveys/MemoryManagement.py +0 -72
  326. edsl/surveys/RuleManager.py +0 -172
  327. edsl/surveys/Simulator.py +0 -75
  328. edsl/surveys/SurveyToApp.py +0 -141
  329. edsl/utilities/PrettyList.py +0 -56
  330. edsl/utilities/is_notebook.py +0 -18
  331. edsl/utilities/is_valid_variable_name.py +0 -11
  332. edsl/utilities/remove_edsl_version.py +0 -24
  333. edsl-0.1.39.dev2.dist-info/RECORD +0 -352
  334. {edsl-0.1.39.dev2.dist-info → edsl-0.1.39.dev3.dist-info}/WHEEL +0 -0
@@ -1,313 +0,0 @@
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
@@ -1,149 +0,0 @@
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)
@@ -1,33 +0,0 @@
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
@@ -1,92 +0,0 @@
1
- from edsl.surveys.base import EndOfSurvey
2
- from edsl.surveys.DAG import DAG
3
- from edsl.exceptions.surveys import SurveyError
4
-
5
-
6
- class ConstructDAG:
7
- def __init__(self, survey):
8
- self.survey = survey
9
- self.questions = survey.questions
10
-
11
- self.parameters_by_question = self.survey.parameters_by_question
12
- self.question_name_to_index = self.survey.question_name_to_index
13
-
14
- def dag(self, textify: bool = False) -> DAG:
15
- memory_dag = self.survey.memory_plan.dag
16
- rule_dag = self.survey.rule_collection.dag
17
- piping_dag = self.piping_dag
18
- if textify:
19
- memory_dag = DAG(self.textify(memory_dag))
20
- rule_dag = DAG(self.textify(rule_dag))
21
- piping_dag = DAG(self.textify(piping_dag))
22
- return memory_dag + rule_dag + piping_dag
23
-
24
- @property
25
- def piping_dag(self) -> DAG:
26
- """Figures out the DAG of piping dependencies.
27
-
28
- >>> from edsl import Survey
29
- >>> from edsl import QuestionFreeText
30
- >>> q0 = QuestionFreeText(question_text="Here is a question", question_name="q0")
31
- >>> q1 = QuestionFreeText(question_text="You previously answered {{ q0 }}---how do you feel now?", question_name="q1")
32
- >>> s = Survey([q0, q1])
33
- >>> ConstructDAG(s).piping_dag
34
- {1: {0}}
35
- """
36
- d = {}
37
- for question_name, depenencies in self.parameters_by_question.items():
38
- if depenencies:
39
- question_index = self.question_name_to_index[question_name]
40
- for dependency in depenencies:
41
- if dependency not in self.question_name_to_index:
42
- pass
43
- else:
44
- dependency_index = self.question_name_to_index[dependency]
45
- if question_index not in d:
46
- d[question_index] = set()
47
- d[question_index].add(dependency_index)
48
- return d
49
-
50
- def textify(self, index_dag: DAG) -> DAG:
51
- """Convert the DAG of question indices to a DAG of question names.
52
-
53
- :param index_dag: The DAG of question indices.
54
-
55
- Example:
56
-
57
- >>> from edsl import Survey
58
- >>> s = Survey.example()
59
- >>> d = s.dag()
60
- >>> d
61
- {1: {0}, 2: {0}}
62
- >>> ConstructDAG(s).textify(d)
63
- {'q1': {'q0'}, 'q2': {'q0'}}
64
- """
65
-
66
- def get_name(index: int):
67
- """Return the name of the question given the index."""
68
- if index >= len(self.questions):
69
- return EndOfSurvey
70
- try:
71
- return self.questions[index].question_name
72
- except IndexError:
73
- print(
74
- f"The index is {index} but the length of the questions is {len(self.questions)}"
75
- )
76
- raise SurveyError
77
-
78
- try:
79
- text_dag = {}
80
- for child_index, parent_indices in index_dag.items():
81
- parent_names = {get_name(index) for index in parent_indices}
82
- child_name = get_name(child_index)
83
- text_dag[child_name] = parent_names
84
- return text_dag
85
- except IndexError:
86
- raise
87
-
88
-
89
- if __name__ == "__main__":
90
- import doctest
91
-
92
- doctest.testmod()