edsl 0.1.47__py3-none-any.whl → 0.1.48__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/__init__.py +44 -39
- edsl/__version__.py +1 -1
- edsl/agents/__init__.py +4 -2
- edsl/agents/{Agent.py → agent.py} +442 -152
- edsl/agents/{AgentList.py → agent_list.py} +220 -162
- edsl/agents/descriptors.py +46 -7
- edsl/{exceptions/agents.py → agents/exceptions.py} +3 -12
- edsl/base/__init__.py +75 -0
- edsl/base/base_class.py +1303 -0
- edsl/base/data_transfer_models.py +114 -0
- edsl/base/enums.py +215 -0
- edsl/base.py +8 -0
- edsl/buckets/__init__.py +25 -0
- edsl/buckets/bucket_collection.py +324 -0
- edsl/buckets/model_buckets.py +206 -0
- edsl/buckets/token_bucket.py +502 -0
- edsl/{jobs/buckets/TokenBucketAPI.py → buckets/token_bucket_api.py} +1 -1
- edsl/buckets/token_bucket_client.py +509 -0
- edsl/caching/__init__.py +20 -0
- edsl/caching/cache.py +814 -0
- edsl/caching/cache_entry.py +427 -0
- edsl/{data/CacheHandler.py → caching/cache_handler.py} +14 -15
- edsl/caching/exceptions.py +24 -0
- edsl/caching/orm.py +30 -0
- edsl/{data/RemoteCacheSync.py → caching/remote_cache_sync.py} +3 -3
- edsl/caching/sql_dict.py +441 -0
- edsl/config/__init__.py +8 -0
- edsl/config/config_class.py +177 -0
- edsl/config.py +4 -176
- edsl/conversation/Conversation.py +7 -7
- edsl/conversation/car_buying.py +4 -4
- edsl/conversation/chips.py +6 -6
- edsl/coop/__init__.py +25 -2
- edsl/coop/coop.py +303 -67
- edsl/coop/{ExpectedParrotKeyHandler.py → ep_key_handling.py} +86 -10
- edsl/coop/exceptions.py +62 -0
- edsl/coop/price_fetcher.py +126 -0
- edsl/coop/utils.py +89 -24
- edsl/data_transfer_models.py +5 -72
- edsl/dataset/__init__.py +10 -0
- edsl/{results/Dataset.py → dataset/dataset.py} +116 -36
- edsl/{results/DatasetExportMixin.py → dataset/dataset_operations_mixin.py} +606 -122
- edsl/{results/DatasetTree.py → dataset/dataset_tree.py} +156 -75
- edsl/{results/TableDisplay.py → dataset/display/table_display.py} +18 -7
- edsl/{results → dataset/display}/table_renderers.py +58 -2
- edsl/{results → dataset}/file_exports.py +4 -5
- edsl/{results → dataset}/smart_objects.py +2 -2
- edsl/enums.py +5 -205
- edsl/inference_services/__init__.py +5 -0
- edsl/inference_services/{AvailableModelCacheHandler.py → available_model_cache_handler.py} +2 -3
- edsl/inference_services/{AvailableModelFetcher.py → available_model_fetcher.py} +8 -14
- edsl/inference_services/data_structures.py +3 -2
- edsl/{exceptions/inference_services.py → inference_services/exceptions.py} +1 -1
- edsl/inference_services/{InferenceServiceABC.py → inference_service_abc.py} +1 -1
- edsl/inference_services/{InferenceServicesCollection.py → inference_services_collection.py} +8 -7
- edsl/inference_services/registry.py +4 -41
- edsl/inference_services/{ServiceAvailability.py → service_availability.py} +5 -25
- edsl/inference_services/services/__init__.py +31 -0
- edsl/inference_services/{AnthropicService.py → services/anthropic_service.py} +3 -3
- edsl/inference_services/{AwsBedrock.py → services/aws_bedrock.py} +2 -2
- edsl/inference_services/{AzureAI.py → services/azure_ai.py} +2 -2
- edsl/inference_services/{DeepInfraService.py → services/deep_infra_service.py} +1 -3
- edsl/inference_services/{DeepSeekService.py → services/deep_seek_service.py} +2 -4
- edsl/inference_services/{GoogleService.py → services/google_service.py} +5 -4
- edsl/inference_services/{GroqService.py → services/groq_service.py} +1 -1
- edsl/inference_services/{MistralAIService.py → services/mistral_ai_service.py} +3 -3
- edsl/inference_services/{OllamaService.py → services/ollama_service.py} +1 -7
- edsl/inference_services/{OpenAIService.py → services/open_ai_service.py} +5 -6
- edsl/inference_services/{PerplexityService.py → services/perplexity_service.py} +3 -7
- edsl/inference_services/{TestService.py → services/test_service.py} +7 -6
- edsl/inference_services/{TogetherAIService.py → services/together_ai_service.py} +2 -6
- edsl/inference_services/{XAIService.py → services/xai_service.py} +1 -1
- edsl/inference_services/write_available.py +1 -2
- edsl/instructions/__init__.py +6 -0
- edsl/{surveys/instructions/Instruction.py → instructions/instruction.py} +11 -6
- edsl/{surveys/instructions/InstructionCollection.py → instructions/instruction_collection.py} +10 -5
- edsl/{surveys/InstructionHandler.py → instructions/instruction_handler.py} +3 -3
- edsl/{jobs/interviews → interviews}/ReportErrors.py +2 -2
- edsl/interviews/__init__.py +4 -0
- edsl/{jobs/AnswerQuestionFunctionConstructor.py → interviews/answering_function.py} +45 -18
- edsl/{jobs/interviews/InterviewExceptionEntry.py → interviews/exception_tracking.py} +107 -22
- edsl/interviews/interview.py +638 -0
- edsl/{jobs/interviews/InterviewStatusDictionary.py → interviews/interview_status_dictionary.py} +21 -12
- edsl/{jobs/interviews/InterviewStatusLog.py → interviews/interview_status_log.py} +16 -7
- edsl/{jobs/InterviewTaskManager.py → interviews/interview_task_manager.py} +12 -7
- edsl/{jobs/RequestTokenEstimator.py → interviews/request_token_estimator.py} +8 -3
- edsl/{jobs/interviews/InterviewStatistic.py → interviews/statistics.py} +36 -10
- edsl/invigilators/__init__.py +38 -0
- edsl/invigilators/invigilator_base.py +477 -0
- edsl/{agents/Invigilator.py → invigilators/invigilators.py} +263 -10
- edsl/invigilators/prompt_constructor.py +476 -0
- edsl/{agents → invigilators}/prompt_helpers.py +2 -1
- edsl/{agents/QuestionInstructionPromptBuilder.py → invigilators/question_instructions_prompt_builder.py} +18 -13
- edsl/{agents → invigilators}/question_option_processor.py +96 -21
- edsl/{agents/QuestionTemplateReplacementsBuilder.py → invigilators/question_template_replacements_builder.py} +64 -12
- edsl/jobs/__init__.py +7 -1
- edsl/jobs/async_interview_runner.py +99 -35
- edsl/jobs/check_survey_scenario_compatibility.py +7 -5
- edsl/jobs/data_structures.py +153 -22
- edsl/{exceptions/jobs.py → jobs/exceptions.py} +2 -1
- edsl/jobs/{FetchInvigilator.py → fetch_invigilator.py} +4 -4
- edsl/jobs/{loggers/HTMLTableJobLogger.py → html_table_job_logger.py} +6 -2
- edsl/jobs/{Jobs.py → jobs.py} +313 -167
- edsl/jobs/{JobsChecks.py → jobs_checks.py} +15 -7
- edsl/jobs/{JobsComponentConstructor.py → jobs_component_constructor.py} +19 -17
- edsl/jobs/{InterviewsConstructor.py → jobs_interview_constructor.py} +10 -5
- edsl/jobs/jobs_pricing_estimation.py +347 -0
- edsl/jobs/{JobsRemoteInferenceLogger.py → jobs_remote_inference_logger.py} +4 -3
- edsl/jobs/jobs_runner_asyncio.py +282 -0
- edsl/jobs/{JobsRemoteInferenceHandler.py → remote_inference.py} +19 -22
- edsl/jobs/results_exceptions_handler.py +2 -2
- edsl/key_management/__init__.py +28 -0
- edsl/key_management/key_lookup.py +161 -0
- edsl/{language_models/key_management/KeyLookupBuilder.py → key_management/key_lookup_builder.py} +118 -47
- edsl/key_management/key_lookup_collection.py +82 -0
- edsl/key_management/models.py +218 -0
- edsl/language_models/__init__.py +7 -2
- edsl/language_models/{ComputeCost.py → compute_cost.py} +18 -3
- edsl/{exceptions/language_models.py → language_models/exceptions.py} +2 -1
- edsl/language_models/language_model.py +1080 -0
- edsl/language_models/model.py +10 -25
- edsl/language_models/{ModelList.py → model_list.py} +9 -14
- edsl/language_models/{RawResponseHandler.py → raw_response_handler.py} +1 -1
- edsl/language_models/{RegisterLanguageModelsMeta.py → registry.py} +1 -1
- edsl/language_models/repair.py +4 -4
- edsl/language_models/utilities.py +4 -4
- edsl/notebooks/__init__.py +3 -1
- edsl/notebooks/{Notebook.py → notebook.py} +7 -8
- edsl/prompts/__init__.py +1 -1
- edsl/{exceptions/prompts.py → prompts/exceptions.py} +3 -1
- edsl/prompts/{Prompt.py → prompt.py} +101 -95
- edsl/questions/HTMLQuestion.py +1 -1
- edsl/questions/__init__.py +154 -25
- edsl/questions/answer_validator_mixin.py +1 -1
- edsl/questions/compose_questions.py +4 -3
- edsl/questions/derived/question_likert_five.py +166 -0
- edsl/questions/derived/{QuestionLinearScale.py → question_linear_scale.py} +4 -4
- edsl/questions/derived/{QuestionTopK.py → question_top_k.py} +4 -4
- edsl/questions/derived/{QuestionYesNo.py → question_yes_no.py} +4 -5
- edsl/questions/descriptors.py +24 -30
- edsl/questions/loop_processor.py +65 -19
- edsl/questions/question_base.py +881 -0
- edsl/questions/question_base_gen_mixin.py +15 -16
- edsl/questions/{QuestionBasePromptsMixin.py → question_base_prompts_mixin.py} +2 -2
- edsl/questions/{QuestionBudget.py → question_budget.py} +3 -4
- edsl/questions/{QuestionCheckBox.py → question_check_box.py} +16 -16
- edsl/questions/{QuestionDict.py → question_dict.py} +39 -5
- edsl/questions/{QuestionExtract.py → question_extract.py} +9 -9
- edsl/questions/question_free_text.py +282 -0
- edsl/questions/{QuestionFunctional.py → question_functional.py} +6 -5
- edsl/questions/{QuestionList.py → question_list.py} +6 -7
- edsl/questions/{QuestionMatrix.py → question_matrix.py} +6 -5
- edsl/questions/{QuestionMultipleChoice.py → question_multiple_choice.py} +126 -21
- edsl/questions/{QuestionNumerical.py → question_numerical.py} +5 -5
- edsl/questions/{QuestionRank.py → question_rank.py} +6 -6
- edsl/questions/question_registry.py +4 -9
- edsl/questions/register_questions_meta.py +8 -4
- edsl/questions/response_validator_abc.py +17 -16
- edsl/results/__init__.py +4 -1
- edsl/{exceptions/results.py → results/exceptions.py} +1 -1
- edsl/results/report.py +197 -0
- edsl/results/{Result.py → result.py} +131 -45
- edsl/results/{Results.py → results.py} +365 -220
- edsl/results/results_selector.py +344 -25
- edsl/scenarios/__init__.py +30 -3
- edsl/scenarios/{ConstructDownloadLink.py → construct_download_link.py} +7 -0
- edsl/scenarios/directory_scanner.py +156 -13
- edsl/scenarios/document_chunker.py +186 -0
- edsl/scenarios/exceptions.py +101 -0
- edsl/scenarios/file_methods.py +2 -3
- edsl/scenarios/{FileStore.py → file_store.py} +275 -189
- edsl/scenarios/handlers/__init__.py +14 -14
- edsl/scenarios/handlers/{csv.py → csv_file_store.py} +1 -2
- edsl/scenarios/handlers/{docx.py → docx_file_store.py} +8 -7
- edsl/scenarios/handlers/{html.py → html_file_store.py} +1 -2
- edsl/scenarios/handlers/{jpeg.py → jpeg_file_store.py} +1 -1
- edsl/scenarios/handlers/{json.py → json_file_store.py} +1 -1
- edsl/scenarios/handlers/latex_file_store.py +5 -0
- edsl/scenarios/handlers/{md.py → md_file_store.py} +1 -1
- edsl/scenarios/handlers/{pdf.py → pdf_file_store.py} +2 -2
- edsl/scenarios/handlers/{png.py → png_file_store.py} +1 -1
- edsl/scenarios/handlers/{pptx.py → pptx_file_store.py} +8 -7
- edsl/scenarios/handlers/{py.py → py_file_store.py} +1 -3
- edsl/scenarios/handlers/{sql.py → sql_file_store.py} +2 -1
- edsl/scenarios/handlers/{sqlite.py → sqlite_file_store.py} +2 -3
- edsl/scenarios/handlers/{txt.py → txt_file_store.py} +1 -1
- edsl/scenarios/scenario.py +928 -0
- edsl/scenarios/scenario_join.py +18 -5
- edsl/scenarios/{ScenarioList.py → scenario_list.py} +294 -106
- edsl/scenarios/{ScenarioListPdfMixin.py → scenario_list_pdf_tools.py} +16 -15
- edsl/scenarios/scenario_selector.py +5 -1
- edsl/study/ObjectEntry.py +2 -2
- edsl/study/SnapShot.py +5 -5
- edsl/study/Study.py +18 -19
- edsl/study/__init__.py +6 -4
- edsl/surveys/__init__.py +7 -4
- edsl/surveys/dag/__init__.py +2 -0
- edsl/surveys/{ConstructDAG.py → dag/construct_dag.py} +3 -3
- edsl/surveys/{DAG.py → dag/dag.py} +13 -10
- edsl/surveys/descriptors.py +1 -1
- edsl/surveys/{EditSurvey.py → edit_survey.py} +9 -9
- edsl/{exceptions/surveys.py → surveys/exceptions.py} +1 -2
- edsl/surveys/memory/__init__.py +3 -0
- edsl/surveys/{MemoryPlan.py → memory/memory_plan.py} +10 -9
- edsl/surveys/rules/__init__.py +3 -0
- edsl/surveys/{Rule.py → rules/rule.py} +103 -43
- edsl/surveys/{RuleCollection.py → rules/rule_collection.py} +21 -30
- edsl/surveys/{RuleManager.py → rules/rule_manager.py} +19 -13
- edsl/surveys/survey.py +1743 -0
- edsl/surveys/{SurveyExportMixin.py → survey_export.py} +22 -27
- edsl/surveys/{SurveyFlowVisualization.py → survey_flow_visualization.py} +11 -2
- edsl/surveys/{Simulator.py → survey_simulator.py} +10 -3
- edsl/tasks/__init__.py +32 -0
- edsl/{jobs/tasks/QuestionTaskCreator.py → tasks/question_task_creator.py} +115 -57
- edsl/tasks/task_creators.py +135 -0
- edsl/{jobs/tasks/TaskHistory.py → tasks/task_history.py} +86 -47
- edsl/{jobs/tasks → tasks}/task_status_enum.py +91 -7
- edsl/tasks/task_status_log.py +85 -0
- edsl/tokens/__init__.py +2 -0
- edsl/tokens/interview_token_usage.py +53 -0
- edsl/utilities/PrettyList.py +1 -1
- edsl/utilities/SystemInfo.py +25 -22
- edsl/utilities/__init__.py +29 -21
- edsl/utilities/gcp_bucket/__init__.py +2 -0
- edsl/utilities/gcp_bucket/cloud_storage.py +99 -96
- edsl/utilities/interface.py +44 -536
- edsl/{results/MarkdownToPDF.py → utilities/markdown_to_pdf.py} +13 -5
- edsl/utilities/repair_functions.py +1 -1
- {edsl-0.1.47.dist-info → edsl-0.1.48.dist-info}/METADATA +1 -1
- edsl-0.1.48.dist-info/RECORD +347 -0
- edsl/Base.py +0 -493
- edsl/BaseDiff.py +0 -260
- edsl/agents/InvigilatorBase.py +0 -260
- edsl/agents/PromptConstructor.py +0 -318
- edsl/coop/PriceFetcher.py +0 -54
- edsl/data/Cache.py +0 -582
- edsl/data/CacheEntry.py +0 -238
- edsl/data/SQLiteDict.py +0 -292
- edsl/data/__init__.py +0 -5
- edsl/data/orm.py +0 -10
- edsl/exceptions/cache.py +0 -5
- edsl/exceptions/coop.py +0 -14
- edsl/exceptions/data.py +0 -14
- edsl/exceptions/scenarios.py +0 -29
- edsl/jobs/Answers.py +0 -43
- edsl/jobs/JobsPrompts.py +0 -354
- edsl/jobs/buckets/BucketCollection.py +0 -134
- edsl/jobs/buckets/ModelBuckets.py +0 -65
- edsl/jobs/buckets/TokenBucket.py +0 -283
- edsl/jobs/buckets/TokenBucketClient.py +0 -191
- edsl/jobs/interviews/Interview.py +0 -395
- edsl/jobs/interviews/InterviewExceptionCollection.py +0 -99
- edsl/jobs/interviews/InterviewStatisticsCollection.py +0 -25
- edsl/jobs/runners/JobsRunnerAsyncio.py +0 -163
- edsl/jobs/runners/JobsRunnerStatusData.py +0 -0
- edsl/jobs/tasks/TaskCreators.py +0 -64
- edsl/jobs/tasks/TaskStatusLog.py +0 -23
- edsl/jobs/tokens/InterviewTokenUsage.py +0 -27
- edsl/language_models/LanguageModel.py +0 -635
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/key_management/KeyLookup.py +0 -63
- edsl/language_models/key_management/KeyLookupCollection.py +0 -38
- edsl/language_models/key_management/models.py +0 -137
- edsl/questions/QuestionBase.py +0 -544
- edsl/questions/QuestionFreeText.py +0 -130
- edsl/questions/derived/QuestionLikertFive.py +0 -76
- edsl/results/ResultsExportMixin.py +0 -45
- edsl/results/TextEditor.py +0 -50
- edsl/results/results_fetch_mixin.py +0 -33
- edsl/results/results_tools_mixin.py +0 -98
- edsl/scenarios/DocumentChunker.py +0 -104
- edsl/scenarios/Scenario.py +0 -548
- edsl/scenarios/ScenarioHtmlMixin.py +0 -65
- edsl/scenarios/ScenarioListExportMixin.py +0 -45
- edsl/scenarios/handlers/latex.py +0 -5
- edsl/shared.py +0 -1
- edsl/surveys/Survey.py +0 -1301
- edsl/surveys/SurveyQualtricsImport.py +0 -284
- edsl/surveys/SurveyToApp.py +0 -141
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/tools/__init__.py +0 -1
- edsl/tools/clusters.py +0 -192
- edsl/tools/embeddings.py +0 -27
- edsl/tools/embeddings_plotting.py +0 -118
- edsl/tools/plotting.py +0 -112
- edsl/tools/summarize.py +0 -18
- edsl/utilities/data/Registry.py +0 -6
- edsl/utilities/data/__init__.py +0 -1
- edsl/utilities/data/scooter_results.json +0 -1
- edsl-0.1.47.dist-info/RECORD +0 -354
- /edsl/coop/{CoopFunctionsMixin.py → coop_functions.py} +0 -0
- /edsl/{results → dataset/display}/CSSParameterizer.py +0 -0
- /edsl/{language_models/key_management → dataset/display}/__init__.py +0 -0
- /edsl/{results → dataset/display}/table_data_class.py +0 -0
- /edsl/{results → dataset/display}/table_display.css +0 -0
- /edsl/{results/ResultsGGMixin.py → dataset/r/ggplot.py} +0 -0
- /edsl/{results → dataset}/tree_explore.py +0 -0
- /edsl/{surveys/instructions/ChangeInstruction.py → instructions/change_instruction.py} +0 -0
- /edsl/{jobs/interviews → interviews}/interview_status_enum.py +0 -0
- /edsl/jobs/{runners/JobsRunnerStatus.py → jobs_runner_status.py} +0 -0
- /edsl/language_models/{PriceManager.py → price_manager.py} +0 -0
- /edsl/language_models/{fake_openai_call.py → unused/fake_openai_call.py} +0 -0
- /edsl/language_models/{fake_openai_service.py → unused/fake_openai_service.py} +0 -0
- /edsl/notebooks/{NotebookToLaTeX.py → notebook_to_latex.py} +0 -0
- /edsl/{exceptions/questions.py → questions/exceptions.py} +0 -0
- /edsl/questions/{SimpleAskMixin.py → simple_ask_mixin.py} +0 -0
- /edsl/surveys/{Memory.py → memory/memory.py} +0 -0
- /edsl/surveys/{MemoryManagement.py → memory/memory_management.py} +0 -0
- /edsl/surveys/{SurveyCSS.py → survey_css.py} +0 -0
- /edsl/{jobs/tokens/TokenUsage.py → tokens/token_usage.py} +0 -0
- /edsl/{results/MarkdownToDocx.py → utilities/markdown_to_docx.py} +0 -0
- /edsl/{TemplateLoader.py → utilities/template_loader.py} +0 -0
- {edsl-0.1.47.dist-info → edsl-0.1.48.dist-info}/LICENSE +0 -0
- {edsl-0.1.47.dist-info → edsl-0.1.48.dist-info}/WHEEL +0 -0
edsl/utilities/interface.py
CHANGED
@@ -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
|
-
|
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()
|
46
|
+
text = console.export_text()
|
12
47
|
|
13
|
-
# Create an image from the text
|
14
48
|
font_size = 15
|
15
|
-
font = ImageFont.load_default()
|
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
|
-
)
|
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
|
-
|
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
|
-
"""
|
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
|
-
|
32
|
+
import warnings
|
33
|
+
warnings.warn(
|
27
34
|
"Pandoc is not installed or not found in PATH. "
|
28
|
-
"
|
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
|
115
|
+
from ..scenarios import FileStore
|
108
116
|
|
109
117
|
return FileStore(temp_pdf)
|
110
118
|
|