edsl 0.1.47__py3-none-any.whl → 0.1.49__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 (314) hide show
  1. edsl/__init__.py +44 -39
  2. edsl/__version__.py +1 -1
  3. edsl/agents/__init__.py +4 -2
  4. edsl/agents/{Agent.py → agent.py} +442 -152
  5. edsl/agents/{AgentList.py → agent_list.py} +220 -162
  6. edsl/agents/descriptors.py +46 -7
  7. edsl/{exceptions/agents.py → agents/exceptions.py} +3 -12
  8. edsl/base/__init__.py +75 -0
  9. edsl/base/base_class.py +1303 -0
  10. edsl/base/data_transfer_models.py +114 -0
  11. edsl/base/enums.py +215 -0
  12. edsl/base.py +8 -0
  13. edsl/buckets/__init__.py +25 -0
  14. edsl/buckets/bucket_collection.py +324 -0
  15. edsl/buckets/model_buckets.py +206 -0
  16. edsl/buckets/token_bucket.py +502 -0
  17. edsl/{jobs/buckets/TokenBucketAPI.py → buckets/token_bucket_api.py} +1 -1
  18. edsl/buckets/token_bucket_client.py +509 -0
  19. edsl/caching/__init__.py +20 -0
  20. edsl/caching/cache.py +814 -0
  21. edsl/caching/cache_entry.py +427 -0
  22. edsl/{data/CacheHandler.py → caching/cache_handler.py} +14 -15
  23. edsl/caching/exceptions.py +24 -0
  24. edsl/caching/orm.py +30 -0
  25. edsl/{data/RemoteCacheSync.py → caching/remote_cache_sync.py} +3 -3
  26. edsl/caching/sql_dict.py +441 -0
  27. edsl/config/__init__.py +8 -0
  28. edsl/config/config_class.py +177 -0
  29. edsl/config.py +4 -176
  30. edsl/conversation/Conversation.py +7 -7
  31. edsl/conversation/car_buying.py +4 -4
  32. edsl/conversation/chips.py +6 -6
  33. edsl/coop/__init__.py +25 -2
  34. edsl/coop/coop.py +311 -75
  35. edsl/coop/{ExpectedParrotKeyHandler.py → ep_key_handling.py} +86 -10
  36. edsl/coop/exceptions.py +62 -0
  37. edsl/coop/price_fetcher.py +126 -0
  38. edsl/coop/utils.py +89 -24
  39. edsl/data_transfer_models.py +5 -72
  40. edsl/dataset/__init__.py +10 -0
  41. edsl/{results/Dataset.py → dataset/dataset.py} +116 -36
  42. edsl/{results/DatasetExportMixin.py → dataset/dataset_operations_mixin.py} +606 -122
  43. edsl/{results/DatasetTree.py → dataset/dataset_tree.py} +156 -75
  44. edsl/{results/TableDisplay.py → dataset/display/table_display.py} +18 -7
  45. edsl/{results → dataset/display}/table_renderers.py +58 -2
  46. edsl/{results → dataset}/file_exports.py +4 -5
  47. edsl/{results → dataset}/smart_objects.py +2 -2
  48. edsl/enums.py +5 -205
  49. edsl/inference_services/__init__.py +5 -0
  50. edsl/inference_services/{AvailableModelCacheHandler.py → available_model_cache_handler.py} +2 -3
  51. edsl/inference_services/{AvailableModelFetcher.py → available_model_fetcher.py} +8 -14
  52. edsl/inference_services/data_structures.py +3 -2
  53. edsl/{exceptions/inference_services.py → inference_services/exceptions.py} +1 -1
  54. edsl/inference_services/{InferenceServiceABC.py → inference_service_abc.py} +1 -1
  55. edsl/inference_services/{InferenceServicesCollection.py → inference_services_collection.py} +8 -7
  56. edsl/inference_services/registry.py +4 -41
  57. edsl/inference_services/{ServiceAvailability.py → service_availability.py} +5 -25
  58. edsl/inference_services/services/__init__.py +31 -0
  59. edsl/inference_services/{AnthropicService.py → services/anthropic_service.py} +3 -3
  60. edsl/inference_services/{AwsBedrock.py → services/aws_bedrock.py} +2 -2
  61. edsl/inference_services/{AzureAI.py → services/azure_ai.py} +2 -2
  62. edsl/inference_services/{DeepInfraService.py → services/deep_infra_service.py} +1 -3
  63. edsl/inference_services/{DeepSeekService.py → services/deep_seek_service.py} +2 -4
  64. edsl/inference_services/{GoogleService.py → services/google_service.py} +5 -4
  65. edsl/inference_services/{GroqService.py → services/groq_service.py} +1 -1
  66. edsl/inference_services/{MistralAIService.py → services/mistral_ai_service.py} +3 -3
  67. edsl/inference_services/{OllamaService.py → services/ollama_service.py} +1 -7
  68. edsl/inference_services/{OpenAIService.py → services/open_ai_service.py} +5 -6
  69. edsl/inference_services/{PerplexityService.py → services/perplexity_service.py} +3 -7
  70. edsl/inference_services/{TestService.py → services/test_service.py} +7 -6
  71. edsl/inference_services/{TogetherAIService.py → services/together_ai_service.py} +2 -6
  72. edsl/inference_services/{XAIService.py → services/xai_service.py} +1 -1
  73. edsl/inference_services/write_available.py +1 -2
  74. edsl/instructions/__init__.py +6 -0
  75. edsl/{surveys/instructions/Instruction.py → instructions/instruction.py} +11 -6
  76. edsl/{surveys/instructions/InstructionCollection.py → instructions/instruction_collection.py} +10 -5
  77. edsl/{surveys/InstructionHandler.py → instructions/instruction_handler.py} +3 -3
  78. edsl/{jobs/interviews → interviews}/ReportErrors.py +2 -2
  79. edsl/interviews/__init__.py +4 -0
  80. edsl/{jobs/AnswerQuestionFunctionConstructor.py → interviews/answering_function.py} +45 -18
  81. edsl/{jobs/interviews/InterviewExceptionEntry.py → interviews/exception_tracking.py} +107 -22
  82. edsl/interviews/interview.py +638 -0
  83. edsl/{jobs/interviews/InterviewStatusDictionary.py → interviews/interview_status_dictionary.py} +21 -12
  84. edsl/{jobs/interviews/InterviewStatusLog.py → interviews/interview_status_log.py} +16 -7
  85. edsl/{jobs/InterviewTaskManager.py → interviews/interview_task_manager.py} +12 -7
  86. edsl/{jobs/RequestTokenEstimator.py → interviews/request_token_estimator.py} +8 -3
  87. edsl/{jobs/interviews/InterviewStatistic.py → interviews/statistics.py} +36 -10
  88. edsl/invigilators/__init__.py +38 -0
  89. edsl/invigilators/invigilator_base.py +477 -0
  90. edsl/{agents/Invigilator.py → invigilators/invigilators.py} +263 -10
  91. edsl/invigilators/prompt_constructor.py +476 -0
  92. edsl/{agents → invigilators}/prompt_helpers.py +2 -1
  93. edsl/{agents/QuestionInstructionPromptBuilder.py → invigilators/question_instructions_prompt_builder.py} +18 -13
  94. edsl/{agents → invigilators}/question_option_processor.py +96 -21
  95. edsl/{agents/QuestionTemplateReplacementsBuilder.py → invigilators/question_template_replacements_builder.py} +64 -12
  96. edsl/jobs/__init__.py +7 -1
  97. edsl/jobs/async_interview_runner.py +99 -35
  98. edsl/jobs/check_survey_scenario_compatibility.py +7 -5
  99. edsl/jobs/data_structures.py +153 -22
  100. edsl/{exceptions/jobs.py → jobs/exceptions.py} +2 -1
  101. edsl/jobs/{FetchInvigilator.py → fetch_invigilator.py} +4 -4
  102. edsl/jobs/{loggers/HTMLTableJobLogger.py → html_table_job_logger.py} +6 -2
  103. edsl/jobs/{Jobs.py → jobs.py} +313 -167
  104. edsl/jobs/{JobsChecks.py → jobs_checks.py} +15 -7
  105. edsl/jobs/{JobsComponentConstructor.py → jobs_component_constructor.py} +19 -17
  106. edsl/jobs/{InterviewsConstructor.py → jobs_interview_constructor.py} +10 -5
  107. edsl/jobs/jobs_pricing_estimation.py +347 -0
  108. edsl/jobs/{JobsRemoteInferenceLogger.py → jobs_remote_inference_logger.py} +4 -3
  109. edsl/jobs/jobs_runner_asyncio.py +282 -0
  110. edsl/jobs/{JobsRemoteInferenceHandler.py → remote_inference.py} +19 -22
  111. edsl/jobs/results_exceptions_handler.py +2 -2
  112. edsl/key_management/__init__.py +28 -0
  113. edsl/key_management/key_lookup.py +161 -0
  114. edsl/{language_models/key_management/KeyLookupBuilder.py → key_management/key_lookup_builder.py} +118 -47
  115. edsl/key_management/key_lookup_collection.py +82 -0
  116. edsl/key_management/models.py +218 -0
  117. edsl/language_models/__init__.py +7 -2
  118. edsl/language_models/{ComputeCost.py → compute_cost.py} +18 -3
  119. edsl/{exceptions/language_models.py → language_models/exceptions.py} +2 -1
  120. edsl/language_models/language_model.py +1080 -0
  121. edsl/language_models/model.py +10 -25
  122. edsl/language_models/{ModelList.py → model_list.py} +9 -14
  123. edsl/language_models/{RawResponseHandler.py → raw_response_handler.py} +1 -1
  124. edsl/language_models/{RegisterLanguageModelsMeta.py → registry.py} +1 -1
  125. edsl/language_models/repair.py +4 -4
  126. edsl/language_models/utilities.py +4 -4
  127. edsl/notebooks/__init__.py +3 -1
  128. edsl/notebooks/{Notebook.py → notebook.py} +7 -8
  129. edsl/prompts/__init__.py +1 -1
  130. edsl/{exceptions/prompts.py → prompts/exceptions.py} +3 -1
  131. edsl/prompts/{Prompt.py → prompt.py} +101 -95
  132. edsl/questions/HTMLQuestion.py +1 -1
  133. edsl/questions/__init__.py +154 -25
  134. edsl/questions/answer_validator_mixin.py +1 -1
  135. edsl/questions/compose_questions.py +4 -3
  136. edsl/questions/derived/question_likert_five.py +166 -0
  137. edsl/questions/derived/{QuestionLinearScale.py → question_linear_scale.py} +4 -4
  138. edsl/questions/derived/{QuestionTopK.py → question_top_k.py} +4 -4
  139. edsl/questions/derived/{QuestionYesNo.py → question_yes_no.py} +4 -5
  140. edsl/questions/descriptors.py +24 -30
  141. edsl/questions/loop_processor.py +65 -19
  142. edsl/questions/question_base.py +881 -0
  143. edsl/questions/question_base_gen_mixin.py +15 -16
  144. edsl/questions/{QuestionBasePromptsMixin.py → question_base_prompts_mixin.py} +2 -2
  145. edsl/questions/{QuestionBudget.py → question_budget.py} +3 -4
  146. edsl/questions/{QuestionCheckBox.py → question_check_box.py} +16 -16
  147. edsl/questions/{QuestionDict.py → question_dict.py} +39 -5
  148. edsl/questions/{QuestionExtract.py → question_extract.py} +9 -9
  149. edsl/questions/question_free_text.py +282 -0
  150. edsl/questions/{QuestionFunctional.py → question_functional.py} +6 -5
  151. edsl/questions/{QuestionList.py → question_list.py} +6 -7
  152. edsl/questions/{QuestionMatrix.py → question_matrix.py} +6 -5
  153. edsl/questions/{QuestionMultipleChoice.py → question_multiple_choice.py} +126 -21
  154. edsl/questions/{QuestionNumerical.py → question_numerical.py} +5 -5
  155. edsl/questions/{QuestionRank.py → question_rank.py} +6 -6
  156. edsl/questions/question_registry.py +4 -9
  157. edsl/questions/register_questions_meta.py +8 -4
  158. edsl/questions/response_validator_abc.py +17 -16
  159. edsl/results/__init__.py +4 -1
  160. edsl/{exceptions/results.py → results/exceptions.py} +1 -1
  161. edsl/results/report.py +197 -0
  162. edsl/results/{Result.py → result.py} +131 -45
  163. edsl/results/{Results.py → results.py} +365 -220
  164. edsl/results/results_selector.py +344 -25
  165. edsl/scenarios/__init__.py +30 -3
  166. edsl/scenarios/{ConstructDownloadLink.py → construct_download_link.py} +7 -0
  167. edsl/scenarios/directory_scanner.py +156 -13
  168. edsl/scenarios/document_chunker.py +186 -0
  169. edsl/scenarios/exceptions.py +101 -0
  170. edsl/scenarios/file_methods.py +2 -3
  171. edsl/scenarios/{FileStore.py → file_store.py} +275 -189
  172. edsl/scenarios/handlers/__init__.py +14 -14
  173. edsl/scenarios/handlers/{csv.py → csv_file_store.py} +1 -2
  174. edsl/scenarios/handlers/{docx.py → docx_file_store.py} +8 -7
  175. edsl/scenarios/handlers/{html.py → html_file_store.py} +1 -2
  176. edsl/scenarios/handlers/{jpeg.py → jpeg_file_store.py} +1 -1
  177. edsl/scenarios/handlers/{json.py → json_file_store.py} +1 -1
  178. edsl/scenarios/handlers/latex_file_store.py +5 -0
  179. edsl/scenarios/handlers/{md.py → md_file_store.py} +1 -1
  180. edsl/scenarios/handlers/{pdf.py → pdf_file_store.py} +2 -2
  181. edsl/scenarios/handlers/{png.py → png_file_store.py} +1 -1
  182. edsl/scenarios/handlers/{pptx.py → pptx_file_store.py} +8 -7
  183. edsl/scenarios/handlers/{py.py → py_file_store.py} +1 -3
  184. edsl/scenarios/handlers/{sql.py → sql_file_store.py} +2 -1
  185. edsl/scenarios/handlers/{sqlite.py → sqlite_file_store.py} +2 -3
  186. edsl/scenarios/handlers/{txt.py → txt_file_store.py} +1 -1
  187. edsl/scenarios/scenario.py +928 -0
  188. edsl/scenarios/scenario_join.py +18 -5
  189. edsl/scenarios/{ScenarioList.py → scenario_list.py} +294 -106
  190. edsl/scenarios/{ScenarioListPdfMixin.py → scenario_list_pdf_tools.py} +16 -15
  191. edsl/scenarios/scenario_selector.py +5 -1
  192. edsl/study/ObjectEntry.py +2 -2
  193. edsl/study/SnapShot.py +5 -5
  194. edsl/study/Study.py +18 -19
  195. edsl/study/__init__.py +6 -4
  196. edsl/surveys/__init__.py +7 -4
  197. edsl/surveys/dag/__init__.py +2 -0
  198. edsl/surveys/{ConstructDAG.py → dag/construct_dag.py} +3 -3
  199. edsl/surveys/{DAG.py → dag/dag.py} +13 -10
  200. edsl/surveys/descriptors.py +1 -1
  201. edsl/surveys/{EditSurvey.py → edit_survey.py} +9 -9
  202. edsl/{exceptions/surveys.py → surveys/exceptions.py} +1 -2
  203. edsl/surveys/memory/__init__.py +3 -0
  204. edsl/surveys/{MemoryPlan.py → memory/memory_plan.py} +10 -9
  205. edsl/surveys/rules/__init__.py +3 -0
  206. edsl/surveys/{Rule.py → rules/rule.py} +103 -43
  207. edsl/surveys/{RuleCollection.py → rules/rule_collection.py} +21 -30
  208. edsl/surveys/{RuleManager.py → rules/rule_manager.py} +19 -13
  209. edsl/surveys/survey.py +1743 -0
  210. edsl/surveys/{SurveyExportMixin.py → survey_export.py} +22 -27
  211. edsl/surveys/{SurveyFlowVisualization.py → survey_flow_visualization.py} +11 -2
  212. edsl/surveys/{Simulator.py → survey_simulator.py} +10 -3
  213. edsl/tasks/__init__.py +32 -0
  214. edsl/{jobs/tasks/QuestionTaskCreator.py → tasks/question_task_creator.py} +115 -57
  215. edsl/tasks/task_creators.py +135 -0
  216. edsl/{jobs/tasks/TaskHistory.py → tasks/task_history.py} +86 -47
  217. edsl/{jobs/tasks → tasks}/task_status_enum.py +91 -7
  218. edsl/tasks/task_status_log.py +85 -0
  219. edsl/tokens/__init__.py +2 -0
  220. edsl/tokens/interview_token_usage.py +53 -0
  221. edsl/utilities/PrettyList.py +1 -1
  222. edsl/utilities/SystemInfo.py +25 -22
  223. edsl/utilities/__init__.py +29 -21
  224. edsl/utilities/gcp_bucket/__init__.py +2 -0
  225. edsl/utilities/gcp_bucket/cloud_storage.py +99 -96
  226. edsl/utilities/interface.py +44 -536
  227. edsl/{results/MarkdownToPDF.py → utilities/markdown_to_pdf.py} +13 -5
  228. edsl/utilities/repair_functions.py +1 -1
  229. {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/METADATA +1 -1
  230. edsl-0.1.49.dist-info/RECORD +347 -0
  231. edsl/Base.py +0 -493
  232. edsl/BaseDiff.py +0 -260
  233. edsl/agents/InvigilatorBase.py +0 -260
  234. edsl/agents/PromptConstructor.py +0 -318
  235. edsl/coop/PriceFetcher.py +0 -54
  236. edsl/data/Cache.py +0 -582
  237. edsl/data/CacheEntry.py +0 -238
  238. edsl/data/SQLiteDict.py +0 -292
  239. edsl/data/__init__.py +0 -5
  240. edsl/data/orm.py +0 -10
  241. edsl/exceptions/cache.py +0 -5
  242. edsl/exceptions/coop.py +0 -14
  243. edsl/exceptions/data.py +0 -14
  244. edsl/exceptions/scenarios.py +0 -29
  245. edsl/jobs/Answers.py +0 -43
  246. edsl/jobs/JobsPrompts.py +0 -354
  247. edsl/jobs/buckets/BucketCollection.py +0 -134
  248. edsl/jobs/buckets/ModelBuckets.py +0 -65
  249. edsl/jobs/buckets/TokenBucket.py +0 -283
  250. edsl/jobs/buckets/TokenBucketClient.py +0 -191
  251. edsl/jobs/interviews/Interview.py +0 -395
  252. edsl/jobs/interviews/InterviewExceptionCollection.py +0 -99
  253. edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -25
  254. edsl/jobs/runners/JobsRunnerAsyncio.py +0 -163
  255. edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
  256. edsl/jobs/tasks/TaskCreators.py +0 -64
  257. edsl/jobs/tasks/TaskStatusLog.py +0 -23
  258. edsl/jobs/tokens/InterviewTokenUsage.py +0 -27
  259. edsl/language_models/LanguageModel.py +0 -635
  260. edsl/language_models/ServiceDataSources.py +0 -0
  261. edsl/language_models/key_management/KeyLookup.py +0 -63
  262. edsl/language_models/key_management/KeyLookupCollection.py +0 -38
  263. edsl/language_models/key_management/models.py +0 -137
  264. edsl/questions/QuestionBase.py +0 -544
  265. edsl/questions/QuestionFreeText.py +0 -130
  266. edsl/questions/derived/QuestionLikertFive.py +0 -76
  267. edsl/results/ResultsExportMixin.py +0 -45
  268. edsl/results/TextEditor.py +0 -50
  269. edsl/results/results_fetch_mixin.py +0 -33
  270. edsl/results/results_tools_mixin.py +0 -98
  271. edsl/scenarios/DocumentChunker.py +0 -104
  272. edsl/scenarios/Scenario.py +0 -548
  273. edsl/scenarios/ScenarioHtmlMixin.py +0 -65
  274. edsl/scenarios/ScenarioListExportMixin.py +0 -45
  275. edsl/scenarios/handlers/latex.py +0 -5
  276. edsl/shared.py +0 -1
  277. edsl/surveys/Survey.py +0 -1301
  278. edsl/surveys/SurveyQualtricsImport.py +0 -284
  279. edsl/surveys/SurveyToApp.py +0 -141
  280. edsl/surveys/instructions/__init__.py +0 -0
  281. edsl/tools/__init__.py +0 -1
  282. edsl/tools/clusters.py +0 -192
  283. edsl/tools/embeddings.py +0 -27
  284. edsl/tools/embeddings_plotting.py +0 -118
  285. edsl/tools/plotting.py +0 -112
  286. edsl/tools/summarize.py +0 -18
  287. edsl/utilities/data/Registry.py +0 -6
  288. edsl/utilities/data/__init__.py +0 -1
  289. edsl/utilities/data/scooter_results.json +0 -1
  290. edsl-0.1.47.dist-info/RECORD +0 -354
  291. /edsl/coop/{CoopFunctionsMixin.py → coop_functions.py} +0 -0
  292. /edsl/{results → dataset/display}/CSSParameterizer.py +0 -0
  293. /edsl/{language_models/key_management → dataset/display}/__init__.py +0 -0
  294. /edsl/{results → dataset/display}/table_data_class.py +0 -0
  295. /edsl/{results → dataset/display}/table_display.css +0 -0
  296. /edsl/{results/ResultsGGMixin.py → dataset/r/ggplot.py} +0 -0
  297. /edsl/{results → dataset}/tree_explore.py +0 -0
  298. /edsl/{surveys/instructions/ChangeInstruction.py → instructions/change_instruction.py} +0 -0
  299. /edsl/{jobs/interviews → interviews}/interview_status_enum.py +0 -0
  300. /edsl/jobs/{runners/JobsRunnerStatus.py → jobs_runner_status.py} +0 -0
  301. /edsl/language_models/{PriceManager.py → price_manager.py} +0 -0
  302. /edsl/language_models/{fake_openai_call.py → unused/fake_openai_call.py} +0 -0
  303. /edsl/language_models/{fake_openai_service.py → unused/fake_openai_service.py} +0 -0
  304. /edsl/notebooks/{NotebookToLaTeX.py → notebook_to_latex.py} +0 -0
  305. /edsl/{exceptions/questions.py → questions/exceptions.py} +0 -0
  306. /edsl/questions/{SimpleAskMixin.py → simple_ask_mixin.py} +0 -0
  307. /edsl/surveys/{Memory.py → memory/memory.py} +0 -0
  308. /edsl/surveys/{MemoryManagement.py → memory/memory_management.py} +0 -0
  309. /edsl/surveys/{SurveyCSS.py → survey_css.py} +0 -0
  310. /edsl/{jobs/tokens/TokenUsage.py → tokens/token_usage.py} +0 -0
  311. /edsl/{results/MarkdownToDocx.py → utilities/markdown_to_docx.py} +0 -0
  312. /edsl/{TemplateLoader.py → utilities/template_loader.py} +0 -0
  313. {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/LICENSE +0 -0
  314. {edsl-0.1.47.dist-info → edsl-0.1.49.dist-info}/WHEEL +0 -0
@@ -1,37 +1,62 @@
1
- """A module for displaying data in various formats."""
1
+ """A module for displaying data in various formats.
2
2
 
3
- from html import escape
3
+ This module provides utility functions for formatting and displaying data,
4
+ primarily used by the Results module for printing results.
5
+ """
4
6
 
7
+ # Only print_results_long is actively used in the codebase (in results.py)
8
+ # The rest of the functions are kept for reference but are not imported in __init__.py
5
9
 
10
+
11
+ def print_results_long(results, max_rows=None):
12
+ """
13
+ Format results data as a rich console table with columns for index, key, and value.
14
+
15
+ Args:
16
+ results: The Results object to display
17
+ max_rows: Optional maximum number of rows to display
18
+ """
19
+ from rich.console import Console
20
+ from rich.table import Table
21
+
22
+ console = Console(record=True)
23
+ table = Table(show_header=True, header_style="bold magenta")
24
+ table.add_column("Result index", style="dim")
25
+ table.add_column("Key", style="dim")
26
+ table.add_column("Value", style="dim")
27
+ list_of_dicts = results.to_dicts()
28
+ num_rows = 0
29
+ for i, results_dict in enumerate(list_of_dicts):
30
+ for key, value in results_dict.items():
31
+ table.add_row(str(i), key, str(value))
32
+ num_rows += 1
33
+ if max_rows is not None and num_rows >= max_rows:
34
+ break
35
+ console.print(table)
36
+
37
+
38
+ # The rest of these functions are not actively used by the codebase
39
+ # They are kept but commented out for potential future reference
40
+
41
+ """
6
42
  def create_image(console, image_filename):
7
- """Create an image from the console output."""
8
43
  font_size = 15
9
44
  from PIL import Image, ImageDraw, ImageFont
10
45
 
11
- text = console.export_text() # Get the console output as text.
46
+ text = console.export_text()
12
47
 
13
- # Create an image from the text
14
48
  font_size = 15
15
- font = ImageFont.load_default() # Use the default font to avoid file path issues.
16
- # text_width, text_height = ImageDraw.Draw(
17
- # Image.new("RGB", (100, 100))
18
- # ).multiline_textsize(text, font=font)
49
+ font = ImageFont.load_default()
19
50
  text_width, text_height = get_multiline_textsize(text, font)
20
51
  image = Image.new(
21
52
  "RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
22
- ) # Add some padding
53
+ )
23
54
  d = ImageDraw.Draw(image)
24
-
25
- # Draw text to image
26
55
  d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
27
- # Save the image
28
56
  image.save(image_filename)
29
57
 
30
58
 
31
59
  def display_table(console, table, filename):
32
- # from rich.console import Console
33
- # from rich.table import Table
34
- """Display the table using the rich library and save it to a file if a filename is provided."""
35
60
  if filename is not None:
36
61
  with open(filename, "w") as f:
37
62
  with console.capture() as capture:
@@ -43,162 +68,34 @@ def display_table(console, table, filename):
43
68
 
44
69
 
45
70
  def gen_html_sandwich(html_inner, interactive=False):
46
- """Wrap the inner HTML content in a header and footer to make a complete HTML document."""
47
71
  return html_inner
48
- if interactive:
49
- html_header = """
50
- <html>
51
- <head>
52
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
53
- <link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.css" />
54
- <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.js"></script>
55
- <style>
56
- table {
57
- font-family: Arial, sans-serif;
58
- border-collapse: collapse;
59
- width: 100%;
60
- }
61
-
62
- td, th {
63
- border: 1px solid #dddddd;
64
- text-align: left;
65
- padding: 8px;
66
- }
67
-
68
- tr:nth-child(even) {
69
- background-color: #dddddd;
70
- }
71
- </style>
72
- <script>
73
- $(document).ready( function () {
74
- $('#myTable').DataTable();
75
- } )
76
- </script>
77
- </head>
78
- <body>
79
- """
80
- else:
81
- html_header = """
82
- <html>
83
- <head>
84
- <style>
85
- table {
86
- font-family: Arial, sans-serif;
87
- border-collapse: collapse;
88
- width: 100%;
89
- }
90
-
91
- td, th {
92
- border: 1px solid #dddddd;
93
- text-align: left;
94
- padding: 8px;
95
- }
96
-
97
- tr:nth-child(even) {
98
- background-color: #dddddd;
99
- }
100
- </style>
101
- </head>
102
- <body>
103
- """
104
-
105
- html_footer = """
106
- </body>
107
- </html>
108
- """
109
- return html_header + html_inner + html_footer
110
72
 
111
73
 
112
74
  def view_html(html):
113
- """Display HTML content in a web browser."""
114
75
  import tempfile
115
76
  import webbrowser
116
77
 
117
78
  with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html") as f:
118
79
  url = "file://" + f.name
119
- # Write the HTML content to the file
120
80
  f.write(html)
121
-
122
- # Open the URL in the web browser
123
81
  webbrowser.open(url)
124
82
 
125
83
 
126
- def human_readable_labeler_creator():
127
- """Create a function that maps thread ids to human-readable labels.
128
-
129
- It is structured as a closure, so that the mapping is persistent.
130
- I.e., when the returned function is called, it will use the same
131
- dictionary to map thread ids to human-readable labels if it's seen that ID
132
- before; otherwise, it will add a new entry to the dictionary.
133
- This will persist across calls to the function.
134
- """
135
- d = {}
136
-
137
- def func(thread_id):
138
- if thread_id in d:
139
- return d[thread_id]
140
- else:
141
- d[thread_id] = len(d)
142
- return d[thread_id]
143
-
144
- return func
145
-
146
-
147
84
  def get_multiline_textsize(text, font):
148
- """Get the size of the text when it is drawn on an image."""
149
85
  lines = text.split("\n")
150
-
151
- # Initialize width and height
152
86
  max_width = 0
153
87
  total_height = 0
154
88
 
155
89
  for line in lines:
156
- # Get the size of the text for the line
157
90
  box = font.getbbox(line)
158
91
  width, height = box[2], box[3]
159
-
160
- # Update max_width if width of the current line is greater than max_width
161
92
  max_width = max(max_width, width)
162
-
163
- # Add height to total_height
164
93
  total_height += height
165
94
 
166
95
  return max_width, total_height
167
96
 
168
97
 
169
- def print_results_long(results, max_rows=None):
170
- from rich.console import Console
171
- from rich.table import Table
172
-
173
- console = Console(record=True)
174
- table = Table(show_header=True, header_style="bold magenta")
175
- table.add_column("Result index", style="dim")
176
- table.add_column("Key", style="dim")
177
- table.add_column("Value", style="dim")
178
- list_of_dicts = results.to_dicts()
179
- num_rows = 0
180
- for i, results_dict in enumerate(list_of_dicts):
181
- for key, value in results_dict.items():
182
- table.add_row(str(i), key, str(value))
183
- num_rows += 1
184
- if max_rows is not None and num_rows >= max_rows:
185
- break
186
- console.print(table)
187
-
188
-
189
98
  def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
190
- """Print a dictionary as a table using the rich library.
191
-
192
- Example:
193
- >>> print_dict_with_rich({"a": 1, "b": 2, "c": 3})
194
- ┏━━━━━┳━━━━━━━┓
195
- ┃ Key ┃ Value ┃
196
- ┡━━━━━╇━━━━━━━┩
197
- │ a │ 1 │
198
- │ b │ 2 │
199
- │ c │ 3 │
200
- └─────┴───────┘
201
- """
202
99
  from rich.console import Console
203
100
  from rich.table import Table
204
101
 
@@ -209,419 +106,30 @@ def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
209
106
  for key, value in d.items():
210
107
  table.add_row(key, str(value))
211
108
  console.print(table)
212
- # display_table(console, table, filename)
213
-
214
-
215
- def print_dict_as_html_table(
216
- d,
217
- show=False,
218
- key_name="Key",
219
- value_name="Value",
220
- filename=None,
221
- ):
222
- """Print a dictionary as an HTML table.
223
-
224
- :param d: The dictionary to print.
225
- :param show: Whether to display the HTML table in the browser.
226
- :param key_name: The name of the key column.
227
- :param value_name: The name of the value column.
228
- :param filename: The name of the file to save the HTML table to.
229
- """
230
- # Start the HTML table
231
- html_table = f'<table border="1">\n<tr><th>{escape(key_name)}</th><th>{escape(value_name)}</th></tr>\n'
232
-
233
- # Add rows to the HTML table
234
- for key, value in d.items():
235
- html_table += (
236
- f"<tr><td>{escape(str(key))}</td><td>{escape(str(value))}</td></tr>\n"
237
- )
238
-
239
- # Close the HTML table
240
- html_table += "</table>"
241
-
242
- # Print the HTML table to console
243
- # print(html_table)
244
-
245
- # Write to file if a filename is provided
246
- if filename:
247
- with open(filename, "w") as file:
248
- file.write(html_table)
249
- else:
250
- if show:
251
- view_html(gen_html_sandwich(html_table))
252
- else:
253
- return html_table
254
-
255
-
256
- def print_scenario_list(data):
257
- from rich.console import Console
258
- from rich.table import Table
259
-
260
- new_data = []
261
- for obs in data:
262
- try:
263
- _ = obs.pop("edsl_version")
264
- _ = obs.pop("edsl_class_name")
265
- except KeyError as e:
266
- # print(e)
267
- pass
268
- new_data.append(obs)
269
-
270
- columns = list(new_data[0].keys())
271
- console = Console(record=True)
272
-
273
- # Create a table object
274
- table = Table(show_header=True, header_style="bold magenta", show_lines=True)
275
- for column in columns:
276
- table.add_column(column, style="dim")
277
-
278
- for obs in new_data:
279
- row = [str(obs[key]) for key in columns]
280
- table.add_row(*row)
281
-
282
- console.print(table)
283
-
284
-
285
- def print_list_of_dicts_with_rich(data, filename=None, split_at_dot=True):
286
- raise Exception(
287
- "print_list_of_dicts_with_rich is now called print_dataset_with_rich"
288
- )
289
-
290
-
291
- def print_dataset_with_rich(data, filename=None, split_at_dot=True):
292
- """Initialize console object."""
293
- """
294
- The list seems superfluous.
295
- This prints a list of dictionaries as a table using the rich library.
296
-
297
- >>> data = [{"a": [1, 2, 3], "b": [4, 5, 6]}]
298
- >>> print_list_of_dicts_with_rich(data)
299
- ┏━━━┳━━━┓
300
- ┃ a ┃ b ┃
301
- ┡━━━╇━━━┩
302
- │ 1 │ 4 │
303
- ├───┼───┤
304
- │ 2 │ 5 │
305
- ├───┼───┤
306
- │ 3 │ 6 │
307
- └───┴───┘
308
- """
309
- from rich.console import Console
310
- from rich.table import Table
311
-
312
- console = Console(record=True)
313
-
314
- # Create a table object
315
- table = Table(show_header=True, header_style="bold magenta", show_lines=True)
316
-
317
- # Adding columns to the table
318
- for d in data:
319
- for key in d.keys():
320
- if split_at_dot:
321
- value = key.replace(".", "\n.")
322
- else:
323
- value = key
324
- table.add_column(value, style="dim")
325
-
326
- # Adding rows to the table
327
- num_rows = len(next(iter(data[0].values())))
328
- for i in range(num_rows):
329
- row = [str(d[key][i]) for d in data for key in d.keys()]
330
- table.add_row(*row)
331
-
332
- console.print(table)
333
- # display_table(console, table, filename)
334
-
335
-
336
- def create_latex_table_from_data(data, filename=None, split_at_dot=True):
337
- """
338
- This function takes a list of dictionaries and returns a LaTeX table as a string.
339
- The table can either be printed or written to a file.
340
-
341
- >>> data = [{"a": [1, 2, 3], "b": [4, 5, 6]}]
342
- >>> print(create_latex_table_from_data(data))
343
- \\begin{tabular}{|c|c|}
344
- \\hline
345
- a & b \\\\
346
- \\hline
347
- 1 & 4 \\\\
348
- 2 & 5 \\\\
349
- 3 & 6 \\\\
350
- \\hline
351
- \\end{tabular}
352
- """
353
-
354
- def escape_latex(s):
355
- replacements = [
356
- ("_", r"\_"),
357
- ("&", r"\&"),
358
- ("%", r"\%"),
359
- ("$", r"\$"),
360
- ("#", r"\#"),
361
- ("{", r"\{"),
362
- ("}", r"\}"),
363
- ("~", r"\textasciitilde{}"),
364
- ("^", r"\textasciicircum{}"),
365
- ("\\", r"\textbackslash{}"),
366
- ]
367
-
368
- for old, new in replacements:
369
- s = s.replace(old, new)
370
- return s
371
-
372
- # Start the LaTeX table
373
- latex_table = ["\\begin{tabular}{|" + "c|" * len(data[0]) + "}"]
374
- latex_table.append("\\hline")
375
-
376
- # Add the header row
377
- headers = []
378
- for key in data[0].keys():
379
- if split_at_dot:
380
- value = key.replace(".", "\n.")
381
- else:
382
- value = key
383
- headers.append(escape_latex(value))
384
- latex_table.append(" & ".join(headers) + " \\\\")
385
- latex_table.append("\\hline")
386
-
387
- # Determine the number of rows
388
- num_rows = len(next(iter(data[0].values())))
389
-
390
- # Debugging: Print the keys of the dictionaries
391
- # print("Keys in data[0]:", list(data[0].keys()))
392
-
393
- # Add the data rows
394
- for i in range(num_rows):
395
- row = []
396
- for key in data[0].keys():
397
- for d in data:
398
- try:
399
- row.append(escape_latex(str(d[key][i])))
400
- except KeyError as e:
401
- print(
402
- f"KeyError: {e} - Key '{key}' not found in data dictionary. The keys are {list(d.keys())}"
403
- )
404
- raise
405
- latex_table.append(" & ".join(row) + " \\\\")
406
-
407
- latex_table.append("\\hline")
408
- latex_table.append("\\end{tabular}")
409
-
410
- # Join all parts into a single string
411
- latex_table_str = "\n".join(latex_table)
412
-
413
- # Write to file if filename is provided
414
- if filename:
415
- with open(filename, "w") as f:
416
- f.write(latex_table_str)
417
- print(f"Table written to {filename}")
418
-
419
- return latex_table_str
420
-
421
-
422
- def print_list_of_dicts_as_html_table(data, interactive=True):
423
- """Print a list of dictionaries as an HTML table.
424
-
425
- :param data: The list of dictionaries to print.
426
- :param filename: The name of the file to save the HTML table to.
427
- :param interactive: Whether to make the table interactive using DataTables.
428
- """
429
- style = """
430
- <style>
431
- table {
432
- width: 100%;
433
- border-collapse: collapse;
434
- }
435
- table, th, td {
436
- border: 1px solid black;
437
- }
438
- th, td {
439
- padding: 10px;
440
- text-align: left;
441
- }
442
- </style>
443
- """
444
- html_table = style + '<table id="myTable" class="display">\n'
445
- html_table += " <thead>\n"
446
- # Add the header row
447
- headers = [key for d in data for key in d.keys()]
448
- html_table += " <tr>\n"
449
- for header in headers:
450
- html_table += f" <th>{header}</th>\n"
451
- html_table += " </tr>\n"
452
- html_table += " </thead>\n</tbody>\n"
453
-
454
- # Determine the number of rows
455
- num_rows = max(len(values) for d in data for values in d.values())
456
-
457
- # Add the data rows
458
- for i in range(num_rows):
459
- html_table += " <tr>\n"
460
- for d in data:
461
- for key in d.keys():
462
- value = d[key][i] if i < len(d[key]) else ""
463
- html_table += f" <td>{value}</td>\n"
464
- html_table += " </tr>\n"
465
-
466
- # Close the table
467
- html_table += "</tbody>\n"
468
- html_table += "</table>"
469
- return gen_html_sandwich(html_table, interactive=interactive)
470
-
471
-
472
- def print_list_of_dicts_as_markdown_table(data, filename=None):
473
- """Print a list of dictionaries as a Markdown table.
474
-
475
- :param data: The list of dictionaries to print.
476
- :param filename: The name of the file to save the Markdown table to.
477
- """
478
- if not data:
479
- print("No data provided")
480
- return
481
-
482
- # Gather all unique headers
483
- # headers = list({key for d in data for key in d.keys()})
484
- headers = []
485
- for column in data:
486
- headers.append(list(column.keys())[0])
487
-
488
- markdown_table = "| " + " | ".join(headers) + " |\n"
489
- markdown_table += "|-" + "-|-".join(["" for _ in headers]) + "-|\n"
490
-
491
- num_rows = len(next(iter(data[0].values())))
492
- for i in range(num_rows):
493
- row = [str(d[key][i]) for d in data for key in d.keys()]
494
- # table.add_row(*row)
495
- markdown_table += "| " + " | ".join(row) + " |\n"
496
-
497
- # Output or save to file
498
- if filename:
499
- with open(filename, "w") as f:
500
- f.write(markdown_table)
501
- else:
502
- print(markdown_table)
503
-
504
-
505
- def print_public_methods_with_doc(obj):
506
- """Print the public methods of an object along with their docstrings."""
507
- from rich.console import Console
508
- from rich.table import Table
509
-
510
- console = Console()
511
- public_methods_with_docstrings = [
512
- (method, getattr(obj, method).__doc__)
513
- for method in dir(obj)
514
- if callable(getattr(obj, method))
515
- and not method.startswith("_")
516
- and method != "methods"
517
- ]
518
-
519
- for method, doc in public_methods_with_docstrings:
520
- if doc:
521
- console.print(f"[bold]{method}:[/bold]", style="green")
522
- console.print(f"\t{doc.strip()}", style="yellow")
523
-
524
-
525
- def print_tally_with_rich(data, filename=None):
526
- """Print a tally of values in a list using the rich library.
527
-
528
- Example:
529
- >>> data = {'a':12, 'b':14, 'c':9}
530
- >>> print_tally_with_rich(data)
531
- ┏━━━━━━━┳━━━━━━━┓
532
- ┃ Value ┃ Count ┃
533
- ┡━━━━━━━╇━━━━━━━┩
534
- │ a │ 12 │
535
- │ b │ 14 │
536
- │ c │ 9 │
537
- └───────┴───────┘
538
- """
539
- # Initialize a console object
540
- from rich.console import Console
541
- from rich.table import Table
542
- from IPython.display import display
543
-
544
- console = Console(record=True)
545
-
546
- # Create a new table
547
- table = Table(show_header=True, header_style="bold magenta", row_styles=["", "dim"])
548
-
549
- # Add columns to the table
550
- table.add_column("Value", style="dim")
551
- table.add_column("Count", style="dim")
552
-
553
- # Add rows to the table
554
- for key, value in data.items():
555
- table.add_row(key, str(value))
556
-
557
- from IPython.display import display
558
-
559
- display_table(console, table, filename)
560
109
 
561
110
 
562
111
  def print_table_with_rich(data, filename=None):
563
- """Print a list of dictionaries as a table using the rich library.
564
-
565
- Example:
566
- >>> data = [{"a": 1, "b": 2, "c": 3}]
567
- >>> print_table_with_rich(data)
568
- ┏━━━┳━━━┳━━━┓
569
- ┃ a ┃ b ┃ c ┃
570
- ┡━━━╇━━━╇━━━┩
571
- │ 1 │ 2 │ 3 │
572
- └───┴───┴───┘
573
- >>> data = [{"a": 1, "b": 2, "c": 3},{"a": 2, "b": 9, "c": 8}]
574
- >>> print_table_with_rich(data)
575
- ┏━━━┳━━━┳━━━┓
576
- ┃ a ┃ b ┃ c ┃
577
- ┡━━━╇━━━╇━━━┩
578
- │ 1 │ 2 │ 3 │
579
- │ 2 │ 9 │ 8 │
580
- └───┴───┴───┘
581
- """
582
112
  from rich.console import Console
583
113
  from rich.table import Table
584
114
 
585
- # Initialize a console object - expects a list of dictionaries
586
115
  console = Console(record=True)
587
-
588
- # Create a new table
589
116
  table = Table(show_header=True, header_style="bold magenta", row_styles=["", "dim"])
590
117
 
591
- # Check if data is empty; if it is, exit
592
118
  if not data:
593
119
  console.print("No data provided!")
594
120
  return
595
121
 
596
- # Add columns based on keys in the first dictionary
597
122
  for key in data[0].keys():
598
123
  table.add_column(key, style="dim")
599
124
 
600
- # Add rows to the table
601
125
  for row in data:
602
126
  table.add_row(*[str(value) for value in row.values()])
603
127
 
604
- display_table(console, table, filename)
128
+ console.print(table)
129
+ """
605
130
 
606
131
 
607
132
  if __name__ == "__main__":
608
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3})
609
133
  import doctest
