edsl 0.1.38__py3-none-any.whl → 0.1.38.dev1__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 (86) hide show
  1. edsl/Base.py +34 -63
  2. edsl/BaseDiff.py +7 -7
  3. edsl/__init__.py +1 -2
  4. edsl/__version__.py +1 -1
  5. edsl/agents/Agent.py +11 -23
  6. edsl/agents/AgentList.py +23 -86
  7. edsl/agents/Invigilator.py +7 -18
  8. edsl/agents/InvigilatorBase.py +19 -0
  9. edsl/agents/PromptConstructor.py +4 -5
  10. edsl/auto/SurveyCreatorPipeline.py +1 -1
  11. edsl/auto/utilities.py +1 -1
  12. edsl/base/Base.py +13 -3
  13. edsl/config.py +0 -8
  14. edsl/conjure/AgentConstructionMixin.py +160 -0
  15. edsl/conjure/Conjure.py +62 -0
  16. edsl/conjure/InputData.py +659 -0
  17. edsl/conjure/InputDataCSV.py +48 -0
  18. edsl/conjure/InputDataMixinQuestionStats.py +182 -0
  19. edsl/conjure/InputDataPyRead.py +91 -0
  20. edsl/conjure/InputDataSPSS.py +8 -0
  21. edsl/conjure/InputDataStata.py +8 -0
  22. edsl/conjure/QuestionOptionMixin.py +76 -0
  23. edsl/conjure/QuestionTypeMixin.py +23 -0
  24. edsl/conjure/RawQuestion.py +65 -0
  25. edsl/conjure/SurveyResponses.py +7 -0
  26. edsl/conjure/__init__.py +9 -0
  27. edsl/conjure/examples/placeholder.txt +0 -0
  28. edsl/{utilities → conjure}/naming_utilities.py +1 -1
  29. edsl/conjure/utilities.py +201 -0
  30. edsl/coop/coop.py +7 -77
  31. edsl/data/Cache.py +17 -45
  32. edsl/data/CacheEntry.py +3 -8
  33. edsl/data/RemoteCacheSync.py +19 -0
  34. edsl/enums.py +0 -2
  35. edsl/exceptions/agents.py +0 -4
  36. edsl/inference_services/GoogleService.py +15 -7
  37. edsl/inference_services/registry.py +0 -2
  38. edsl/jobs/Jobs.py +559 -110
  39. edsl/jobs/buckets/TokenBucket.py +0 -3
  40. edsl/jobs/interviews/Interview.py +7 -7
  41. edsl/jobs/runners/JobsRunnerAsyncio.py +28 -156
  42. edsl/jobs/runners/JobsRunnerStatus.py +196 -194
  43. edsl/jobs/tasks/TaskHistory.py +19 -27
  44. edsl/language_models/LanguageModel.py +90 -52
  45. edsl/language_models/ModelList.py +14 -67
  46. edsl/language_models/registry.py +4 -57
  47. edsl/notebooks/Notebook.py +8 -7
  48. edsl/prompts/Prompt.py +3 -8
  49. edsl/questions/QuestionBase.py +30 -38
  50. edsl/questions/QuestionBaseGenMixin.py +1 -1
  51. edsl/questions/QuestionBasePromptsMixin.py +17 -0
  52. edsl/questions/QuestionExtract.py +4 -3
  53. edsl/questions/QuestionFunctional.py +3 -10
  54. edsl/questions/derived/QuestionTopK.py +0 -2
  55. edsl/questions/question_registry.py +6 -36
  56. edsl/results/Dataset.py +15 -146
  57. edsl/results/DatasetExportMixin.py +217 -231
  58. edsl/results/DatasetTree.py +4 -134
  59. edsl/results/Result.py +16 -31
  60. edsl/results/Results.py +65 -159
  61. edsl/scenarios/FileStore.py +13 -187
  62. edsl/scenarios/Scenario.py +18 -73
  63. edsl/scenarios/ScenarioList.py +76 -251
  64. edsl/surveys/MemoryPlan.py +1 -1
  65. edsl/surveys/Rule.py +5 -1
  66. edsl/surveys/RuleCollection.py +1 -1
  67. edsl/surveys/Survey.py +19 -25
  68. edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
  69. edsl/surveys/instructions/ChangeInstruction.py +7 -9
  70. edsl/surveys/instructions/Instruction.py +7 -21
  71. edsl/templates/error_reporting/interview_details.html +3 -3
  72. edsl/templates/error_reporting/interviews.html +9 -18
  73. edsl/utilities/utilities.py +0 -15
  74. {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/METADATA +1 -2
  75. {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/RECORD +77 -71
  76. edsl/exceptions/cache.py +0 -5
  77. edsl/inference_services/PerplexityService.py +0 -163
  78. edsl/jobs/JobsChecks.py +0 -147
  79. edsl/jobs/JobsPrompts.py +0 -268
  80. edsl/jobs/JobsRemoteInferenceHandler.py +0 -239
  81. edsl/results/CSSParameterizer.py +0 -108
  82. edsl/results/TableDisplay.py +0 -198
  83. edsl/results/table_display.css +0 -78
  84. edsl/scenarios/ScenarioJoin.py +0 -127
  85. {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/LICENSE +0 -0
  86. {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/WHEEL +0 -0
@@ -14,87 +14,18 @@ from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
14
14
  from edsl.utilities.utilities import is_notebook
15
15
 
16
16
 
17
- def view_csv(csv_path):
18
- import pandas as pd
19
-
20
- df = pd.read_csv(csv_path)
21
- return df
22
-
23
-
24
- def view_html(html_path):
25
- import os
26
- import subprocess
27
- from IPython.display import IFrame, display, HTML
28
-
29
- if os.path.exists(html_path):
30
- if is_notebook():
31
- # Display the HTML inline in Jupyter Notebook
32
- display(IFrame(src=html_path, width=700, height=600))
33
- display(
34
- HTML(
35
- f'<a href="{html_path}" target="_blank">Open HTML in a new tab</a>'
36
- )
37
- )
38
- else:
39
- try:
40
- if (os_name := os.name) == "posix":
41
- # Open with the default browser on macOS
42
- subprocess.run(["open", html_path], check=True)
43
- elif os_name == "nt":
44
- # Open with the default browser on Windows
45
- os.startfile(html_path)
46
- else:
47
- # Open with the default browser on Linux
48
- subprocess.run(["xdg-open", html_path], check=True)
49
- except Exception as e:
50
- print(f"Error opening HTML file: {e}")
51
- else:
52
- print("HTML file was not found.")
53
-
54
-
55
- def view_html(html_path):
56
- import os
57
- from IPython.display import display, HTML
58
-
59
- if is_notebook():
60
- with open(html_path, "r") as f:
61
- html_content = f.read()
62
- display(HTML(html_content))
63
- else:
64
- if os.path.exists(html_path):
65
- try:
66
- if (os_name := os.name) == "posix":
67
- subprocess.run(["open", html_path], check=True)
68
- elif os_name == "nt":
69
- os.startfile(html_path)
70
- else:
71
- subprocess.run(["xdg-open", html_path], check=True)
72
- except Exception as e:
73
- print(f"Error opening file: {e}")
74
- else:
75
- print("File was not created successfully.")
76
-
77
-
78
17
  def view_pdf(pdf_path):
79
18
  import os
80
19
  import subprocess
81
- import os
82
- from IPython.display import HTML, display
83
20
 
84
21
  if is_notebook():
85
- # Convert to absolute path if needed
86
- with open(pdf_path, "rb") as f:
87
- base64_pdf = base64.b64encode(f.read()).decode("utf-8")
88
-
89
- html = f"""
90
- <iframe
91
- src="data:application/pdf;base64,{base64_pdf}"
92
- width="800px"
93
- height="800px"
94
- type="application/pdf"
95
- ></iframe>
96
- """
97
- display(HTML(html))
22
+ from IPython.display import IFrame
23
+ from IPython.display import display, HTML
24
+
25
+ # Replace 'path/to/your/file.pdf' with the actual path to your PDF file
26
+ IFrame(pdf_path, width=700, height=600)
27
+ display(HTML(f'<a href="{pdf_path}" target="_blank">Open PDF</a>'))
28
+ return
98
29
 
99
30
  if os.path.exists(pdf_path):
100
31
  try:
@@ -112,8 +43,6 @@ def view_pdf(pdf_path):
112
43
 
113
44
 
114
45
  class FileStore(Scenario):
115
- __documentation__ = "https://docs.expectedparrot.com/en/latest/filestore.html"
116
-
117
46
  def __init__(
118
47
  self,
119
48
  path: Optional[str] = None,
@@ -126,10 +55,7 @@ class FileStore(Scenario):
126
55
  ):
127
56
  if path is None and "filename" in kwargs:
128
57
  path = kwargs["filename"]
129
-
130
- self._path = path # Store the original path privately
131
- self._temp_path = None # Track any generated temporary file
132
-
58
+ self.path = path
133
59
  self.suffix = suffix or path.split(".")[-1]
134
60
  self.binary = binary or False
135
61
  self.mime_type = (
@@ -139,7 +65,7 @@ class FileStore(Scenario):
139
65
  self.external_locations = external_locations or {}
140
66
  super().__init__(
141
67
  {
142
- "path": path,
68
+ "path": self.path,
143
69
  "base64_string": self.base64_string,
144
70
  "binary": self.binary,
145
71
  "suffix": self.suffix,
@@ -148,110 +74,17 @@ class FileStore(Scenario):
148
74
  }
149
75
  )
150
76
 
151
- @property
152
- def path(self) -> str:
153
- """
154
- Property that returns a valid path to the file content.
155
- If the original path doesn't exist, generates a temporary file from the base64 content.
156
- """
157
- # Check if original path exists and is accessible
158
- if self._path and os.path.isfile(self._path):
159
- return self._path
160
-
161
- # If we already have a valid temporary file, use it
162
- if self._temp_path and os.path.isfile(self._temp_path):
163
- return self._temp_path
164
-
165
- # Generate a new temporary file from base64 content
166
- self._temp_path = self.to_tempfile(self.suffix)
167
- return self._temp_path
168
-
169
77
  def __str__(self):
170
78
  return "FileStore: self.path"
171
79
 
172
80
  @classmethod
173
- def example(cls, example_type="text"):
174
- import textwrap
81
+ def example(self):
175
82
  import tempfile
176
83
 
177
- if example_type == "png" or example_type == "image":
178
- import importlib.resources
179
- from pathlib import Path
180
-
181
- # Get package root directory
182
- package_root = Path(__file__).parent.parent.parent
183
- logo_path = package_root / "static" / "logo.png"
184
- return cls(str(logo_path))
185
-
186
- if example_type == "text":
187
- with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as f:
188
- f.write(b"Hello, World!")
189
-
190
- return cls(path=f.name)
84
+ with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as f:
85
+ f.write(b"Hello, World!")
191
86
 
192
- elif example_type == "csv":
193
- from edsl.results.Results import Results
194
-
195
- r = Results.example()
196
-
197
- with tempfile.NamedTemporaryFile(suffix=".csv", delete=False) as f:
198
- r.to_csv(filename=f.name)
199
- return cls(f.name)
200
-
201
- elif example_type == "pdf":
202
- pdf_string = textwrap.dedent(
203
- """\
204
- %PDF-1.4
205
- 1 0 obj
206
- << /Type /Catalog /Pages 2 0 R >>
207
- endobj
208
- 2 0 obj
209
- << /Type /Pages /Kids [3 0 R] /Count 1 >>
210
- endobj
211
- 3 0 obj
212
- << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R >>
213
- endobj
214
- 4 0 obj
215
- << /Length 44 >>
216
- stream
217
- BT
218
- /F1 24 Tf
219
- 100 700 Td
220
- (Hello, World!) Tj
221
- ET
222
- endstream
223
- endobj
224
- 5 0 obj
225
- << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
226
- endobj
227
- 6 0 obj
228
- << /ProcSet [/PDF /Text] /Font << /F1 5 0 R >> >>
229
- endobj
230
- xref
231
- 0 7
232
- 0000000000 65535 f
233
- 0000000010 00000 n
234
- 0000000053 00000 n
235
- 0000000100 00000 n
236
- 0000000173 00000 n
237
- 0000000232 00000 n
238
- 0000000272 00000 n
239
- trailer
240
- << /Size 7 /Root 1 0 R >>
241
- startxref
242
- 318
243
- %%EOF"""
244
- )
245
- with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f:
246
- f.write(pdf_string.encode())
247
-
248
- return cls(f.name)
249
-
250
- elif example_type == "html":
251
- with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as f:
252
- f.write("<html><body><h1>Test</h1></body></html>".encode())
253
-
254
- return cls(f.name)
87
+ return self(path=f.name)
255
88
 
256
89
  @property
257
90
  def size(self) -> int:
@@ -353,16 +186,9 @@ class FileStore(Scenario):
353
186
  return temp_file.name
354
187
 
355
188
  def view(self, max_size: int = 300) -> None:
356
- # with self.open() as f:
357
- if self.suffix == "csv":
358
- return view_csv(self.path)
359
-
360
189
  if self.suffix == "pdf":
361
190
  view_pdf(self.path)
362
191
 
363
- if self.suffix == "html":
364
- view_html(self.path)
365
-
366
192
  if self.suffix == "png" or self.suffix == "jpg" or self.suffix == "jpeg":
367
193
  if is_notebook():
368
194
  from IPython.display import Image
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
  import copy
5
5
  import hashlib
6
6
  import os
7
- import json
8
7
  from collections import UserDict
9
8
  from typing import Union, List, Optional, Generator
10
9
  from uuid import uuid4
@@ -15,30 +14,12 @@ from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
15
14
  from edsl.exceptions.scenarios import ScenarioError
16
15
 
17
16
 
18
- class DisplayJSON:
19
- def __init__(self, dict):
20
- self.text = json.dumps(dict, indent=4)
21
-
22
- def __repr__(self):
23
- return self.text
24
-
25
-
26
- class DisplayYAML:
27
- def __init__(self, dict):
28
- import yaml
29
-
30
- self.text = yaml.dump(dict)
31
-
32
- def __repr__(self):
33
- return self.text
34
-
35
-
36
17
  class Scenario(Base, UserDict, ScenarioHtmlMixin):
37
18
  """A Scenario is a dictionary of keys/values.
38
19
 
39
20
  They can be used parameterize EDSL questions."""
40
21
 
41
- __documentation__ = "https://docs.expectedparrot.com/en/latest/scenarios.html"
22
+ __doc__ = "https://docs.expectedparrot.com/en/latest/scenarios.html"
42
23
 
43
24
  def __init__(self, data: Union[dict, None] = None, name: str = None):
44
25
  """Initialize a new Scenario.
@@ -156,23 +137,7 @@ class Scenario(Base, UserDict, ScenarioHtmlMixin):
156
137
  new_scenario[key] = value
157
138
  return new_scenario
158
139
 
159
- def table(self, tablefmt: str = "grid") -> str:
160
- from edsl.results.Dataset import Dataset
161
-
162
- keys = [key for key, value in self.items()]
163
- values = [value for key, value in self.items()]
164
- d = Dataset([{"key": keys}, {"value": values}])
165
- return d.table(tablefmt=tablefmt)
166
-
167
- def json(self):
168
- return DisplayJSON(self.to_dict(add_edsl_version=False))
169
-
170
- def yaml(self):
171
- import yaml
172
-
173
- return DisplayYAML(self.to_dict(add_edsl_version=False))
174
-
175
- def to_dict(self, add_edsl_version=True) -> dict:
140
+ def _to_dict(self) -> dict:
176
141
  """Convert a scenario to a dictionary.
177
142
 
178
143
  Example:
@@ -180,24 +145,26 @@ class Scenario(Base, UserDict, ScenarioHtmlMixin):
180
145
  >>> s = Scenario({"food": "wood chips"})
181
146
  >>> s.to_dict()
182
147
  {'food': 'wood chips', 'edsl_version': '...', 'edsl_class_name': 'Scenario'}
183
-
184
- >>> s.to_dict(add_edsl_version = False)
185
- {'food': 'wood chips'}
186
-
187
148
  """
188
149
  from edsl.scenarios.FileStore import FileStore
189
150
 
190
151
  d = self.data.copy()
191
152
  for key, value in d.items():
192
153
  if isinstance(value, FileStore):
193
- d[key] = value.to_dict(add_edsl_version=add_edsl_version)
194
- if add_edsl_version:
195
- from edsl import __version__
154
+ d[key] = value.to_dict()
155
+ return d
196
156
 
197
- d["edsl_version"] = __version__
198
- d["edsl_class_name"] = "Scenario"
157
+ @add_edsl_version
158
+ def to_dict(self) -> dict:
159
+ """Convert a scenario to a dictionary.
199
160
 
200
- return d
161
+ Example:
162
+
163
+ >>> s = Scenario({"food": "wood chips"})
164
+ >>> s.to_dict()
165
+ {'food': 'wood chips', 'edsl_version': '...', 'edsl_class_name': 'Scenario'}
166
+ """
167
+ return self._to_dict()
201
168
 
202
169
  def __hash__(self) -> int:
203
170
  """
@@ -211,7 +178,7 @@ class Scenario(Base, UserDict, ScenarioHtmlMixin):
211
178
  """
212
179
  from edsl.utilities.utilities import dict_hash
213
180
 
214
- return dict_hash(self.to_dict(add_edsl_version=False))
181
+ return dict_hash(self._to_dict())
215
182
 
216
183
  def print(self):
217
184
  from rich import print_json
@@ -220,35 +187,13 @@ class Scenario(Base, UserDict, ScenarioHtmlMixin):
220
187
  print_json(json.dumps(self.to_dict()))
221
188
 
222
189
  def __repr__(self):
190
+ # return "Scenario(" + reprlib.repr(self.data) + ")"
223
191
  return "Scenario(" + repr(self.data) + ")"
224
192
 
225
- def to_dataset(self) -> "Dataset":
226
- # d = Dataset([{'a.b':[1,2,3,4]}])
227
- from edsl.results.Dataset import Dataset
228
-
229
- keys = [key for key, value in self.items()]
230
- values = [value for key, value in self.items()]
231
- return Dataset([{"key": keys}, {"value": values}])
232
-
233
193
  def _repr_html_(self):
234
- from tabulate import tabulate
235
- import reprlib
236
-
237
- d = self.to_dict(add_edsl_version=False)
238
- # return self.to_dataset()
239
- r = reprlib.Repr()
240
- r.maxstring = 70
241
-
242
- data = [[k, r.repr(v)] for k, v in d.items()]
243
- from tabulate import tabulate
244
-
245
- if hasattr(self, "__documentation__"):
246
- footer = f"<a href='{self.__documentation__}'>(docs)</a></p>"
247
- else:
248
- footer = ""
194
+ from edsl.utilities.utilities import data_to_html
249
195
 
250
- table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
251
- return f"<pre>{table}</pre>" + footer
196
+ return data_to_html(self.to_dict())
252
197
 
253
198
  def select(self, list_of_keys: List[str]) -> "Scenario":
254
199
  """Select a subset of keys from a scenario.