edsl 0.1.38.dev3__py3-none-any.whl → 0.1.39__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 (341) hide show
  1. edsl/Base.py +413 -303
  2. edsl/BaseDiff.py +260 -260
  3. edsl/TemplateLoader.py +24 -24
  4. edsl/__init__.py +57 -49
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +1071 -858
  7. edsl/agents/AgentList.py +551 -362
  8. edsl/agents/Invigilator.py +284 -222
  9. edsl/agents/InvigilatorBase.py +257 -284
  10. edsl/agents/PromptConstructor.py +272 -353
  11. edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
  12. edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
  13. edsl/agents/__init__.py +2 -3
  14. edsl/agents/descriptors.py +99 -99
  15. edsl/agents/prompt_helpers.py +129 -129
  16. edsl/agents/question_option_processor.py +172 -0
  17. edsl/auto/AutoStudy.py +130 -117
  18. edsl/auto/StageBase.py +243 -230
  19. edsl/auto/StageGenerateSurvey.py +178 -178
  20. edsl/auto/StageLabelQuestions.py +125 -125
  21. edsl/auto/StagePersona.py +61 -61
  22. edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
  23. edsl/auto/StagePersonaDimensionValues.py +74 -74
  24. edsl/auto/StagePersonaDimensions.py +69 -69
  25. edsl/auto/StageQuestions.py +74 -73
  26. edsl/auto/SurveyCreatorPipeline.py +21 -21
  27. edsl/auto/utilities.py +218 -224
  28. edsl/base/Base.py +279 -279
  29. edsl/config.py +177 -149
  30. edsl/conversation/Conversation.py +290 -290
  31. edsl/conversation/car_buying.py +59 -58
  32. edsl/conversation/chips.py +95 -95
  33. edsl/conversation/mug_negotiation.py +81 -81
  34. edsl/conversation/next_speaker_utilities.py +93 -93
  35. edsl/coop/CoopFunctionsMixin.py +15 -0
  36. edsl/coop/ExpectedParrotKeyHandler.py +125 -0
  37. edsl/coop/PriceFetcher.py +54 -54
  38. edsl/coop/__init__.py +2 -2
  39. edsl/coop/coop.py +1106 -961
  40. edsl/coop/utils.py +131 -131
  41. edsl/data/Cache.py +573 -530
  42. edsl/data/CacheEntry.py +230 -228
  43. edsl/data/CacheHandler.py +168 -149
  44. edsl/data/RemoteCacheSync.py +186 -97
  45. edsl/data/SQLiteDict.py +292 -292
  46. edsl/data/__init__.py +5 -4
  47. edsl/data/orm.py +10 -10
  48. edsl/data_transfer_models.py +74 -73
  49. edsl/enums.py +202 -173
  50. edsl/exceptions/BaseException.py +21 -21
  51. edsl/exceptions/__init__.py +54 -54
  52. edsl/exceptions/agents.py +54 -42
  53. edsl/exceptions/cache.py +5 -5
  54. edsl/exceptions/configuration.py +16 -16
  55. edsl/exceptions/coop.py +10 -10
  56. edsl/exceptions/data.py +14 -14
  57. edsl/exceptions/general.py +34 -34
  58. edsl/exceptions/inference_services.py +5 -0
  59. edsl/exceptions/jobs.py +33 -33
  60. edsl/exceptions/language_models.py +63 -63
  61. edsl/exceptions/prompts.py +15 -15
  62. edsl/exceptions/questions.py +109 -91
  63. edsl/exceptions/results.py +29 -29
  64. edsl/exceptions/scenarios.py +29 -22
  65. edsl/exceptions/surveys.py +37 -37
  66. edsl/inference_services/AnthropicService.py +106 -87
  67. edsl/inference_services/AvailableModelCacheHandler.py +184 -0
  68. edsl/inference_services/AvailableModelFetcher.py +215 -0
  69. edsl/inference_services/AwsBedrock.py +118 -120
  70. edsl/inference_services/AzureAI.py +215 -217
  71. edsl/inference_services/DeepInfraService.py +18 -18
  72. edsl/inference_services/GoogleService.py +143 -156
  73. edsl/inference_services/GroqService.py +20 -20
  74. edsl/inference_services/InferenceServiceABC.py +80 -147
  75. edsl/inference_services/InferenceServicesCollection.py +138 -97
  76. edsl/inference_services/MistralAIService.py +120 -123
  77. edsl/inference_services/OllamaService.py +18 -18
  78. edsl/inference_services/OpenAIService.py +236 -224
  79. edsl/inference_services/PerplexityService.py +160 -0
  80. edsl/inference_services/ServiceAvailability.py +135 -0
  81. edsl/inference_services/TestService.py +90 -89
  82. edsl/inference_services/TogetherAIService.py +172 -170
  83. edsl/inference_services/data_structures.py +134 -0
  84. edsl/inference_services/models_available_cache.py +118 -118
  85. edsl/inference_services/rate_limits_cache.py +25 -25
  86. edsl/inference_services/registry.py +41 -39
  87. edsl/inference_services/write_available.py +10 -10
  88. edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
  89. edsl/jobs/Answers.py +43 -56
  90. edsl/jobs/FetchInvigilator.py +47 -0
  91. edsl/jobs/InterviewTaskManager.py +98 -0
  92. edsl/jobs/InterviewsConstructor.py +50 -0
  93. edsl/jobs/Jobs.py +823 -1358
  94. edsl/jobs/JobsChecks.py +172 -0
  95. edsl/jobs/JobsComponentConstructor.py +189 -0
  96. edsl/jobs/JobsPrompts.py +270 -0
  97. edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
  98. edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
  99. edsl/jobs/RequestTokenEstimator.py +30 -0
  100. edsl/jobs/__init__.py +1 -1
  101. edsl/jobs/async_interview_runner.py +138 -0
  102. edsl/jobs/buckets/BucketCollection.py +104 -63
  103. edsl/jobs/buckets/ModelBuckets.py +65 -65
  104. edsl/jobs/buckets/TokenBucket.py +283 -251
  105. edsl/jobs/buckets/TokenBucketAPI.py +211 -0
  106. edsl/jobs/buckets/TokenBucketClient.py +191 -0
  107. edsl/jobs/check_survey_scenario_compatibility.py +85 -0
  108. edsl/jobs/data_structures.py +120 -0
  109. edsl/jobs/decorators.py +35 -0
  110. edsl/jobs/interviews/Interview.py +396 -661
  111. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
  112. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
  113. edsl/jobs/interviews/InterviewStatistic.py +63 -63
  114. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
  115. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
  116. edsl/jobs/interviews/InterviewStatusLog.py +92 -92
  117. edsl/jobs/interviews/ReportErrors.py +66 -66
  118. edsl/jobs/interviews/interview_status_enum.py +9 -9
  119. edsl/jobs/jobs_status_enums.py +9 -0
  120. edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
  121. edsl/jobs/results_exceptions_handler.py +98 -0
  122. edsl/jobs/runners/JobsRunnerAsyncio.py +151 -361
  123. edsl/jobs/runners/JobsRunnerStatus.py +298 -332
  124. edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
  125. edsl/jobs/tasks/TaskCreators.py +64 -64
  126. edsl/jobs/tasks/TaskHistory.py +470 -451
  127. edsl/jobs/tasks/TaskStatusLog.py +23 -23
  128. edsl/jobs/tasks/task_status_enum.py +161 -163
  129. edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
  130. edsl/jobs/tokens/TokenUsage.py +34 -34
  131. edsl/language_models/ComputeCost.py +63 -0
  132. edsl/language_models/LanguageModel.py +626 -708
  133. edsl/language_models/ModelList.py +164 -109
  134. edsl/language_models/PriceManager.py +127 -0
  135. edsl/language_models/RawResponseHandler.py +106 -0
  136. edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
  137. edsl/language_models/ServiceDataSources.py +0 -0
  138. edsl/language_models/__init__.py +2 -3
  139. edsl/language_models/fake_openai_call.py +15 -15
  140. edsl/language_models/fake_openai_service.py +61 -61
  141. edsl/language_models/key_management/KeyLookup.py +63 -0
  142. edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
  143. edsl/language_models/key_management/KeyLookupCollection.py +38 -0
  144. edsl/language_models/key_management/__init__.py +0 -0
  145. edsl/language_models/key_management/models.py +131 -0
  146. edsl/language_models/model.py +256 -0
  147. edsl/language_models/repair.py +156 -156
  148. edsl/language_models/utilities.py +65 -64
  149. edsl/notebooks/Notebook.py +263 -258
  150. edsl/notebooks/NotebookToLaTeX.py +142 -0
  151. edsl/notebooks/__init__.py +1 -1
  152. edsl/prompts/Prompt.py +352 -357
  153. edsl/prompts/__init__.py +2 -2
  154. edsl/questions/ExceptionExplainer.py +77 -0
  155. edsl/questions/HTMLQuestion.py +103 -0
  156. edsl/questions/QuestionBase.py +518 -660
  157. edsl/questions/QuestionBasePromptsMixin.py +221 -217
  158. edsl/questions/QuestionBudget.py +227 -227
  159. edsl/questions/QuestionCheckBox.py +359 -359
  160. edsl/questions/QuestionExtract.py +180 -183
  161. edsl/questions/QuestionFreeText.py +113 -114
  162. edsl/questions/QuestionFunctional.py +166 -166
  163. edsl/questions/QuestionList.py +223 -231
  164. edsl/questions/QuestionMatrix.py +265 -0
  165. edsl/questions/QuestionMultipleChoice.py +330 -286
  166. edsl/questions/QuestionNumerical.py +151 -153
  167. edsl/questions/QuestionRank.py +314 -324
  168. edsl/questions/Quick.py +41 -41
  169. edsl/questions/SimpleAskMixin.py +74 -73
  170. edsl/questions/__init__.py +27 -26
  171. edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
  172. edsl/questions/compose_questions.py +98 -98
  173. edsl/questions/data_structures.py +20 -0
  174. edsl/questions/decorators.py +21 -21
  175. edsl/questions/derived/QuestionLikertFive.py +76 -76
  176. edsl/questions/derived/QuestionLinearScale.py +90 -87
  177. edsl/questions/derived/QuestionTopK.py +93 -93
  178. edsl/questions/derived/QuestionYesNo.py +82 -82
  179. edsl/questions/descriptors.py +427 -413
  180. edsl/questions/loop_processor.py +149 -0
  181. edsl/questions/prompt_templates/question_budget.jinja +13 -13
  182. edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
  183. edsl/questions/prompt_templates/question_extract.jinja +11 -11
  184. edsl/questions/prompt_templates/question_free_text.jinja +3 -3
  185. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
  186. edsl/questions/prompt_templates/question_list.jinja +17 -17
  187. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
  188. edsl/questions/prompt_templates/question_numerical.jinja +36 -36
  189. edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
  190. edsl/questions/question_registry.py +177 -147
  191. edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
  192. edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
  193. edsl/questions/response_validator_factory.py +34 -0
  194. edsl/questions/settings.py +12 -12
  195. edsl/questions/templates/budget/answering_instructions.jinja +7 -7
  196. edsl/questions/templates/budget/question_presentation.jinja +7 -7
  197. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
  198. edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
  199. edsl/questions/templates/extract/answering_instructions.jinja +7 -7
  200. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
  201. edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
  202. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
  203. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
  204. edsl/questions/templates/list/answering_instructions.jinja +3 -3
  205. edsl/questions/templates/list/question_presentation.jinja +5 -5
  206. edsl/questions/templates/matrix/__init__.py +1 -0
  207. edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
  208. edsl/questions/templates/matrix/question_presentation.jinja +20 -0
  209. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
  210. edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
  211. edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
  212. edsl/questions/templates/numerical/question_presentation.jinja +6 -6
  213. edsl/questions/templates/rank/answering_instructions.jinja +11 -11
  214. edsl/questions/templates/rank/question_presentation.jinja +15 -15
  215. edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
  216. edsl/questions/templates/top_k/question_presentation.jinja +22 -22
  217. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
  218. edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
  219. edsl/results/CSSParameterizer.py +108 -0
  220. edsl/results/Dataset.py +587 -293
  221. edsl/results/DatasetExportMixin.py +594 -717
  222. edsl/results/DatasetTree.py +295 -145
  223. edsl/results/MarkdownToDocx.py +122 -0
  224. edsl/results/MarkdownToPDF.py +111 -0
  225. edsl/results/Result.py +557 -456
  226. edsl/results/Results.py +1183 -1071
  227. edsl/results/ResultsExportMixin.py +45 -43
  228. edsl/results/ResultsGGMixin.py +121 -121
  229. edsl/results/TableDisplay.py +125 -0
  230. edsl/results/TextEditor.py +50 -0
  231. edsl/results/__init__.py +2 -2
  232. edsl/results/file_exports.py +252 -0
  233. edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
  234. edsl/results/{Selector.py → results_selector.py} +145 -135
  235. edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
  236. edsl/results/smart_objects.py +96 -0
  237. edsl/results/table_data_class.py +12 -0
  238. edsl/results/table_display.css +78 -0
  239. edsl/results/table_renderers.py +118 -0
  240. edsl/results/tree_explore.py +115 -115
  241. edsl/scenarios/ConstructDownloadLink.py +109 -0
  242. edsl/scenarios/DocumentChunker.py +102 -0
  243. edsl/scenarios/DocxScenario.py +16 -0
  244. edsl/scenarios/FileStore.py +543 -458
  245. edsl/scenarios/PdfExtractor.py +40 -0
  246. edsl/scenarios/Scenario.py +498 -544
  247. edsl/scenarios/ScenarioHtmlMixin.py +65 -64
  248. edsl/scenarios/ScenarioList.py +1458 -1112
  249. edsl/scenarios/ScenarioListExportMixin.py +45 -52
  250. edsl/scenarios/ScenarioListPdfMixin.py +239 -261
  251. edsl/scenarios/__init__.py +3 -4
  252. edsl/scenarios/directory_scanner.py +96 -0
  253. edsl/scenarios/file_methods.py +85 -0
  254. edsl/scenarios/handlers/__init__.py +13 -0
  255. edsl/scenarios/handlers/csv.py +49 -0
  256. edsl/scenarios/handlers/docx.py +76 -0
  257. edsl/scenarios/handlers/html.py +37 -0
  258. edsl/scenarios/handlers/json.py +111 -0
  259. edsl/scenarios/handlers/latex.py +5 -0
  260. edsl/scenarios/handlers/md.py +51 -0
  261. edsl/scenarios/handlers/pdf.py +68 -0
  262. edsl/scenarios/handlers/png.py +39 -0
  263. edsl/scenarios/handlers/pptx.py +105 -0
  264. edsl/scenarios/handlers/py.py +294 -0
  265. edsl/scenarios/handlers/sql.py +313 -0
  266. edsl/scenarios/handlers/sqlite.py +149 -0
  267. edsl/scenarios/handlers/txt.py +33 -0
  268. edsl/scenarios/scenario_join.py +131 -0
  269. edsl/scenarios/scenario_selector.py +156 -0
  270. edsl/shared.py +1 -1
  271. edsl/study/ObjectEntry.py +173 -173
  272. edsl/study/ProofOfWork.py +113 -113
  273. edsl/study/SnapShot.py +80 -80
  274. edsl/study/Study.py +521 -528
  275. edsl/study/__init__.py +4 -4
  276. edsl/surveys/ConstructDAG.py +92 -0
  277. edsl/surveys/DAG.py +148 -148
  278. edsl/surveys/EditSurvey.py +221 -0
  279. edsl/surveys/InstructionHandler.py +100 -0
  280. edsl/surveys/Memory.py +31 -31
  281. edsl/surveys/MemoryManagement.py +72 -0
  282. edsl/surveys/MemoryPlan.py +244 -244
  283. edsl/surveys/Rule.py +327 -326
  284. edsl/surveys/RuleCollection.py +385 -387
  285. edsl/surveys/RuleManager.py +172 -0
  286. edsl/surveys/Simulator.py +75 -0
  287. edsl/surveys/Survey.py +1280 -1787
  288. edsl/surveys/SurveyCSS.py +273 -261
  289. edsl/surveys/SurveyExportMixin.py +259 -259
  290. edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -121
  291. edsl/surveys/SurveyQualtricsImport.py +284 -284
  292. edsl/surveys/SurveyToApp.py +141 -0
  293. edsl/surveys/__init__.py +5 -3
  294. edsl/surveys/base.py +53 -53
  295. edsl/surveys/descriptors.py +60 -56
  296. edsl/surveys/instructions/ChangeInstruction.py +48 -49
  297. edsl/surveys/instructions/Instruction.py +56 -53
  298. edsl/surveys/instructions/InstructionCollection.py +82 -77
  299. edsl/templates/error_reporting/base.html +23 -23
  300. edsl/templates/error_reporting/exceptions_by_model.html +34 -34
  301. edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
  302. edsl/templates/error_reporting/exceptions_by_type.html +16 -16
  303. edsl/templates/error_reporting/interview_details.html +115 -115
  304. edsl/templates/error_reporting/interviews.html +19 -10
  305. edsl/templates/error_reporting/overview.html +4 -4
  306. edsl/templates/error_reporting/performance_plot.html +1 -1
  307. edsl/templates/error_reporting/report.css +73 -73
  308. edsl/templates/error_reporting/report.html +117 -117
  309. edsl/templates/error_reporting/report.js +25 -25
  310. edsl/tools/__init__.py +1 -1
  311. edsl/tools/clusters.py +192 -192
  312. edsl/tools/embeddings.py +27 -27
  313. edsl/tools/embeddings_plotting.py +118 -118
  314. edsl/tools/plotting.py +112 -112
  315. edsl/tools/summarize.py +18 -18
  316. edsl/utilities/PrettyList.py +56 -0
  317. edsl/utilities/SystemInfo.py +28 -28
  318. edsl/utilities/__init__.py +22 -22
  319. edsl/utilities/ast_utilities.py +25 -25
  320. edsl/utilities/data/Registry.py +6 -6
  321. edsl/utilities/data/__init__.py +1 -1
  322. edsl/utilities/data/scooter_results.json +1 -1
  323. edsl/utilities/decorators.py +77 -77
  324. edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
  325. edsl/utilities/interface.py +627 -627
  326. edsl/utilities/is_notebook.py +18 -0
  327. edsl/utilities/is_valid_variable_name.py +11 -0
  328. edsl/utilities/naming_utilities.py +263 -263
  329. edsl/utilities/remove_edsl_version.py +24 -0
  330. edsl/utilities/repair_functions.py +28 -28
  331. edsl/utilities/restricted_python.py +70 -70
  332. edsl/utilities/utilities.py +436 -409
  333. {edsl-0.1.38.dev3.dist-info → edsl-0.1.39.dist-info}/LICENSE +21 -21
  334. {edsl-0.1.38.dev3.dist-info → edsl-0.1.39.dist-info}/METADATA +13 -10
  335. edsl-0.1.39.dist-info/RECORD +358 -0
  336. {edsl-0.1.38.dev3.dist-info → edsl-0.1.39.dist-info}/WHEEL +1 -1
  337. edsl/language_models/KeyLookup.py +0 -30
  338. edsl/language_models/registry.py +0 -137
  339. edsl/language_models/unused/ReplicateBase.py +0 -83
  340. edsl/results/ResultsDBMixin.py +0 -238
  341. edsl-0.1.38.dev3.dist-info/RECORD +0 -269
