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.
- edsl/Base.py +34 -63
- edsl/BaseDiff.py +7 -7
- edsl/__init__.py +1 -2
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +11 -23
- edsl/agents/AgentList.py +23 -86
- edsl/agents/Invigilator.py +7 -18
- edsl/agents/InvigilatorBase.py +19 -0
- edsl/agents/PromptConstructor.py +4 -5
- edsl/auto/SurveyCreatorPipeline.py +1 -1
- edsl/auto/utilities.py +1 -1
- edsl/base/Base.py +13 -3
- edsl/config.py +0 -8
- edsl/conjure/AgentConstructionMixin.py +160 -0
- edsl/conjure/Conjure.py +62 -0
- edsl/conjure/InputData.py +659 -0
- edsl/conjure/InputDataCSV.py +48 -0
- edsl/conjure/InputDataMixinQuestionStats.py +182 -0
- edsl/conjure/InputDataPyRead.py +91 -0
- edsl/conjure/InputDataSPSS.py +8 -0
- edsl/conjure/InputDataStata.py +8 -0
- edsl/conjure/QuestionOptionMixin.py +76 -0
- edsl/conjure/QuestionTypeMixin.py +23 -0
- edsl/conjure/RawQuestion.py +65 -0
- edsl/conjure/SurveyResponses.py +7 -0
- edsl/conjure/__init__.py +9 -0
- edsl/conjure/examples/placeholder.txt +0 -0
- edsl/{utilities → conjure}/naming_utilities.py +1 -1
- edsl/conjure/utilities.py +201 -0
- edsl/coop/coop.py +7 -77
- edsl/data/Cache.py +17 -45
- edsl/data/CacheEntry.py +3 -8
- edsl/data/RemoteCacheSync.py +19 -0
- edsl/enums.py +0 -2
- edsl/exceptions/agents.py +0 -4
- edsl/inference_services/GoogleService.py +15 -7
- edsl/inference_services/registry.py +0 -2
- edsl/jobs/Jobs.py +559 -110
- edsl/jobs/buckets/TokenBucket.py +0 -3
- edsl/jobs/interviews/Interview.py +7 -7
- edsl/jobs/runners/JobsRunnerAsyncio.py +28 -156
- edsl/jobs/runners/JobsRunnerStatus.py +196 -194
- edsl/jobs/tasks/TaskHistory.py +19 -27
- edsl/language_models/LanguageModel.py +90 -52
- edsl/language_models/ModelList.py +14 -67
- edsl/language_models/registry.py +4 -57
- edsl/notebooks/Notebook.py +8 -7
- edsl/prompts/Prompt.py +3 -8
- edsl/questions/QuestionBase.py +30 -38
- edsl/questions/QuestionBaseGenMixin.py +1 -1
- edsl/questions/QuestionBasePromptsMixin.py +17 -0
- edsl/questions/QuestionExtract.py +4 -3
- edsl/questions/QuestionFunctional.py +3 -10
- edsl/questions/derived/QuestionTopK.py +0 -2
- edsl/questions/question_registry.py +6 -36
- edsl/results/Dataset.py +15 -146
- edsl/results/DatasetExportMixin.py +217 -231
- edsl/results/DatasetTree.py +4 -134
- edsl/results/Result.py +16 -31
- edsl/results/Results.py +65 -159
- edsl/scenarios/FileStore.py +13 -187
- edsl/scenarios/Scenario.py +18 -73
- edsl/scenarios/ScenarioList.py +76 -251
- edsl/surveys/MemoryPlan.py +1 -1
- edsl/surveys/Rule.py +5 -1
- edsl/surveys/RuleCollection.py +1 -1
- edsl/surveys/Survey.py +19 -25
- edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
- edsl/surveys/instructions/ChangeInstruction.py +7 -9
- edsl/surveys/instructions/Instruction.py +7 -21
- edsl/templates/error_reporting/interview_details.html +3 -3
- edsl/templates/error_reporting/interviews.html +9 -18
- edsl/utilities/utilities.py +0 -15
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/METADATA +1 -2
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/RECORD +77 -71
- edsl/exceptions/cache.py +0 -5
- edsl/inference_services/PerplexityService.py +0 -163
- edsl/jobs/JobsChecks.py +0 -147
- edsl/jobs/JobsPrompts.py +0 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +0 -239
- edsl/results/CSSParameterizer.py +0 -108
- edsl/results/TableDisplay.py +0 -198
- edsl/results/table_display.css +0 -78
- edsl/scenarios/ScenarioJoin.py +0 -127
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/LICENSE +0 -0
- {edsl-0.1.38.dist-info → edsl-0.1.38.dev1.dist-info}/WHEEL +0 -0
edsl/scenarios/FileStore.py
CHANGED
@@ -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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
<
|
91
|
-
|
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(
|
174
|
-
import textwrap
|
81
|
+
def example(self):
|
175
82
|
import tempfile
|
176
83
|
|
177
|
-
|
178
|
-
|
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
|
-
|
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
|
edsl/scenarios/Scenario.py
CHANGED
@@ -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
|
-
|
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
|
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(
|
194
|
-
|
195
|
-
from edsl import __version__
|
154
|
+
d[key] = value.to_dict()
|
155
|
+
return d
|
196
156
|
|
197
|
-
|
198
|
-
|
157
|
+
@add_edsl_version
|
158
|
+
def to_dict(self) -> dict:
|
159
|
+
"""Convert a scenario to a dictionary.
|
199
160
|
|
200
|
-
|
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.
|
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
|
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
|
-
|
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.
|