edsl 0.1.29.dev3__py3-none-any.whl → 0.1.30__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 +18 -18
- edsl/__init__.py +23 -23
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +79 -41
- edsl/agents/AgentList.py +26 -26
- edsl/agents/Invigilator.py +19 -2
- edsl/agents/InvigilatorBase.py +15 -10
- edsl/agents/PromptConstructionMixin.py +342 -100
- edsl/agents/descriptors.py +2 -1
- edsl/base/Base.py +289 -0
- edsl/config.py +2 -1
- edsl/conjure/InputData.py +39 -8
- edsl/conversation/car_buying.py +1 -1
- edsl/coop/coop.py +187 -150
- edsl/coop/utils.py +43 -75
- edsl/data/Cache.py +41 -18
- edsl/data/CacheEntry.py +6 -7
- edsl/data/SQLiteDict.py +11 -3
- edsl/data_transfer_models.py +4 -0
- edsl/jobs/Answers.py +15 -1
- edsl/jobs/Jobs.py +108 -49
- edsl/jobs/buckets/ModelBuckets.py +14 -2
- edsl/jobs/buckets/TokenBucket.py +32 -5
- edsl/jobs/interviews/Interview.py +99 -79
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +19 -24
- edsl/jobs/runners/JobsRunnerAsyncio.py +16 -16
- edsl/jobs/tasks/QuestionTaskCreator.py +10 -6
- edsl/jobs/tasks/TaskHistory.py +4 -3
- edsl/language_models/LanguageModel.py +17 -17
- edsl/language_models/ModelList.py +1 -1
- edsl/language_models/repair.py +8 -7
- edsl/notebooks/Notebook.py +47 -10
- edsl/prompts/Prompt.py +31 -19
- edsl/questions/QuestionBase.py +38 -13
- edsl/questions/QuestionBudget.py +5 -6
- edsl/questions/QuestionCheckBox.py +7 -3
- edsl/questions/QuestionExtract.py +5 -3
- edsl/questions/QuestionFreeText.py +7 -5
- edsl/questions/QuestionFunctional.py +34 -5
- edsl/questions/QuestionList.py +3 -4
- edsl/questions/QuestionMultipleChoice.py +68 -12
- edsl/questions/QuestionNumerical.py +4 -3
- edsl/questions/QuestionRank.py +5 -3
- edsl/questions/__init__.py +4 -3
- edsl/questions/descriptors.py +46 -4
- edsl/questions/question_registry.py +20 -31
- edsl/questions/settings.py +1 -1
- edsl/results/Dataset.py +31 -0
- edsl/results/DatasetExportMixin.py +570 -0
- edsl/results/Result.py +66 -70
- edsl/results/Results.py +160 -68
- edsl/results/ResultsDBMixin.py +7 -3
- edsl/results/ResultsExportMixin.py +22 -537
- edsl/results/ResultsGGMixin.py +3 -3
- edsl/results/ResultsToolsMixin.py +5 -5
- edsl/scenarios/FileStore.py +299 -0
- edsl/scenarios/Scenario.py +16 -24
- edsl/scenarios/ScenarioList.py +42 -17
- edsl/scenarios/ScenarioListExportMixin.py +32 -0
- edsl/scenarios/ScenarioListPdfMixin.py +2 -1
- edsl/scenarios/__init__.py +1 -0
- edsl/study/Study.py +8 -16
- edsl/surveys/MemoryPlan.py +11 -4
- edsl/surveys/Survey.py +88 -17
- edsl/surveys/SurveyExportMixin.py +4 -2
- edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
- edsl/tools/plotting.py +4 -2
- edsl/utilities/__init__.py +21 -21
- edsl/utilities/interface.py +66 -45
- edsl/utilities/utilities.py +11 -13
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/METADATA +11 -10
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/RECORD +74 -71
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/WHEEL +1 -1
- edsl-0.1.29.dev3.dist-info/entry_points.txt +0 -3
- {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/LICENSE +0 -0
edsl/surveys/MemoryPlan.py
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
from collections import UserDict, defaultdict
|
4
4
|
from typing import Optional
|
5
5
|
|
6
|
-
from edsl.surveys.Memory import Memory
|
7
|
-
from edsl.prompts.Prompt import Prompt
|
8
|
-
from edsl.surveys.DAG import DAG
|
6
|
+
# from edsl.surveys.Memory import Memory
|
7
|
+
# from edsl.prompts.Prompt import Prompt
|
8
|
+
# from edsl.surveys.DAG import DAG
|
9
9
|
|
10
10
|
|
11
11
|
class MemoryPlan(UserDict):
|
@@ -61,6 +61,8 @@ class MemoryPlan(UserDict):
|
|
61
61
|
:param answers: A dictionary of question names to answers.
|
62
62
|
|
63
63
|
"""
|
64
|
+
from edsl.prompts.Prompt import Prompt
|
65
|
+
|
64
66
|
self._check_valid_question_name(focal_question)
|
65
67
|
|
66
68
|
if focal_question not in self:
|
@@ -121,6 +123,7 @@ class MemoryPlan(UserDict):
|
|
121
123
|
self._check_valid_question_name(focal_question)
|
122
124
|
self._check_valid_question_name(prior_question)
|
123
125
|
self._check_order(focal_question, prior_question)
|
126
|
+
from edsl.surveys.Memory import Memory
|
124
127
|
|
125
128
|
if focal_question not in self:
|
126
129
|
memory = Memory()
|
@@ -160,6 +163,8 @@ class MemoryPlan(UserDict):
|
|
160
163
|
@classmethod
|
161
164
|
def from_dict(cls, data) -> "MemoryPlan":
|
162
165
|
"""Deserialize a memory plan from a dictionary."""
|
166
|
+
from edsl.surveys.Memory import Memory
|
167
|
+
|
163
168
|
newdata = {}
|
164
169
|
for question_name, memory in data["data"].items():
|
165
170
|
newdata[question_name] = Memory.from_dict(memory)
|
@@ -182,13 +187,15 @@ class MemoryPlan(UserDict):
|
|
182
187
|
return new_d
|
183
188
|
|
184
189
|
@property
|
185
|
-
def dag(self) -> DAG:
|
190
|
+
def dag(self) -> "DAG":
|
186
191
|
"""Return a directed acyclic graph of the memory plan.
|
187
192
|
|
188
193
|
>>> mp = MemoryPlan.example()
|
189
194
|
>>> mp.dag
|
190
195
|
{1: {0}}
|
191
196
|
"""
|
197
|
+
from edsl.surveys.DAG import DAG
|
198
|
+
|
192
199
|
d = defaultdict(set)
|
193
200
|
for focal_question, memory in self.items():
|
194
201
|
for prior_question in memory:
|
edsl/surveys/Survey.py
CHANGED
@@ -2,26 +2,20 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
import re
|
5
|
-
|
6
5
|
from typing import Any, Generator, Optional, Union, List, Literal, Callable
|
7
|
-
|
8
|
-
from
|
9
|
-
from rich.table import Table
|
10
|
-
|
6
|
+
from uuid import uuid4
|
7
|
+
from edsl.Base import Base
|
11
8
|
from edsl.exceptions import SurveyCreationError, SurveyHasNoRulesError
|
12
9
|
from edsl.questions.QuestionBase import QuestionBase
|
13
10
|
from edsl.surveys.base import RulePriority, EndOfSurvey
|
11
|
+
from edsl.surveys.DAG import DAG
|
12
|
+
from edsl.surveys.descriptors import QuestionsDescriptor
|
13
|
+
from edsl.surveys.MemoryPlan import MemoryPlan
|
14
14
|
from edsl.surveys.Rule import Rule
|
15
15
|
from edsl.surveys.RuleCollection import RuleCollection
|
16
|
-
|
17
|
-
from edsl.Base import Base
|
18
16
|
from edsl.surveys.SurveyExportMixin import SurveyExportMixin
|
19
|
-
from edsl.surveys.descriptors import QuestionsDescriptor
|
20
|
-
from edsl.surveys.MemoryPlan import MemoryPlan
|
21
|
-
from edsl.surveys.DAG import DAG
|
22
|
-
from edsl.utilities import is_notebook
|
23
|
-
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
24
17
|
from edsl.surveys.SurveyFlowVisualizationMixin import SurveyFlowVisualizationMixin
|
18
|
+
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
25
19
|
|
26
20
|
|
27
21
|
class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
@@ -96,6 +90,10 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
96
90
|
index = self.question_name_to_index[question_name]
|
97
91
|
return self._questions[index]
|
98
92
|
|
93
|
+
def question_names_to_questions(self) -> dict:
|
94
|
+
"""Return a dictionary mapping question names to question attributes."""
|
95
|
+
return {q.question_name: q for q in self.questions}
|
96
|
+
|
99
97
|
def get_question(self, question_name: str) -> QuestionBase:
|
100
98
|
"""Return the question object given the question name."""
|
101
99
|
# import warnings
|
@@ -108,10 +106,47 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
108
106
|
|
109
107
|
return dict_hash(self._to_dict())
|
110
108
|
|
109
|
+
def __add__(self, other: Survey) -> Survey:
|
110
|
+
"""Combine two surveys.
|
111
|
+
|
112
|
+
:param other: The other survey to combine with this one.
|
113
|
+
>>> s1 = Survey.example()
|
114
|
+
>>> from edsl import QuestionFreeText
|
115
|
+
>>> s2 = Survey([QuestionFreeText(question_text="What is your name?", question_name="yo")])
|
116
|
+
>>> s3 = s1 + s2
|
117
|
+
Traceback (most recent call last):
|
118
|
+
...
|
119
|
+
ValueError: ('Cannot combine two surveys with non-default rules.', "Please use the 'clear_non_default_rules' method to remove non-default rules from the survey.")
|
120
|
+
>>> s3 = s1.clear_non_default_rules() + s2
|
121
|
+
>>> len(s3.questions)
|
122
|
+
4
|
123
|
+
|
124
|
+
"""
|
125
|
+
if (
|
126
|
+
len(self.rule_collection.non_default_rules) > 0
|
127
|
+
or len(other.rule_collection.non_default_rules) > 0
|
128
|
+
):
|
129
|
+
raise ValueError(
|
130
|
+
"Cannot combine two surveys with non-default rules.",
|
131
|
+
"Please use the 'clear_non_default_rules' method to remove non-default rules from the survey.",
|
132
|
+
)
|
133
|
+
|
134
|
+
return Survey(questions=self.questions + other.questions)
|
135
|
+
|
136
|
+
def clear_non_default_rules(self) -> Survey:
|
137
|
+
s = Survey()
|
138
|
+
for question in self.questions:
|
139
|
+
s.add_question(question)
|
140
|
+
return s
|
141
|
+
|
111
142
|
@property
|
112
143
|
def parameters(self):
|
113
144
|
return set.union(*[q.parameters for q in self.questions])
|
114
145
|
|
146
|
+
@property
|
147
|
+
def parameters_by_question(self):
|
148
|
+
return {q.question_name: q.parameters for q in self.questions}
|
149
|
+
|
115
150
|
@property
|
116
151
|
def question_names(self) -> list[str]:
|
117
152
|
"""Return a list of question names in the survey.
|
@@ -555,6 +590,12 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
555
590
|
job = Jobs(survey=self)
|
556
591
|
return job.by(*args)
|
557
592
|
|
593
|
+
def to_jobs(self):
|
594
|
+
"""Convert the survey to a Jobs object."""
|
595
|
+
from edsl.jobs.Jobs import Jobs
|
596
|
+
|
597
|
+
return Jobs(survey=self)
|
598
|
+
|
558
599
|
def run(self, *args, **kwargs) -> "Results":
|
559
600
|
"""Turn the survey into a Job and runs it.
|
560
601
|
|
@@ -732,6 +773,22 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
732
773
|
except IndexError:
|
733
774
|
raise
|
734
775
|
|
776
|
+
@property
|
777
|
+
def piping_dag(self) -> DAG:
|
778
|
+
d = {}
|
779
|
+
for question_name, depenencies in self.parameters_by_question.items():
|
780
|
+
if depenencies:
|
781
|
+
question_index = self.question_name_to_index[question_name]
|
782
|
+
for dependency in depenencies:
|
783
|
+
if dependency not in self.question_name_to_index:
|
784
|
+
pass
|
785
|
+
else:
|
786
|
+
dependency_index = self.question_name_to_index[dependency]
|
787
|
+
if question_index not in d:
|
788
|
+
d[question_index] = set()
|
789
|
+
d[question_index].add(dependency_index)
|
790
|
+
return d
|
791
|
+
|
735
792
|
def dag(self, textify: bool = False) -> DAG:
|
736
793
|
"""Return the DAG of the survey, which reflects both skip-logic and memory.
|
737
794
|
|
@@ -745,10 +802,12 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
745
802
|
"""
|
746
803
|
memory_dag = self.memory_plan.dag
|
747
804
|
rule_dag = self.rule_collection.dag
|
805
|
+
piping_dag = self.piping_dag
|
748
806
|
if textify:
|
749
807
|
memory_dag = DAG(self.textify(memory_dag))
|
750
808
|
rule_dag = DAG(self.textify(rule_dag))
|
751
|
-
|
809
|
+
piping_dag = DAG(self.textify(piping_dag))
|
810
|
+
return memory_dag + rule_dag + piping_dag
|
752
811
|
|
753
812
|
###################
|
754
813
|
# DUNDER METHODS
|
@@ -931,6 +990,8 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
931
990
|
│ └───────────────┴─────────────────┴───────────────┴──────────────────────────────────────────────┘ │
|
932
991
|
└────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
933
992
|
"""
|
993
|
+
from rich.table import Table
|
994
|
+
|
934
995
|
table = Table(show_header=True, header_style="bold magenta")
|
935
996
|
table.add_column("Questions", style="dim")
|
936
997
|
|
@@ -994,7 +1055,7 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
994
1055
|
return res
|
995
1056
|
|
996
1057
|
@classmethod
|
997
|
-
def example(cls) -> Survey:
|
1058
|
+
def example(cls, params: bool = False, randomize: bool = False) -> Survey:
|
998
1059
|
"""Return an example survey.
|
999
1060
|
|
1000
1061
|
>>> s = Survey.example()
|
@@ -1003,8 +1064,9 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
1003
1064
|
"""
|
1004
1065
|
from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
|
1005
1066
|
|
1067
|
+
addition = "" if not randomize else str(uuid4())
|
1006
1068
|
q0 = QuestionMultipleChoice(
|
1007
|
-
question_text="Do you like school?",
|
1069
|
+
question_text=f"Do you like school?{addition}",
|
1008
1070
|
question_options=["yes", "no"],
|
1009
1071
|
question_name="q0",
|
1010
1072
|
)
|
@@ -1018,12 +1080,20 @@ class Survey(SurveyExportMixin, SurveyFlowVisualizationMixin, Base):
|
|
1018
1080
|
question_options=["**lack*** of killer bees in cafeteria", "other"],
|
1019
1081
|
question_name="q2",
|
1020
1082
|
)
|
1083
|
+
if params:
|
1084
|
+
q3 = QuestionMultipleChoice(
|
1085
|
+
question_text="To the question '{{ q0.question_text}}', you said '{{ q0.answer }}'. Do you still feel this way?",
|
1086
|
+
question_options=["yes", "no"],
|
1087
|
+
question_name="q3",
|
1088
|
+
)
|
1089
|
+
s = cls(questions=[q0, q1, q2, q3])
|
1090
|
+
return s
|
1021
1091
|
s = cls(questions=[q0, q1, q2])
|
1022
1092
|
s = s.add_rule(q0, "q0 == 'yes'", q2)
|
1023
1093
|
return s
|
1024
1094
|
|
1025
1095
|
def get_job(self, model=None, agent=None, **kwargs):
|
1026
|
-
if
|
1096
|
+
if model is None:
|
1027
1097
|
from edsl import Model
|
1028
1098
|
|
1029
1099
|
model = Model()
|
@@ -1114,4 +1184,5 @@ def main():
|
|
1114
1184
|
if __name__ == "__main__":
|
1115
1185
|
import doctest
|
1116
1186
|
|
1117
|
-
doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.SKIP)
|
1187
|
+
# doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.SKIP)
|
1188
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|
@@ -1,8 +1,6 @@
|
|
1
1
|
"""A mixin class for exporting surveys to different formats."""
|
2
2
|
|
3
|
-
from docx import Document
|
4
3
|
from typing import Union, Optional
|
5
|
-
import black
|
6
4
|
|
7
5
|
|
8
6
|
class SurveyExportMixin:
|
@@ -29,6 +27,8 @@ class SurveyExportMixin:
|
|
29
27
|
|
30
28
|
def docx(self, filename=None) -> Union["Document", None]:
|
31
29
|
"""Generate a docx document for the survey."""
|
30
|
+
from docx import Document
|
31
|
+
|
32
32
|
doc = Document()
|
33
33
|
doc.add_heading("EDSL Survey")
|
34
34
|
doc.add_paragraph(f"\n")
|
@@ -83,6 +83,8 @@ class SurveyExportMixin:
|
|
83
83
|
survey = Survey(questions=[q0, q1, q2])
|
84
84
|
...
|
85
85
|
"""
|
86
|
+
import black
|
87
|
+
|
86
88
|
header_lines = ["from edsl.surveys.Survey import Survey"]
|
87
89
|
header_lines.append("from edsl import Question")
|
88
90
|
lines = ["\n".join(header_lines)]
|
@@ -1,10 +1,7 @@
|
|
1
1
|
"""A mixin for visualizing the flow of a survey."""
|
2
2
|
|
3
|
-
import pydot
|
4
|
-
import tempfile
|
5
|
-
from IPython.display import Image
|
6
|
-
from edsl.utilities import is_notebook
|
7
3
|
from edsl.surveys.base import RulePriority, EndOfSurvey
|
4
|
+
import tempfile
|
8
5
|
|
9
6
|
|
10
7
|
class SurveyFlowVisualizationMixin:
|
@@ -13,6 +10,8 @@ class SurveyFlowVisualizationMixin:
|
|
13
10
|
def show_flow(self, filename: str = None):
|
14
11
|
"""Create an image showing the flow of users through the survey."""
|
15
12
|
# Create a graph object
|
13
|
+
import pydot
|
14
|
+
|
16
15
|
graph = pydot.Dot(graph_type="digraph")
|
17
16
|
|
18
17
|
# Add nodes for each question
|
@@ -101,8 +100,11 @@ class SurveyFlowVisualizationMixin:
|
|
101
100
|
on Ubuntu.
|
102
101
|
"""
|
103
102
|
)
|
103
|
+
from edsl.utilities.utilities import is_notebook
|
104
104
|
|
105
105
|
if is_notebook():
|
106
|
+
from IPython.display import Image
|
107
|
+
|
106
108
|
display(Image(tmp_file.name))
|
107
109
|
else:
|
108
110
|
import os
|
edsl/tools/plotting.py
CHANGED
@@ -93,8 +93,10 @@ def theme_plot(results, field, context, themes=None, progress_bar=False):
|
|
93
93
|
SELECT json_each.value AS theme
|
94
94
|
FROM self,
|
95
95
|
json_each({ field }_themes)
|
96
|
-
)
|
97
|
-
|
96
|
+
)
|
97
|
+
GROUP BY theme
|
98
|
+
HAVING theme <> 'Other'
|
99
|
+
ORDER BY mentions DESC
|
98
100
|
"""
|
99
101
|
themes = results.sql(themes_query, to_list=True)
|
100
102
|
|
edsl/utilities/__init__.py
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
from edsl.utilities.interface import (
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
)
|
1
|
+
# from edsl.utilities.interface import (
|
2
|
+
# print_dict_as_html_table,
|
3
|
+
# print_dict_with_rich,
|
4
|
+
# print_list_of_dicts_as_html_table,
|
5
|
+
# print_table_with_rich,
|
6
|
+
# print_public_methods_with_doc,
|
7
|
+
# print_list_of_dicts_as_markdown_table,
|
8
|
+
# )
|
9
9
|
|
10
|
-
from edsl.utilities.utilities import (
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
)
|
10
|
+
# from edsl.utilities.utilities import (
|
11
|
+
# create_valid_var_name,
|
12
|
+
# dict_to_html,
|
13
|
+
# hash_value,
|
14
|
+
# HTMLSnippet,
|
15
|
+
# is_notebook,
|
16
|
+
# is_gzipped,
|
17
|
+
# is_valid_variable_name,
|
18
|
+
# random_string,
|
19
|
+
# repair_json,
|
20
|
+
# shorten_string,
|
21
|
+
# time_all_functions,
|
22
|
+
# )
|
edsl/utilities/interface.py
CHANGED
@@ -1,12 +1,45 @@
|
|
1
1
|
"""A module for displaying data in various formats."""
|
2
2
|
|
3
3
|
from html import escape
|
4
|
-
from IPython.display import HTML
|
5
|
-
from IPython.display import display as ipython_diplay
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
from
|
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)
|
10
43
|
|
11
44
|
|
12
45
|
def gen_html_sandwich(html_inner, interactive=False):
|
@@ -133,43 +166,10 @@ def get_multiline_textsize(text, font):
|
|
133
166
|
return max_width, total_height
|
134
167
|
|
135
168
|
|
136
|
-
# def create_image(console, image_filename):
|
137
|
-
# """Create an image from the console output."""
|
138
|
-
# font_size = 15
|
139
|
-
|
140
|
-
# text = console.export_text() # Get the console output as text.
|
141
|
-
|
142
|
-
# # Create an image from the text
|
143
|
-
# font_size = 15
|
144
|
-
# font = ImageFont.load_default() # Use the default font to avoid file path issues.
|
145
|
-
# # text_width, text_height = ImageDraw.Draw(
|
146
|
-
# # Image.new("RGB", (100, 100))
|
147
|
-
# # ).multiline_textsize(text, font=font)
|
148
|
-
# text_width, text_height = get_multiline_textsize(text, font)
|
149
|
-
# image = Image.new(
|
150
|
-
# "RGB", (text_width + 20, text_height + 20), color=(255, 255, 255)
|
151
|
-
# ) # Add some padding
|
152
|
-
# d = ImageDraw.Draw(image)
|
153
|
-
|
154
|
-
# # Draw text to image
|
155
|
-
# d.multiline_text((10, 10), text, font=font, fill=(0, 0, 0))
|
156
|
-
# # Save the image
|
157
|
-
# image.save(image_filename)
|
158
|
-
|
159
|
-
|
160
|
-
def display(console, table, filename):
|
161
|
-
"""Display the table using the rich library and save it to a file if a filename is provided."""
|
162
|
-
if filename is not None:
|
163
|
-
with open(filename, "w") as f:
|
164
|
-
with console.capture() as capture:
|
165
|
-
console.print(table)
|
166
|
-
f.write(capture.get())
|
167
|
-
create_image(console, filename + ".png")
|
168
|
-
else:
|
169
|
-
console.print(table)
|
170
|
-
|
171
|
-
|
172
169
|
def print_results_long(results, max_rows=None):
|
170
|
+
from rich.console import Console
|
171
|
+
from rich.table import Table
|
172
|
+
|
173
173
|
console = Console(record=True)
|
174
174
|
table = Table(show_header=True, header_style="bold magenta")
|
175
175
|
table.add_column("Result index", style="dim")
|
@@ -199,6 +199,9 @@ def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
|
|
199
199
|
│ c │ 3 │
|
200
200
|
└─────┴───────┘
|
201
201
|
"""
|
202
|
+
from rich.console import Console
|
203
|
+
from rich.table import Table
|
204
|
+
|
202
205
|
console = Console(record=True)
|
203
206
|
table = Table(show_header=True, header_style="bold magenta")
|
204
207
|
table.add_column(key_name, style="dim")
|
@@ -206,7 +209,7 @@ def print_dict_with_rich(d, key_name="Key", value_name="Value", filename=None):
|
|
206
209
|
for key, value in d.items():
|
207
210
|
table.add_row(key, str(value))
|
208
211
|
console.print(table)
|
209
|
-
#
|
212
|
+
# display_table(console, table, filename)
|
210
213
|
|
211
214
|
|
212
215
|
def print_dict_as_html_table(
|
@@ -251,6 +254,9 @@ def print_dict_as_html_table(
|
|
251
254
|
|
252
255
|
|
253
256
|
def print_scenario_list(data):
|
257
|
+
from rich.console import Console
|
258
|
+
from rich.table import Table
|
259
|
+
|
254
260
|
new_data = []
|
255
261
|
for obs in data:
|
256
262
|
try:
|
@@ -300,6 +306,9 @@ def print_dataset_with_rich(data, filename=None, split_at_dot=True):
|
|
300
306
|
│ 3 │ 6 │
|
301
307
|
└───┴───┘
|
302
308
|
"""
|
309
|
+
from rich.console import Console
|
310
|
+
from rich.table import Table
|
311
|
+
|
303
312
|
console = Console(record=True)
|
304
313
|
|
305
314
|
# Create a table object
|
@@ -321,7 +330,7 @@ def print_dataset_with_rich(data, filename=None, split_at_dot=True):
|
|
321
330
|
table.add_row(*row)
|
322
331
|
|
323
332
|
console.print(table)
|
324
|
-
#
|
333
|
+
# display_table(console, table, filename)
|
325
334
|
|
326
335
|
|
327
336
|
def create_latex_table_from_data(data, filename=None, split_at_dot=True):
|
@@ -495,6 +504,9 @@ def print_list_of_dicts_as_markdown_table(data, filename=None):
|
|
495
504
|
|
496
505
|
def print_public_methods_with_doc(obj):
|
497
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
|
+
|
498
510
|
console = Console()
|
499
511
|
public_methods_with_docstrings = [
|
500
512
|
(method, getattr(obj, method).__doc__)
|
@@ -525,6 +537,10 @@ def print_tally_with_rich(data, filename=None):
|
|
525
537
|
└───────┴───────┘
|
526
538
|
"""
|
527
539
|
# Initialize a console object
|
540
|
+
from rich.console import Console
|
541
|
+
from rich.table import Table
|
542
|
+
from IPython.display import display
|
543
|
+
|
528
544
|
console = Console(record=True)
|
529
545
|
|
530
546
|
# Create a new table
|
@@ -538,7 +554,9 @@ def print_tally_with_rich(data, filename=None):
|
|
538
554
|
for key, value in data.items():
|
539
555
|
table.add_row(key, str(value))
|
540
556
|
|
541
|
-
display
|
557
|
+
from IPython.display import display
|
558
|
+
|
559
|
+
display_table(console, table, filename)
|
542
560
|
|
543
561
|
|
544
562
|
def print_table_with_rich(data, filename=None):
|
@@ -561,6 +579,9 @@ def print_table_with_rich(data, filename=None):
|
|
561
579
|
│ 2 │ 9 │ 8 │
|
562
580
|
└───┴───┴───┘
|
563
581
|
"""
|
582
|
+
from rich.console import Console
|
583
|
+
from rich.table import Table
|
584
|
+
|
564
585
|
# Initialize a console object - expects a list of dictionaries
|
565
586
|
console = Console(record=True)
|
566
587
|
|
@@ -580,7 +601,7 @@ def print_table_with_rich(data, filename=None):
|
|
580
601
|
for row in data:
|
581
602
|
table.add_row(*[str(value) for value in row.values()])
|
582
603
|
|
583
|
-
|
604
|
+
display_table(console, table, filename)
|
584
605
|
|
585
606
|
|
586
607
|
if __name__ == "__main__":
|
edsl/utilities/utilities.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
"""Utility functions for working with strings, dictionaries, and files."""
|
2
2
|
|
3
|
+
from functools import wraps
|
4
|
+
import types
|
5
|
+
import time
|
6
|
+
|
3
7
|
import hashlib
|
4
8
|
import json
|
5
9
|
import keyword
|
@@ -11,18 +15,10 @@ import tempfile
|
|
11
15
|
import gzip
|
12
16
|
import webbrowser
|
13
17
|
import json
|
18
|
+
|
14
19
|
from html import escape
|
15
20
|
from typing import Callable, Union
|
16
21
|
|
17
|
-
from pygments import highlight
|
18
|
-
from pygments.lexers import JsonLexer
|
19
|
-
from pygments.formatters import HtmlFormatter
|
20
|
-
from IPython.display import HTML
|
21
|
-
|
22
|
-
from functools import wraps
|
23
|
-
import types
|
24
|
-
import time
|
25
|
-
|
26
22
|
|
27
23
|
def time_it(func):
|
28
24
|
@wraps(func)
|
@@ -52,10 +48,6 @@ def dict_hash(data: dict):
|
|
52
48
|
)
|
53
49
|
|
54
50
|
|
55
|
-
import re
|
56
|
-
import json
|
57
|
-
|
58
|
-
|
59
51
|
def extract_json_from_string(text):
|
60
52
|
pattern = re.compile(r"\{.*?\}")
|
61
53
|
match = pattern.search(text)
|
@@ -96,6 +88,11 @@ def data_to_html(data, replace_new_lines=False):
|
|
96
88
|
if "edsl_class_name" in data:
|
97
89
|
_ = data.pop("edsl_class_name")
|
98
90
|
|
91
|
+
from pygments import highlight
|
92
|
+
from pygments.lexers import JsonLexer
|
93
|
+
from pygments.formatters import HtmlFormatter
|
94
|
+
from IPython.display import HTML
|
95
|
+
|
99
96
|
json_str = json.dumps(data, indent=4)
|
100
97
|
formatted_json = highlight(
|
101
98
|
json_str,
|
@@ -104,6 +101,7 @@ def data_to_html(data, replace_new_lines=False):
|
|
104
101
|
)
|
105
102
|
if replace_new_lines:
|
106
103
|
formatted_json = formatted_json.replace("\\n", "<br>")
|
104
|
+
|
107
105
|
return HTML(formatted_json).data
|
108
106
|
|
109
107
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: edsl
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.30
|
4
4
|
Summary: Create and analyze LLM-based surveys
|
5
5
|
Home-page: https://www.expectedparrot.com/
|
6
6
|
License: MIT
|
@@ -57,15 +57,6 @@ The Expected Parrot Domain-Specific Language (EDSL) package lets you conduct com
|
|
57
57
|
- [LinkedIn](https://www.linkedin.com/company/expectedparrot/)
|
58
58
|
- [Blog](https://blog.expectedparrot.com)
|
59
59
|
|
60
|
-
## 💡 Contributions, feature requests & bugs
|
61
|
-
Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
|
62
|
-
Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
|
63
|
-
|
64
|
-
## 💻 Requirements
|
65
|
-
* EDSL is compatible with Python 3.9 - 3.12.
|
66
|
-
* API keys for large language models that you want to use, stored in a `.env` file.
|
67
|
-
See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
|
68
|
-
|
69
60
|
## 🌎 Hello, World!
|
70
61
|
A quick example:
|
71
62
|
|
@@ -96,3 +87,13 @@ Output:
|
|
96
87
|
│ Good │
|
97
88
|
└───────────────────┘
|
98
89
|
```
|
90
|
+
|
91
|
+
## 💻 Requirements
|
92
|
+
* EDSL is compatible with Python 3.9 - 3.12.
|
93
|
+
* API keys for large language models that you want to use, stored in a `.env` file.
|
94
|
+
See instructions on [storing API keys](https://docs.expectedparrot.com/en/latest/api_keys.html).
|
95
|
+
|
96
|
+
## 💡 Contributions, feature requests & bugs
|
97
|
+
Interested in contributing? Want us to add a new feature? Found a bug for us to squash?
|
98
|
+
Please send us an email at [info@expectedparrot.com](mailto:info@expectedparrot.com) or message us at our [Discord channel](https://discord.com/invite/mxAYkjfy9m).
|
99
|
+
|