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.
Files changed (75) hide show
  1. edsl/Base.py +18 -18
  2. edsl/__init__.py +23 -23
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +79 -41
  5. edsl/agents/AgentList.py +26 -26
  6. edsl/agents/Invigilator.py +19 -2
  7. edsl/agents/InvigilatorBase.py +15 -10
  8. edsl/agents/PromptConstructionMixin.py +342 -100
  9. edsl/agents/descriptors.py +2 -1
  10. edsl/base/Base.py +289 -0
  11. edsl/config.py +2 -1
  12. edsl/conjure/InputData.py +39 -8
  13. edsl/conversation/car_buying.py +1 -1
  14. edsl/coop/coop.py +187 -150
  15. edsl/coop/utils.py +43 -75
  16. edsl/data/Cache.py +41 -18
  17. edsl/data/CacheEntry.py +6 -7
  18. edsl/data/SQLiteDict.py +11 -3
  19. edsl/data_transfer_models.py +4 -0
  20. edsl/jobs/Answers.py +15 -1
  21. edsl/jobs/Jobs.py +108 -49
  22. edsl/jobs/buckets/ModelBuckets.py +14 -2
  23. edsl/jobs/buckets/TokenBucket.py +32 -5
  24. edsl/jobs/interviews/Interview.py +99 -79
  25. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +19 -24
  26. edsl/jobs/runners/JobsRunnerAsyncio.py +16 -16
  27. edsl/jobs/tasks/QuestionTaskCreator.py +10 -6
  28. edsl/jobs/tasks/TaskHistory.py +4 -3
  29. edsl/language_models/LanguageModel.py +17 -17
  30. edsl/language_models/ModelList.py +1 -1
  31. edsl/language_models/repair.py +8 -7
  32. edsl/notebooks/Notebook.py +47 -10
  33. edsl/prompts/Prompt.py +31 -19
  34. edsl/questions/QuestionBase.py +38 -13
  35. edsl/questions/QuestionBudget.py +5 -6
  36. edsl/questions/QuestionCheckBox.py +7 -3
  37. edsl/questions/QuestionExtract.py +5 -3
  38. edsl/questions/QuestionFreeText.py +7 -5
  39. edsl/questions/QuestionFunctional.py +34 -5
  40. edsl/questions/QuestionList.py +3 -4
  41. edsl/questions/QuestionMultipleChoice.py +68 -12
  42. edsl/questions/QuestionNumerical.py +4 -3
  43. edsl/questions/QuestionRank.py +5 -3
  44. edsl/questions/__init__.py +4 -3
  45. edsl/questions/descriptors.py +46 -4
  46. edsl/questions/question_registry.py +20 -31
  47. edsl/questions/settings.py +1 -1
  48. edsl/results/Dataset.py +31 -0
  49. edsl/results/DatasetExportMixin.py +570 -0
  50. edsl/results/Result.py +66 -70
  51. edsl/results/Results.py +160 -68
  52. edsl/results/ResultsDBMixin.py +7 -3
  53. edsl/results/ResultsExportMixin.py +22 -537
  54. edsl/results/ResultsGGMixin.py +3 -3
  55. edsl/results/ResultsToolsMixin.py +5 -5
  56. edsl/scenarios/FileStore.py +299 -0
  57. edsl/scenarios/Scenario.py +16 -24
  58. edsl/scenarios/ScenarioList.py +42 -17
  59. edsl/scenarios/ScenarioListExportMixin.py +32 -0
  60. edsl/scenarios/ScenarioListPdfMixin.py +2 -1
  61. edsl/scenarios/__init__.py +1 -0
  62. edsl/study/Study.py +8 -16
  63. edsl/surveys/MemoryPlan.py +11 -4
  64. edsl/surveys/Survey.py +88 -17
  65. edsl/surveys/SurveyExportMixin.py +4 -2
  66. edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
  67. edsl/tools/plotting.py +4 -2
  68. edsl/utilities/__init__.py +21 -21
  69. edsl/utilities/interface.py +66 -45
  70. edsl/utilities/utilities.py +11 -13
  71. {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/METADATA +11 -10
  72. {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/RECORD +74 -71
  73. {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/WHEEL +1 -1
  74. edsl-0.1.29.dev3.dist-info/entry_points.txt +0 -3
  75. {edsl-0.1.29.dev3.dist-info → edsl-0.1.30.dist-info}/LICENSE +0 -0
@@ -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 rich import print
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
- return memory_dag + rule_dag
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 not model:
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
- ) GROUP BY theme
97
- ORDER BY mentions DESC
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
 
@@ -1,22 +1,22 @@
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
- )
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
- 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
- )
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
+ # )
@@ -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
- # from PIL import Image, ImageDraw, ImageFont
8
- from rich.console import Console
9
- from rich.table import Table
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
- # display(console, table, filename)
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
- # display(console, table, filename)
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(console, table, filename)
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
- display(console, table, filename)
604
+ display_table(console, table, filename)
584
605
 
585
606
 
586
607
  if __name__ == "__main__":
@@ -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.29.dev3
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
+