@@ -1,43 +1,45 @@
1
- """Mixin class for exporting results."""
2
-
3
- from functools import wraps
4
- from typing import Literal, Optional, Union
5
-
6
- from edsl.results.DatasetExportMixin import DatasetExportMixin
7
-
8
-
9
- def to_dataset(func):
10
- """Convert the Results object to a Dataset object before calling the function."""
11
-
12
- @wraps(func)
13
- def wrapper(self, *args, **kwargs):
14
- """Return the function with the Results object converted to a Dataset object."""
15
- if self.__class__.__name__ == "Results":
16
- return func(self.select(), *args, **kwargs)
17
- else:
18
- return func(self, *args, **kwargs)
19
-
20
- wrapper._is_wrapped = True
21
- return wrapper
22
-
23
-
24
- def decorate_methods_from_mixin(cls, mixin_cls):
25
- for attr_name, attr_value in mixin_cls.__dict__.items():
26
- if callable(attr_value) and not attr_name.startswith("__"):
27
- setattr(cls, attr_name, to_dataset(attr_value))
28
- return cls
29
-
30
-
31
- class ResultsExportMixin(DatasetExportMixin):
32
- """Mixin class for exporting Results objects."""
33
-
34
- def __init_subclass__(cls, **kwargs):
35
- super().__init_subclass__(**kwargs)
36
- decorate_methods_from_mixin(cls, DatasetExportMixin)
37
-
38
-
39
- if __name__ == "__main__":
40
- # pass
41
- import doctest
42
-
43
- doctest.testmod(optionflags=doctest.ELLIPSIS)
1
+ """Mixin class for exporting results."""
2
+
3
+ from functools import wraps
4
+ from typing import Literal, Optional, Union
5
+
6
+ from edsl.results.DatasetExportMixin import DatasetExportMixin
7
+
8
+
9
+ def to_dataset(func):
10
+ """Convert the Results object to a Dataset object before calling the function."""
11
+
12
+ @wraps(func)
13
+ def wrapper(self, *args, **kwargs):
14
+ """Return the function with the Results object converted to a Dataset object."""
15
+ if self.__class__.__name__ == "Results":
16
+ return func(self.select(), *args, **kwargs)
17
+ elif self.__class__.__name__ == "AgentList":
18
+ return func(self.to_dataset(), *args, **kwargs)
19
+ else:
20
+ return func(self, *args, **kwargs)
21
+
22
+ wrapper._is_wrapped = True
23
+ return wrapper
24
+
25
+
26
+ def decorate_methods_from_mixin(cls, mixin_cls):
27
+ for attr_name, attr_value in mixin_cls.__dict__.items():
28
+ if callable(attr_value) and not attr_name.startswith("__"):
29
+ setattr(cls, attr_name, to_dataset(attr_value))
30
+ return cls
31
+
32
+
33
+ class ResultsExportMixin(DatasetExportMixin):
34
+ """Mixin class for exporting Results objects."""
35
+
36
+ def __init_subclass__(cls, **kwargs):
37
+ super().__init_subclass__(**kwargs)
38
+ decorate_methods_from_mixin(cls, DatasetExportMixin)
39
+
40
+
41
+ if __name__ == "__main__":
42
+ # pass
43
+ import doctest
44
+
45
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
@@ -1,121 +1,121 @@
1
- """Mixin class for ggplot2 plotting."""
2
-
3
- import subprocess
4
- import tempfile
5
- from typing import Optional
6
-
7
-
8
- class ResultsGGMixin:
9
- """Mixin class for ggplot2 plotting."""
10
-
11
- def ggplot2(
12
- self,
13
- ggplot_code: str,
14
- filename: str = None,
15
- shape="wide",
16
- sql: str = None,
17
- remove_prefix: bool = True,
18
- debug: bool = False,
19
- height=4,
20
- width=6,
21
- format="svg",
22
- factor_orders: Optional[dict] = None,
23
- ):
24
- """Create a ggplot2 plot from a DataFrame.
25
-
26
- :param ggplot_code: The ggplot2 code to execute.
27
- :param filename: The filename to save the plot to.
28
- :param shape: The shape of the data in the DataFrame (wide or long).
29
- :param sql: The SQL query to execute beforehand to manipulate the data.
30
- :param remove_prefix: Whether to remove the prefix from the column names.
31
- :param debug: Whether to print the R code instead of executing it.
32
- :param height: The height of the plot in inches.
33
- :param width: The width of the plot in inches.
34
- :param format: The format to save the plot in (png or svg).
35
- :param factor_orders: A dictionary of factor columns and their order.
36
- """
37
-
38
- if sql == None:
39
- sql = "select * from self"
40
-
41
- if shape == "long":
42
- df = self.sql(sql, shape="long")
43
- elif shape == "wide":
44
- df = self.sql(sql, shape="wide", remove_prefix=remove_prefix)
45
-
46
- # Convert DataFrame to CSV format
47
- csv_data = df.to_csv(index=False)
48
-
49
- # Embed the CSV data within the R script
50
- csv_data_escaped = csv_data.replace("\n", "\\n").replace("'", "\\'")
51
- read_csv_code = f"self <- read.csv(text = '{csv_data_escaped}', sep = ',')\n"
52
-
53
- if factor_orders is not None:
54
- for factor, order in factor_orders.items():
55
- # read_csv_code += f"""self${{{factor}}} <- factor(self${{{factor}}}, levels=c({','.join(['"{}"'.format(x) for x in order])}))"""
56
-
57
- level_string = ", ".join([f'"{x}"' for x in order])
58
- read_csv_code += (
59
- f"self${factor} <- factor(self${factor}, levels=c({level_string}))"
60
- )
61
- read_csv_code += "\n"
62
-
63
- # Load ggplot2 library
64
- load_ggplot2 = "library(ggplot2)\n"
65
-
66
- # Check if a filename is provided for the plot, if not create a temporary one
67
- if not filename:
68
- filename = tempfile.mktemp(suffix=f".{format}")
69
-
70
- # Combine all R script parts
71
- full_r_code = load_ggplot2 + read_csv_code + ggplot_code
72
-
73
- # Add command to save the plot to a file
74
- full_r_code += f'\nggsave("{filename}", plot = last_plot(), width = {width}, height = {height}, device = "{format}")'
75
-
76
- if debug:
77
- print(full_r_code)
78
- return
79
-
80
- result = subprocess.run(
81
- ["Rscript", "-"],
82
- input=full_r_code,
83
- text=True,
84
- stdout=subprocess.PIPE,
85
- stderr=subprocess.PIPE,
86
- )
87
-
88
- if result.returncode != 0:
89
- if result.returncode == 127: # 'command not found'
90
- raise RuntimeError(
91
- "Rscript is probably not installed. Please install R from https://cran.r-project.org/"
92
- )
93
- else:
94
- raise RuntimeError(
95
- f"An error occurred while running Rscript: {result.stderr}"
96
- )
97
-
98
- if result.stderr:
99
- print("Error in R script:", result.stderr)
100
- else:
101
- self._display_plot(filename, width, height)
102
-
103
- def _display_plot(self, filename: str, width: float, height: float):
104
- """Display the plot in the notebook."""
105
- import matplotlib.pyplot as plt
106
- import matplotlib.image as mpimg
107
-
108
- if filename.endswith(".png"):
109
- img = mpimg.imread(filename)
110
- plt.figure(
111
- figsize=(width, height)
112
- ) # Set the figure size (width, height) in inches
113
- plt.imshow(img)
114
- plt.axis("off")
115
- plt.show()
116
- elif filename.endswith(".svg"):
117
- from IPython.display import SVG, display
118
-
119
- display(SVG(filename=filename))
120
- else:
121
- print("Unsupported file format. Please provide a PNG or SVG file.")
1
+ """Mixin class for ggplot2 plotting."""
2
+
3
+ import subprocess
4
+ import tempfile
5
+ from typing import Optional
6
+
7
+
8
+ class ResultsGGMixin:
9
+ """Mixin class for ggplot2 plotting."""
10
+
11
+ def ggplot2(
12
+ self,
13
+ ggplot_code: str,
14
+ filename: str = None,
15
+ shape="wide",
16
+ sql: str = None,
17
+ remove_prefix: bool = True,
18
+ debug: bool = False,
19
+ height=4,
20
+ width=6,
21
+ format="svg",
22
+ factor_orders: Optional[dict] = None,
23
+ ):
24
+ """Create a ggplot2 plot from a DataFrame.
25
+
26
+ :param ggplot_code: The ggplot2 code to execute.
27
+ :param filename: The filename to save the plot to.
28
+ :param shape: The shape of the data in the DataFrame (wide or long).
29
+ :param sql: The SQL query to execute beforehand to manipulate the data.
30
+ :param remove_prefix: Whether to remove the prefix from the column names.
31
+ :param debug: Whether to print the R code instead of executing it.
32
+ :param height: The height of the plot in inches.
33
+ :param width: The width of the plot in inches.
34
+ :param format: The format to save the plot in (png or svg).
35
+ :param factor_orders: A dictionary of factor columns and their order.
36
+ """
37
+
38
+ if sql == None:
39
+ sql = "select * from self"
40
+
41
+ if shape == "long":
42
+ df = self.sql(sql, shape="long")
43
+ elif shape == "wide":
44
+ df = self.sql(sql, shape="wide", remove_prefix=remove_prefix)
45
+
46
+ # Convert DataFrame to CSV format
47
+ csv_data = df.to_csv(index=False)
48
+
49
+ # Embed the CSV data within the R script
50
+ csv_data_escaped = csv_data.replace("\n", "\\n").replace("'", "\\'")
51
+ read_csv_code = f"self <- read.csv(text = '{csv_data_escaped}', sep = ',')\n"
52
+
53
+ if factor_orders is not None:
54
+ for factor, order in factor_orders.items():
55
+ # read_csv_code += f"""self${{{factor}}} <- factor(self${{{factor}}}, levels=c({','.join(['"{}"'.format(x) for x in order])}))"""
56
+
57
+ level_string = ", ".join([f'"{x}"' for x in order])
58
+ read_csv_code += (
59
+ f"self${factor} <- factor(self${factor}, levels=c({level_string}))"
60
+ )
61
+ read_csv_code += "\n"
62
+
63
+ # Load ggplot2 library
64
+ load_ggplot2 = "library(ggplot2)\n"
65
+
66
+ # Check if a filename is provided for the plot, if not create a temporary one
67
+ if not filename:
68
+ filename = tempfile.mktemp(suffix=f".{format}")
69
+
70
+ # Combine all R script parts
71
+ full_r_code = load_ggplot2 + read_csv_code + ggplot_code
72
+
73
+ # Add command to save the plot to a file
74
+ full_r_code += f'\nggsave("{filename}", plot = last_plot(), width = {width}, height = {height}, device = "{format}")'
75
+
76
+ if debug:
77
+ print(full_r_code)
78
+ return
79
+
80
+ result = subprocess.run(
81
+ ["Rscript", "-"],
82
+ input=full_r_code,
83
+ text=True,
84
+ stdout=subprocess.PIPE,
85
+ stderr=subprocess.PIPE,
86
+ )
87
+
88
+ if result.returncode != 0:
89
+ if result.returncode == 127: # 'command not found'
90
+ raise RuntimeError(
91
+ "Rscript is probably not installed. Please install R from https://cran.r-project.org/"
92
+ )
93
+ else:
94
+ raise RuntimeError(
95
+ f"An error occurred while running Rscript: {result.stderr}"
96
+ )
97
+
98
+ if result.stderr:
99
+ print("Error in R script:", result.stderr)
100
+ else:
101
+ self._display_plot(filename, width, height)
102
+
103
+ def _display_plot(self, filename: str, width: float, height: float):
104
+ """Display the plot in the notebook."""
105
+ import matplotlib.pyplot as plt
106
+ import matplotlib.image as mpimg
107
+
108
+ if filename.endswith(".png"):
109
+ img = mpimg.imread(filename)
110
+ plt.figure(
111
+ figsize=(width, height)
112
+ ) # Set the figure size (width, height) in inches
113
+ plt.imshow(img)
114
+ plt.axis("off")
115
+ plt.show()
116
+ elif filename.endswith(".svg"):
117
+ from IPython.display import SVG, display
118
+
119
+ display(SVG(filename=filename))
120
+ else:
121
+ print("Unsupported file format. Please provide a PNG or SVG file.")
@@ -0,0 +1,125 @@
1
+ from typing import (
2
+ Protocol,
3
+ List,
4
+ Any,
5
+ Optional,
6
+ TYPE_CHECKING,
7
+ Sequence,
8
+ Union,
9
+ Literal,
10
+ )
11
+
12
+ if TYPE_CHECKING:
13
+ from edsl.results.Dataset import Dataset
14
+
15
+ from edsl.results.table_data_class import TableData
16
+
17
+ from edsl.results.table_renderers import DataTablesRenderer, PandasStyleRenderer
18
+
19
+ Row = Sequence[Union[str, int, float, bool, None]]
20
+ TableFormat = Literal[
21
+ "grid", "simple", "pipe", "orgtbl", "rst", "mediawiki", "html", "latex"
22
+ ]
23
+
24
+
25
+ class TableRenderer(Protocol):
26
+ """Table renderer protocol"""
27
+
28
+ def render_html(self, table_data: TableData) -> str:
29
+ pass
30
+
31
+
32
+ # Modified TableDisplay class
33
+ class TableDisplay:
34
+ def __init__(
35
+ self,
36
+ headers: Sequence[str],
37
+ data: Sequence[Row],
38
+ tablefmt: Optional[TableFormat] = None,
39
+ raw_data_set: "Dataset" = None,
40
+ renderer_class: Optional[TableRenderer] = None,
41
+ ):
42
+ assert len(headers) == len(data[0]) # Check if headers and data are consistent
43
+
44
+ self.headers = headers
45
+ self.data = data
46
+ self.tablefmt = tablefmt
47
+ self.raw_data_set = raw_data_set
48
+
49
+ self.renderer_class = renderer_class or PandasStyleRenderer
50
+
51
+ # Handle printing parameters from raw_data_set
52
+ if hasattr(raw_data_set, "print_parameters"):
53
+ self.printing_parameters = (
54
+ raw_data_set.print_parameters if raw_data_set.print_parameters else {}
55
+ )
56
+ else:
57
+ self.printing_parameters = {}
58
+
59
+ def _repr_html_(self) -> str:
60
+ table_data = TableData(
61
+ headers=self.headers,
62
+ data=self.data,
63
+ parameters=self.printing_parameters,
64
+ raw_data_set=self.raw_data_set,
65
+ )
66
+ return self.renderer_class(table_data).render_html()
67
+
68
+ def __repr__(self):
69
+ from tabulate import tabulate
70
+
71
+ return tabulate(self.data, headers=self.headers, tablefmt=self.tablefmt)
72
+
73
+ @classmethod
74
+ def from_dictionary(
75
+ cls,
76
+ dictionary: dict,
77
+ tablefmt: Optional[TableFormat] = None,
78
+ renderer: Optional[TableRenderer] = None,
79
+ ) -> "TableDisplay":
80
+ headers = list(dictionary.keys())
81
+ data = [list(dictionary.values())]
82
+ return cls(headers, data, tablefmt, renderer_class=renderer)
83
+
84
+ @classmethod
85
+ def from_dictionary_wide(
86
+ cls,
87
+ dictionary: dict,
88
+ tablefmt: Optional[TableFormat] = None,
89
+ renderer: Optional[TableRenderer] = None,
90
+ ) -> "TableDisplay":
91
+ headers = ["key", "value"]
92
+ data = [[k, v] for k, v in dictionary.items()]
93
+ return cls(headers, data, tablefmt, renderer_class=renderer)
94
+
95
+ @classmethod
96
+ def from_dataset(
97
+ cls,
98
+ dataset: "Dataset",
99
+ tablefmt: Optional[TableFormat] = None,
100
+ renderer: Optional[TableRenderer] = None,
101
+ ) -> "TableDisplay":
102
+ headers, data = dataset._tabular()
103
+ return cls(headers, data, tablefmt, dataset, renderer_class=renderer)
104
+
105
+ def long(self) -> "TableDisplay":
106
+ """Convert to long format"""
107
+ new_header = ["row", "key", "value"]
108
+ new_data = []
109
+ for index, row in enumerate(self.data):
110
+ new_data.extend([[index, k, v] for k, v in zip(self.headers, row)])
111
+ return TableDisplay(
112
+ new_header, new_data, self.tablefmt, renderer_class=self.renderer_class
113
+ )
114
+
115
+
116
+ # Example usage:
117
+ if __name__ == "__main__":
118
+ headers = ["Name", "Age", "City"]
119
+ data = [["John", 30, "New York"], ["Jane", 25, "London"]]
120
+
121
+ # Using default (Pandas) renderer
122
+ table1 = TableDisplay(headers, data)
123
+
124
+ # Using DataTables renderer
125
+ table2 = TableDisplay(headers, data, renderer=DataTablesRenderer())
@@ -0,0 +1,50 @@
1
+ try:
2
+ import gradio as gr
3
+ except ImportError:
4
+ print("Gradio is not installed. Please install it using `pip install gradio`")
5
+
6
+ import time
7
+
8
+
9
+ class TextEditor:
10
+ def __init__(self, initial_text=""):
11
+ self.text = initial_text
12
+ self._text_saved = False
13
+
14
+ def save_text(self, new_text):
15
+ self.text = new_text
16
+ self._text_saved = True
17
+ return "Text saved successfully!"
18
+
19
+ def edit_gui(self):
20
+ js_code = """
21
+ async (text) => {
22
+ await navigator.clipboard.writeText(text);
23
+ return "Copied to clipboard!";
24
+ }
25
+ """
26
+
27
+ with gr.Blocks() as interface:
28
+ text_area = gr.Textbox(
29
+ value=self.text, lines=10, label="Edit Text", placeholder="Type here..."
30
+ )
31
+
32
+ with gr.Row():
33
+ save_btn = gr.Button("Save")
34
+ copy_btn = gr.Button("Copy to Clipboard")
35
+
36
+ output = gr.Textbox(label="Status")
37
+
38
+ save_btn.click(fn=self.save_text, inputs=[text_area], outputs=[output])
39
+
40
+ # Add copy functionality
41
+ copy_btn.click(
42
+ fn=None, inputs=text_area, outputs=output, api_name=False, js=js_code
43
+ )
44
+
45
+ interface.launch(share=False, prevent_thread_lock=True)
46
+
47
+ while not self._text_saved:
48
+ time.sleep(0.1)
49
+
50
+ return self.text
edsl/results/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- from edsl.results.Result import Result
2
- from edsl.results.Results import Results
1
+ # from edsl.results.Result import Result
2
+ from edsl.results.Results import Results