610
134
 
611
- doctest.testmod()
612
- # print_list_of_dicts_with_rich([{"a": [1, 2, 3], "b": [4, 5, 6]}])
613
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html")
614
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, show=True)
615
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
616
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
617
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
618
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
619
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
620
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
621
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
622
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
623
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
624
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
625
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=True)
626
- # print_dict_as_html_table({"a": 1, "b": 2, "c": 3}, filename="test.html", show=False)
627
- # print_dict_as_html_table({"a": 1, "b": 2, "c
135
+ doctest.testmod()
@@ -15,18 +15,26 @@ class MarkdownToPDF:
15
15
  """
16
16
  self.markdown_content = markdown_content
17
17
  self.filename = filename
18
- self._check_pandoc()
18
+ self.has_pandoc = self._check_pandoc()
19
19
  # self.convert()
20
20
 
21
21
  def _check_pandoc(self):
22
- """Check if pandoc is installed and accessible."""
22
+ """
23
+ Check if pandoc is installed and accessible.
24
+
25
+ Returns:
26
+ bool: True if pandoc is available, False otherwise
27
+ """
23
28
  try:
24
29
  subprocess.run(["pandoc", "--version"], capture_output=True, check=True)
30
+ return True
25
31
  except (subprocess.CalledProcessError, FileNotFoundError):
26
- raise RuntimeError(
32
+ import warnings
33
+ warnings.warn(
27
34
  "Pandoc is not installed or not found in PATH. "
28
- "Please install pandoc before using this converter."
35
+ "PDF conversion will not be available."
29
36
  )
37
+ return False
30
38
 
31
39
  def convert(self, output_path: str, **options) -> bool:
32
40
  """
@@ -104,7 +112,7 @@ class MarkdownToPDF:
104
112
  temp_pdf = os.path.join(temp_dir, "preview.pdf")
105
113
 
106
114
  if self.convert(temp_pdf):
107
- from edsl.scenarios.FileStore import FileStore
115
+ from ..scenarios import FileStore
108
116
 
109
117
  return FileStore(temp_pdf)
110
118