edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev4__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.
- edsl/Base.py +413 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +57 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +1071 -867
- edsl/agents/AgentList.py +551 -413
- edsl/agents/Invigilator.py +284 -233
- edsl/agents/InvigilatorBase.py +257 -270
- edsl/agents/PromptConstructor.py +272 -354
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +2 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -117
- edsl/auto/StageBase.py +243 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +74 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +218 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +177 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +59 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1106 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +573 -555
- edsl/data/CacheEntry.py +230 -233
- edsl/data/CacheHandler.py +168 -149
- edsl/data/RemoteCacheSync.py +186 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +5 -4
- edsl/data/hack.py +10 -0
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +74 -73
- edsl/enums.py +202 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +54 -42
- edsl/exceptions/cache.py +5 -5
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +109 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +29 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +106 -87
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -120
- edsl/inference_services/AzureAI.py +215 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +143 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +80 -147
- edsl/inference_services/InferenceServicesCollection.py +138 -97
- edsl/inference_services/MistralAIService.py +120 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +236 -224
- edsl/inference_services/PerplexityService.py +160 -163
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -89
- edsl/inference_services/TogetherAIService.py +172 -170
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +43 -56
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +823 -898
- edsl/jobs/JobsChecks.py +172 -147
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +283 -251
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +396 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
- edsl/jobs/runners/JobsRunnerStatus.py +297 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +470 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +161 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +626 -668
- edsl/language_models/ModelList.py +164 -155
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +2 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +156 -156
- edsl/language_models/utilities.py +65 -64
- edsl/notebooks/Notebook.py +263 -258
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +352 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -664
- edsl/questions/QuestionBasePromptsMixin.py +221 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +180 -182
- edsl/questions/QuestionFreeText.py +113 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +223 -231
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +330 -286
- edsl/questions/QuestionNumerical.py +151 -153
- edsl/questions/QuestionRank.py +314 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/SimpleAskMixin.py +74 -73
- edsl/questions/__init__.py +27 -26
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +90 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +427 -413
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
- edsl/questions/question_registry.py +177 -177
- edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -108
- edsl/results/Dataset.py +587 -424
- edsl/results/DatasetExportMixin.py +594 -731
- edsl/results/DatasetTree.py +295 -275
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +557 -465
- edsl/results/Results.py +1183 -1165
- edsl/results/ResultsExportMixin.py +45 -43
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/TableDisplay.py +125 -198
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +2 -2
- edsl/results/file_exports.py +252 -0
- edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
- edsl/results/{Selector.py → results_selector.py} +145 -135
- edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +77 -77
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +511 -632
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +498 -601
- edsl/scenarios/ScenarioHtmlMixin.py +65 -64
- edsl/scenarios/ScenarioList.py +1458 -1287
- edsl/scenarios/ScenarioListExportMixin.py +45 -52
- edsl/scenarios/ScenarioListPdfMixin.py +239 -261
- edsl/scenarios/__init__.py +3 -4
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +38 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +521 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +327 -326
- edsl/surveys/RuleCollection.py +385 -387
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1280 -1801
- edsl/surveys/SurveyCSS.py +273 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +5 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +60 -56
- edsl/surveys/instructions/ChangeInstruction.py +48 -49
- edsl/surveys/instructions/Instruction.py +56 -65
- edsl/surveys/instructions/InstructionCollection.py +82 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -19
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/test_h +1 -0
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/gcp_bucket/example.py +50 -0
- edsl/utilities/interface.py +627 -627
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +436 -424
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/METADATA +13 -11
- edsl-0.1.39.dev4.dist-info/RECORD +361 -0
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.39.dev3.dist-info/RECORD +0 -277
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
from edsl.scenarios.file_methods import FileMethods
|
2
|
+
import os
|
3
|
+
import tempfile
|
4
|
+
|
5
|
+
|
6
|
+
class PptxMethods(FileMethods):
|
7
|
+
suffix = "pptx"
|
8
|
+
|
9
|
+
def extract_text(self):
|
10
|
+
from pptx import Presentation
|
11
|
+
|
12
|
+
self.ppt = Presentation(self.path)
|
13
|
+
|
14
|
+
# Extract all text from slides
|
15
|
+
full_text = []
|
16
|
+
for slide in self.ppt.slides:
|
17
|
+
slide_text = []
|
18
|
+
for shape in slide.shapes:
|
19
|
+
if hasattr(shape, "text"):
|
20
|
+
slide_text.append(shape.text)
|
21
|
+
full_text.append("\n".join(slide_text))
|
22
|
+
|
23
|
+
text = "\n\n".join(full_text)
|
24
|
+
return text
|
25
|
+
|
26
|
+
def view_system(self):
|
27
|
+
import os
|
28
|
+
import subprocess
|
29
|
+
|
30
|
+
if os.path.exists(self.path):
|
31
|
+
try:
|
32
|
+
if (os_name := os.name) == "posix":
|
33
|
+
subprocess.run(["open", self.path], check=True) # macOS
|
34
|
+
elif os_name == "nt":
|
35
|
+
os.startfile(self.path) # Windows
|
36
|
+
else:
|
37
|
+
subprocess.run(["xdg-open", self.path], check=True) # Linux
|
38
|
+
except Exception as e:
|
39
|
+
print(f"Error opening PPTX: {e}")
|
40
|
+
else:
|
41
|
+
print("PPTX file was not found.")
|
42
|
+
|
43
|
+
def view_notebook(self):
|
44
|
+
from pptx import Presentation
|
45
|
+
from IPython.display import HTML, display
|
46
|
+
|
47
|
+
prs = Presentation(self.path)
|
48
|
+
|
49
|
+
# Create a simple HTML representation of the slides
|
50
|
+
html_content = []
|
51
|
+
for i, slide in enumerate(prs.slides, 1):
|
52
|
+
slide_content = []
|
53
|
+
for shape in slide.shapes:
|
54
|
+
if hasattr(shape, "text"):
|
55
|
+
slide_content.append(f"<p>{shape.text}</p>")
|
56
|
+
|
57
|
+
html_content.append(
|
58
|
+
f"""
|
59
|
+
<div style='border: 1px solid #ccc; margin: 10px; padding: 10px;'>
|
60
|
+
<h3>Slide {i}</h3>
|
61
|
+
{''.join(slide_content)}
|
62
|
+
</div>
|
63
|
+
"""
|
64
|
+
)
|
65
|
+
|
66
|
+
html = f"""
|
67
|
+
<div style="width: 800px; height: 800px; padding: 20px;
|
68
|
+
border: 1px solid #ccc; overflow-y: auto;">
|
69
|
+
{''.join(html_content)}
|
70
|
+
</div>
|
71
|
+
"""
|
72
|
+
display(HTML(html))
|
73
|
+
|
74
|
+
def example(self):
|
75
|
+
from pptx import Presentation
|
76
|
+
from edsl.scenarios.Scenario import Scenario
|
77
|
+
from edsl.scenarios.ScenarioList import ScenarioList
|
78
|
+
|
79
|
+
os.makedirs("test_dir", exist_ok=True)
|
80
|
+
|
81
|
+
# Create first presentation
|
82
|
+
ppt1 = Presentation()
|
83
|
+
slide = ppt1.slides.add_slide(ppt1.slide_layouts[0])
|
84
|
+
title = slide.shapes.title
|
85
|
+
title.text = "First Presentation"
|
86
|
+
ppt1.save("test_dir/test1.pptx")
|
87
|
+
|
88
|
+
# Create second presentation
|
89
|
+
ppt2 = Presentation()
|
90
|
+
slide = ppt2.slides.add_slide(ppt2.slide_layouts[0])
|
91
|
+
title = slide.shapes.title
|
92
|
+
title.text = "Second Presentation"
|
93
|
+
|
94
|
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".pptx") as tmp:
|
95
|
+
ppt2.save(tmp.name)
|
96
|
+
tmp.close()
|
97
|
+
|
98
|
+
return tmp.name
|
99
|
+
|
100
|
+
|
101
|
+
if __name__ == "__main__":
|
102
|
+
pptx_temp = PptxMethods.example()
|
103
|
+
from edsl.scenarios.FileStore import FileStore
|
104
|
+
|
105
|
+
fs = FileStore(pptx_temp)
|
@@ -0,0 +1,294 @@
|
|
1
|
+
from edsl.scenarios.file_methods import FileMethods
|
2
|
+
import tempfile
|
3
|
+
import re
|
4
|
+
from typing import List, Optional, Dict
|
5
|
+
import ast
|
6
|
+
import black
|
7
|
+
import textwrap
|
8
|
+
import subprocess
|
9
|
+
import sys
|
10
|
+
from importlib import util
|
11
|
+
|
12
|
+
|
13
|
+
class PyMethods(FileMethods):
|
14
|
+
suffix = "py"
|
15
|
+
|
16
|
+
def view_system(self):
|
17
|
+
"""Open the Python file in the system's default editor."""
|
18
|
+
import os
|
19
|
+
import subprocess
|
20
|
+
|
21
|
+
if os.path.exists(self.path):
|
22
|
+
try:
|
23
|
+
if (os_name := os.name) == "posix":
|
24
|
+
subprocess.run(["open", self.path], check=True) # macOS
|
25
|
+
elif os_name == "nt":
|
26
|
+
os.startfile(self.path) # Windows
|
27
|
+
else:
|
28
|
+
subprocess.run(["xdg-open", self.path], check=True) # Linux
|
29
|
+
except Exception as e:
|
30
|
+
print(f"Error opening Python file: {e}")
|
31
|
+
else:
|
32
|
+
print("Python file was not found.")
|
33
|
+
|
34
|
+
def view_notebook(self):
|
35
|
+
"""Display the Python file with syntax highlighting in a notebook."""
|
36
|
+
from IPython.display import FileLink, display, HTML
|
37
|
+
import pygments
|
38
|
+
from pygments.lexers import PythonLexer
|
39
|
+
from pygments.formatters import HtmlFormatter
|
40
|
+
from pygments.styles import get_style_by_name
|
41
|
+
|
42
|
+
try:
|
43
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
44
|
+
content = f.read()
|
45
|
+
|
46
|
+
# Create custom CSS for better visibility in both light and dark themes
|
47
|
+
custom_css = """
|
48
|
+
.highlight {
|
49
|
+
background: var(--jp-cell-editor-background, #f7f7f7);
|
50
|
+
border: 1px solid var(--jp-border-color2, #ddd);
|
51
|
+
border-radius: 3px;
|
52
|
+
padding: 1em;
|
53
|
+
margin: 1em 0;
|
54
|
+
}
|
55
|
+
.highlight pre {
|
56
|
+
margin: 0;
|
57
|
+
color: var(--jp-content-font-color0, #000);
|
58
|
+
background: transparent;
|
59
|
+
}
|
60
|
+
.highlight .hll { background-color: var(--jp-cell-editor-active-background, #ffffcc) }
|
61
|
+
.highlight .c { color: #408080; font-style: italic } /* Comment */
|
62
|
+
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
|
63
|
+
.highlight .o { color: #666666 } /* Operator */
|
64
|
+
.highlight .s { color: #BA2121 } /* String */
|
65
|
+
.highlight .n { color: var(--jp-content-font-color0, #000) } /* Name */
|
66
|
+
.highlight .p { color: var(--jp-content-font-color0, #000) } /* Punctuation */
|
67
|
+
"""
|
68
|
+
|
69
|
+
formatter = HtmlFormatter(style="default")
|
70
|
+
highlighted_python = pygments.highlight(content, PythonLexer(), formatter)
|
71
|
+
|
72
|
+
# Combine the custom CSS with basic formatter CSS
|
73
|
+
css = formatter.get_style_defs(".highlight") + custom_css
|
74
|
+
|
75
|
+
display(HTML(f"<style>{css}</style>{highlighted_python}"))
|
76
|
+
display(FileLink(self.path))
|
77
|
+
except Exception as e:
|
78
|
+
print(f"Error displaying Python: {e}")
|
79
|
+
|
80
|
+
def format_python(self) -> bool:
|
81
|
+
"""Format the Python file using black."""
|
82
|
+
try:
|
83
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
84
|
+
content = f.read()
|
85
|
+
|
86
|
+
# Format using black
|
87
|
+
formatted_content = black.format_str(content, mode=black.FileMode())
|
88
|
+
|
89
|
+
with open(self.path, "w", encoding="utf-8") as f:
|
90
|
+
f.write(formatted_content)
|
91
|
+
|
92
|
+
return True
|
93
|
+
except Exception as e:
|
94
|
+
print(f"Error formatting Python: {e}")
|
95
|
+
return False
|
96
|
+
|
97
|
+
def validate_syntax(self) -> bool:
|
98
|
+
"""Validate Python syntax using ast.parse."""
|
99
|
+
try:
|
100
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
101
|
+
content = f.read()
|
102
|
+
|
103
|
+
ast.parse(content)
|
104
|
+
return True
|
105
|
+
except SyntaxError as e:
|
106
|
+
print(f"Syntax error in Python file: {e}")
|
107
|
+
return False
|
108
|
+
except Exception as e:
|
109
|
+
print(f"Error validating Python: {e}")
|
110
|
+
return False
|
111
|
+
|
112
|
+
def extract_imports(self) -> List[str]:
|
113
|
+
"""Extract all import statements from the Python file."""
|
114
|
+
imports = []
|
115
|
+
try:
|
116
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
117
|
+
content = f.read()
|
118
|
+
|
119
|
+
tree = ast.parse(content)
|
120
|
+
for node in ast.walk(tree):
|
121
|
+
if isinstance(node, ast.Import):
|
122
|
+
for name in node.names:
|
123
|
+
imports.append(name.name)
|
124
|
+
elif isinstance(node, ast.ImportFrom):
|
125
|
+
module = node.module or ""
|
126
|
+
for name in node.names:
|
127
|
+
imports.append(f"{module}.{name.name}")
|
128
|
+
|
129
|
+
return sorted(list(set(imports)))
|
130
|
+
except Exception as e:
|
131
|
+
print(f"Error extracting imports: {e}")
|
132
|
+
return []
|
133
|
+
|
134
|
+
def extract_functions(self) -> List[str]:
|
135
|
+
"""Extract all function names from the Python file."""
|
136
|
+
functions = []
|
137
|
+
try:
|
138
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
139
|
+
content = f.read()
|
140
|
+
|
141
|
+
tree = ast.parse(content)
|
142
|
+
for node in ast.walk(tree):
|
143
|
+
if isinstance(node, ast.FunctionDef):
|
144
|
+
functions.append(node.name)
|
145
|
+
|
146
|
+
return sorted(functions)
|
147
|
+
except Exception as e:
|
148
|
+
print(f"Error extracting functions: {e}")
|
149
|
+
return []
|
150
|
+
|
151
|
+
def extract_classes(self) -> List[str]:
|
152
|
+
"""Extract all class names from the Python file."""
|
153
|
+
classes = []
|
154
|
+
try:
|
155
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
156
|
+
content = f.read()
|
157
|
+
|
158
|
+
tree = ast.parse(content)
|
159
|
+
for node in ast.walk(tree):
|
160
|
+
if isinstance(node, ast.ClassDef):
|
161
|
+
classes.append(node.name)
|
162
|
+
|
163
|
+
return sorted(classes)
|
164
|
+
except Exception as e:
|
165
|
+
print(f"Error extracting classes: {e}")
|
166
|
+
return []
|
167
|
+
|
168
|
+
def get_docstrings(self) -> Dict[str, str]:
|
169
|
+
"""Extract docstrings for all functions and classes."""
|
170
|
+
docstrings = {}
|
171
|
+
try:
|
172
|
+
with open(self.path, "r", encoding="utf-8") as f:
|
173
|
+
content = f.read()
|
174
|
+
|
175
|
+
tree = ast.parse(content)
|
176
|
+
for node in ast.walk(tree):
|
177
|
+
if isinstance(node, (ast.FunctionDef, ast.ClassDef)):
|
178
|
+
docstring = ast.get_docstring(node)
|
179
|
+
if docstring:
|
180
|
+
docstrings[node.name] = docstring
|
181
|
+
|
182
|
+
return docstrings
|
183
|
+
except Exception as e:
|
184
|
+
print(f"Error extracting docstrings: {e}")
|
185
|
+
return {}
|
186
|
+
|
187
|
+
def run_file(self, args: List[str] = None) -> Optional[int]:
|
188
|
+
"""Run the Python file as a script with optional arguments."""
|
189
|
+
try:
|
190
|
+
cmd = [sys.executable, self.path]
|
191
|
+
if args:
|
192
|
+
cmd.extend(args)
|
193
|
+
|
194
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
195
|
+
print(result.stdout)
|
196
|
+
if result.stderr:
|
197
|
+
print("Errors:", result.stderr, file=sys.stderr)
|
198
|
+
return result.returncode
|
199
|
+
except Exception as e:
|
200
|
+
print(f"Error running Python file: {e}")
|
201
|
+
return None
|
202
|
+
|
203
|
+
def check_dependencies(self) -> List[str]:
|
204
|
+
"""Check if all imported modules are available."""
|
205
|
+
missing_deps = []
|
206
|
+
try:
|
207
|
+
imports = self.extract_imports()
|
208
|
+
for imp in imports:
|
209
|
+
# Get the top-level module name
|
210
|
+
top_module = imp.split(".")[0]
|
211
|
+
if not util.find_spec(top_module):
|
212
|
+
missing_deps.append(top_module)
|
213
|
+
return missing_deps
|
214
|
+
except Exception as e:
|
215
|
+
print(f"Error checking dependencies: {e}")
|
216
|
+
return []
|
217
|
+
|
218
|
+
def example(self):
|
219
|
+
"""Create a sample Python file with common patterns."""
|
220
|
+
sample_python = '''#!/usr/bin/env python3
|
221
|
+
"""Example Python module demonstrating common patterns."""
|
222
|
+
|
223
|
+
import sys
|
224
|
+
from typing import List, Optional
|
225
|
+
from dataclasses import dataclass
|
226
|
+
|
227
|
+
|
228
|
+
@dataclass
|
229
|
+
class Employee:
|
230
|
+
"""Represents an employee in the system."""
|
231
|
+
name: str
|
232
|
+
department: str
|
233
|
+
salary: float
|
234
|
+
hire_date: str
|
235
|
+
|
236
|
+
|
237
|
+
class EmployeeManager:
|
238
|
+
"""Manages employee operations."""
|
239
|
+
|
240
|
+
def __init__(self):
|
241
|
+
self.employees: List[Employee] = []
|
242
|
+
|
243
|
+
def add_employee(self, employee: Employee) -> None:
|
244
|
+
"""Add a new employee to the system."""
|
245
|
+
self.employees.append(employee)
|
246
|
+
|
247
|
+
def get_department_stats(self, department: str) -> Optional[dict]:
|
248
|
+
"""Calculate statistics for a department."""
|
249
|
+
dept_employees = [e for e in self.employees if e.department == department]
|
250
|
+
|
251
|
+
if not dept_employees:
|
252
|
+
return None
|
253
|
+
|
254
|
+
return {
|
255
|
+
'count': len(dept_employees),
|
256
|
+
'avg_salary': sum(e.salary for e in dept_employees) / len(dept_employees)
|
257
|
+
}
|
258
|
+
|
259
|
+
|
260
|
+
def main(args: List[str]) -> int:
|
261
|
+
"""Main entry point for the script."""
|
262
|
+
manager = EmployeeManager()
|
263
|
+
|
264
|
+
# Add sample employees
|
265
|
+
manager.add_employee(Employee(
|
266
|
+
"John Doe",
|
267
|
+
"Engineering",
|
268
|
+
75000.00,
|
269
|
+
"2023-01-15"
|
270
|
+
))
|
271
|
+
|
272
|
+
manager.add_employee(Employee(
|
273
|
+
"Jane Smith",
|
274
|
+
"Marketing",
|
275
|
+
65000.00,
|
276
|
+
"2023-02-01"
|
277
|
+
))
|
278
|
+
|
279
|
+
# Print department statistics
|
280
|
+
stats = manager.get_department_stats("Engineering")
|
281
|
+
if stats:
|
282
|
+
print(f"Engineering department stats: {stats}")
|
283
|
+
|
284
|
+
return 0
|
285
|
+
|
286
|
+
|
287
|
+
if __name__ == "__main__":
|
288
|
+
sys.exit(main(sys.argv[1:]))
|
289
|
+
'''
|
290
|
+
with tempfile.NamedTemporaryFile(
|
291
|
+
delete=False, suffix=".py", mode="w", encoding="utf-8"
|
292
|
+
) as f:
|
293
|
+
f.write(sample_python)
|
294
|
+
return f.name
|
@@ -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
|