edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edsl/Base.py +413 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +57 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +1071 -867
- edsl/agents/AgentList.py +551 -413
- edsl/agents/Invigilator.py +284 -233
- edsl/agents/InvigilatorBase.py +257 -270
- edsl/agents/PromptConstructor.py +272 -354
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +2 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -117
- edsl/auto/StageBase.py +243 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +74 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +218 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +177 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +59 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1106 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +573 -555
- edsl/data/CacheEntry.py +230 -233
- edsl/data/CacheHandler.py +168 -149
- edsl/data/RemoteCacheSync.py +186 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +5 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +74 -73
- edsl/enums.py +202 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +54 -42
- edsl/exceptions/cache.py +5 -5
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +109 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +29 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +106 -87
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -120
- edsl/inference_services/AzureAI.py +215 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +143 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +80 -147
- edsl/inference_services/InferenceServicesCollection.py +138 -97
- edsl/inference_services/MistralAIService.py +120 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +236 -224
- edsl/inference_services/PerplexityService.py +160 -163
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -89
- edsl/inference_services/TogetherAIService.py +172 -170
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +43 -56
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +823 -898
- edsl/jobs/JobsChecks.py +172 -147
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +283 -251
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +396 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
- edsl/jobs/runners/JobsRunnerStatus.py +297 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +470 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +161 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +626 -668
- edsl/language_models/ModelList.py +164 -155
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +2 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +156 -156
- edsl/language_models/utilities.py +65 -64
- edsl/notebooks/Notebook.py +263 -258
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +352 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -664
- edsl/questions/QuestionBasePromptsMixin.py +221 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +180 -182
- edsl/questions/QuestionFreeText.py +113 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +223 -231
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +330 -286
- edsl/questions/QuestionNumerical.py +151 -153
- edsl/questions/QuestionRank.py +314 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/SimpleAskMixin.py +74 -73
- edsl/questions/__init__.py +27 -26
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +90 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +427 -413
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
- edsl/questions/question_registry.py +177 -177
- edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -108
- edsl/results/Dataset.py +587 -424
- edsl/results/DatasetExportMixin.py +594 -731
- edsl/results/DatasetTree.py +295 -275
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +557 -465
- edsl/results/Results.py +1183 -1165
- edsl/results/ResultsExportMixin.py +45 -43
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/TableDisplay.py +125 -198
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +2 -2
- edsl/results/file_exports.py +252 -0
- edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
- edsl/results/{Selector.py → results_selector.py} +145 -135
- edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +77 -77
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +511 -632
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +498 -601
- edsl/scenarios/ScenarioHtmlMixin.py +65 -64
- edsl/scenarios/ScenarioList.py +1458 -1287
- edsl/scenarios/ScenarioListExportMixin.py +45 -52
- edsl/scenarios/ScenarioListPdfMixin.py +239 -261
- edsl/scenarios/__init__.py +3 -4
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +38 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +521 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +327 -326
- edsl/surveys/RuleCollection.py +385 -387
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1280 -1801
- edsl/surveys/SurveyCSS.py +273 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +5 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +60 -56
- edsl/surveys/instructions/ChangeInstruction.py +48 -49
- edsl/surveys/instructions/Instruction.py +56 -65
- edsl/surveys/instructions/InstructionCollection.py +82 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -19
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +436 -424
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/METADATA +13 -11
- edsl-0.1.39.dev5.dist-info/RECORD +358 -0
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/WHEEL +1 -1
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.39.dev3.dist-info/RECORD +0 -277
edsl/utilities/interface.py
CHANGED
@@ -1,627 +1,627 @@
|
|
1
|
-
"""A module for displaying data in various formats."""
|
2
|
-
|
3
|
-
from html import escape
|
4
|
-
|
5
|
-
|
6
|
-
def create_image(console, image_filename):
|
7
|
-
"""Create an image from the console output."""
|
8
|
-
font_size = 15
|
9
|
-
from PIL import Image, ImageDraw, ImageFont
|
10
|
-
|
11
|
-
text = console.export_text() # Get the console output as text.
|
12
|
-
|
13
|
-
# Create an image from the text
|
14
|
-
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)
|
19
|
-
text_width, text_height = get_multiline_textsize(text, font)
|
20
|
-
image = Image.new(
|
21
|
-
"RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
|
22
|
-
) # Add some padding
|
23
|
-
d = ImageDraw.Draw(image)
|
24
|
-
|
25
|
-
# Draw text to image
|
26
|
-
d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
|
27
|
-
# Save the image
|
28
|
-
image.save(image_filename)
|
29
|
-
|
30
|
-
|
31
|
-
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
|
-
if filename is not None:
|
36
|
-
with open(filename, "w") as f:
|
37
|
-
with console.capture() as capture:
|
38
|
-
console.print(table)
|
39
|
-
f.write(capture.get())
|
40
|
-
create_image(console, filename + ".png")
|
41
|
-
else:
|
42
|
-
console.print(table)
|
43
|
-
|
44
|
-
|
45
|
-
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
|
-
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
|
-
|
111
|
-
|
112
|
-
def view_html(html):
|
113
|
-
"""Display HTML content in a web browser."""
|
114
|
-
import tempfile
|
115
|
-
import webbrowser
|
116
|
-
|
117
|
-
with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html") as f:
|
118
|
-
url = "file://" + f.name
|
119
|
-
# Write the HTML content to the file
|
120
|
-
f.write(html)
|
121
|
-
|
122
|
-
# Open the URL in the web browser
|
123
|
-
webbrowser.open(url)
|
124
|
-
|
125
|
-
|
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
|
-
def get_multiline_textsize(text, font):
|
148
|
-
"""Get the size of the text when it is drawn on an image."""
|
149
|
-
lines = text.split("\n")
|
150
|
-
|
151
|
-
# Initialize width and height
|
152
|
-
max_width = 0
|
153
|
-
total_height = 0
|
154
|
-
|
155
|
-
for line in lines:
|
156
|
-
# Get the size of the text for the line
|
157
|
-
box = font.getbbox(line)
|
158
|
-
width, height = box[2], box[3]
|
159
|
-
|
160
|
-
# Update max_width if width of the current line is greater than max_width
|
161
|
-
max_width = max(max_width, width)
|
162
|
-
|
163
|
-
# Add height to total_height
|
164
|
-
total_height += height
|
165
|
-
|
166
|
-
return max_width, total_height
|
167
|
-
|
168
|
-
|
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
|
-
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
|
-
from rich.console import Console
|
203
|
-
from rich.table import Table
|
204
|
-
|
205
|
-
console = Console(record=True)
|
206
|
-
table = Table(show_header=True, header_style="bold magenta")
|
207
|
-
table.add_column(key_name, style="dim")
|
208
|
-
table.add_column(value_name, style="dim")
|
209
|
-
for key, value in d.items():
|
210
|
-
table.add_row(key, str(value))
|
211
|
-
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
|
-
|
561
|
-
|
562
|
-
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
|
-
from rich.console import Console
|
583
|
-
from rich.table import Table
|
584
|
-
|
585
|
-
# Initialize a console object - expects a list of dictionaries
|
586
|
-
console = Console(record=True)
|
587
|
-
|
588
|
-
# Create a new table
|
589
|
-
table = Table(show_header=True, header_style="bold magenta", row_styles=["", "dim"])
|
590
|
-
|
591
|
-
# Check if data is empty; if it is, exit
|
592
|
-
if not data:
|
593
|
-
console.print("No data provided!")
|
594
|
-
return
|
595
|
-
|
596
|
-
# Add columns based on keys in the first dictionary
|
597
|
-
for key in data[0].keys():
|
598
|
-
table.add_column(key, style="dim")
|
599
|
-
|
600
|
-
# Add rows to the table
|
601
|
-
for row in data:
|
602
|
-
table.add_row(*[str(value) for value in row.values()])
|
603
|
-
|
604
|
-
display_table(console, table, filename)
|
605
|
-
|
606
|
-
|
607
|
-
if __name__ == "__main__":
|
608
|
-
# print_dict_as_html_table({"a": 1, "b": 2, "c": 3})
|
609
|
-
import doctest
|
610
|
-
|
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
|
1
|
+
"""A module for displaying data in various formats."""
|
2
|
+
|
3
|
+
from html import escape
|
4
|
+
|
5
|
+
|
6
|
+
def create_image(console, image_filename):
|
7
|
+
"""Create an image from the console output."""
|
8
|
+
font_size = 15
|
9
|
+
from PIL import Image, ImageDraw, ImageFont
|
10
|
+
|
11
|
+
text = console.export_text() # Get the console output as text.
|
12
|
+
|
13
|
+
# Create an image from the text
|
14
|
+
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)
|
19
|
+
text_width, text_height = get_multiline_textsize(text, font)
|
20
|
+
image = Image.new(
|
21
|
+
"RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
|
22
|
+
) # Add some padding
|
23
|
+
d = ImageDraw.Draw(image)
|
24
|
+
|
25
|
+
# Draw text to image
|
26
|
+
d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
|
27
|
+
# Save the image
|
28
|
+
image.save(image_filename)
|
29
|
+
|
30
|
+
|
31
|
+
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
|
+
if filename is not None:
|
36
|
+
with open(filename, "w") as f:
|
37
|
+
with console.capture() as capture:
|
38
|
+
console.print(table)
|
39
|
+
f.write(capture.get())
|
40
|
+
create_image(console, filename + ".png")
|
41
|
+
else:
|
42
|
+
console.print(table)
|
43
|
+
|
44
|
+
|
45
|
+
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
|
+
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
|
+
|
111
|
+
|
112
|
+
def view_html(html):
|
113
|
+
"""Display HTML content in a web browser."""
|
114
|
+
import tempfile
|
115
|
+
import webbrowser
|
116
|
+
|
117
|
+
with tempfile.NamedTemporaryFile("w", delete=False, suffix=".html") as f:
|
118
|
+
url = "file://" + f.name
|
119
|
+
# Write the HTML content to the file
|
120
|
+
f.write(html)
|
121
|
+
|
122
|
+
# Open the URL in the web browser
|
123
|
+
webbrowser.open(url)
|
124
|
+
|
125
|
+
|
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
|
+
def get_multiline_textsize(text, font):
|
148
|
+
"""Get the size of the text when it is drawn on an image."""
|
149
|
+
lines = text.split("\n")
|
150
|
+
|
151
|
+
# Initialize width and height
|
152
|
+
max_width = 0
|
153
|
+
total_height = 0
|
154
|
+
|
155
|
+
for line in lines:
|
156
|
+
# Get the size of the text for the line
|
157
|
+
box = font.getbbox(line)
|
158
|
+
width, height = box[2], box[3]
|
159
|
+
|
160
|
+
# Update max_width if width of the current line is greater than max_width
|
161
|
+
max_width = max(max_width, width)
|
162
|
+
|
163
|
+
# Add height to total_height
|
164
|
+
total_height += height
|
165
|
+
|
166
|
+
return max_width, total_height
|
167
|
+
|
168
|
+
|
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
|
+
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
|
+
from rich.console import Console
|
203
|
+
from rich.table import Table
|
204
|
+
|
205
|
+
console = Console(record=True)
|
206
|
+
table = Table(show_header=True, header_style="bold magenta")
|
207
|
+
table.add_column(key_name, style="dim")
|
208
|
+
table.add_column(value_name, style="dim")
|
209
|
+
for key, value in d.items():
|
210
|
+
table.add_row(key, str(value))
|
211
|
+
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
|
+
|
561
|
+
|
562
|
+
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
|
+
from rich.console import Console
|
583
|
+
from rich.table import Table
|
584
|
+
|
585
|
+
# Initialize a console object - expects a list of dictionaries
|
586
|
+
console = Console(record=True)
|
587
|
+
|
588
|
+
# Create a new table
|
589
|
+
table = Table(show_header=True, header_style="bold magenta", row_styles=["", "dim"])
|
590
|
+
|
591
|
+
# Check if data is empty; if it is, exit
|
592
|
+
if not data:
|
593
|
+
console.print("No data provided!")
|
594
|
+
return
|
595
|
+
|
596
|
+
# Add columns based on keys in the first dictionary
|
597
|
+
for key in data[0].keys():
|
598
|
+
table.add_column(key, style="dim")
|
599
|
+
|
600
|
+
# Add rows to the table
|
601
|
+
for row in data:
|
602
|
+
table.add_row(*[str(value) for value in row.values()])
|
603
|
+
|
604
|
+
display_table(console, table, filename)
|
605
|
+
|
606
|
+
|
607
|
+
if __name__ == "__main__":
|
608
|
+
# print_dict_as_html_table({"a": 1, "b": 2, "c": 3})
|
609
|
+
import doctest
|
610
|
+
|
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
|