edsl 0.1.29.dev6__py3-none-any.whl → 0.1.30.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 +6 -3
- edsl/__init__.py +23 -23
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +35 -34
- edsl/agents/AgentList.py +16 -5
- edsl/agents/Invigilator.py +19 -1
- edsl/agents/descriptors.py +2 -1
- edsl/base/Base.py +289 -0
- edsl/config.py +2 -1
- edsl/coop/utils.py +28 -1
- edsl/data/Cache.py +19 -5
- edsl/data/SQLiteDict.py +11 -3
- edsl/jobs/Answers.py +15 -1
- edsl/jobs/Jobs.py +69 -31
- edsl/jobs/buckets/ModelBuckets.py +4 -2
- edsl/jobs/buckets/TokenBucket.py +1 -2
- edsl/jobs/interviews/Interview.py +0 -6
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +9 -5
- edsl/jobs/runners/JobsRunnerAsyncio.py +12 -16
- edsl/jobs/tasks/TaskHistory.py +4 -3
- edsl/language_models/LanguageModel.py +5 -11
- edsl/language_models/ModelList.py +1 -1
- edsl/language_models/repair.py +8 -7
- edsl/notebooks/Notebook.py +9 -3
- edsl/questions/QuestionBase.py +6 -2
- edsl/questions/QuestionBudget.py +5 -6
- edsl/questions/QuestionCheckBox.py +7 -3
- edsl/questions/QuestionExtract.py +5 -3
- edsl/questions/QuestionFreeText.py +3 -3
- edsl/questions/QuestionFunctional.py +0 -3
- edsl/questions/QuestionList.py +3 -4
- edsl/questions/QuestionMultipleChoice.py +12 -5
- edsl/questions/QuestionNumerical.py +4 -3
- edsl/questions/QuestionRank.py +5 -3
- edsl/questions/__init__.py +4 -3
- edsl/questions/descriptors.py +4 -2
- edsl/results/DatasetExportMixin.py +491 -0
- edsl/results/Result.py +13 -65
- edsl/results/Results.py +91 -39
- edsl/results/ResultsDBMixin.py +7 -3
- edsl/results/ResultsExportMixin.py +22 -537
- edsl/results/ResultsGGMixin.py +3 -3
- edsl/results/ResultsToolsMixin.py +1 -4
- edsl/scenarios/FileStore.py +140 -0
- edsl/scenarios/Scenario.py +5 -6
- edsl/scenarios/ScenarioList.py +17 -8
- edsl/scenarios/ScenarioListExportMixin.py +32 -0
- edsl/scenarios/ScenarioListPdfMixin.py +2 -1
- edsl/scenarios/__init__.py +1 -0
- edsl/surveys/MemoryPlan.py +11 -4
- edsl/surveys/Survey.py +9 -4
- edsl/surveys/SurveyExportMixin.py +4 -2
- edsl/surveys/SurveyFlowVisualizationMixin.py +6 -4
- edsl/utilities/__init__.py +21 -21
- edsl/utilities/interface.py +66 -45
- edsl/utilities/utilities.py +11 -13
- {edsl-0.1.29.dev6.dist-info → edsl-0.1.30.dev1.dist-info}/METADATA +1 -1
- {edsl-0.1.29.dev6.dist-info → edsl-0.1.30.dev1.dist-info}/RECORD +60 -56
- {edsl-0.1.29.dev6.dist-info → edsl-0.1.30.dev1.dist-info}/LICENSE +0 -0
- {edsl-0.1.29.dev6.dist-info → edsl-0.1.30.dev1.dist-info}/WHEEL +0 -0
edsl/results/Results.py
CHANGED
@@ -5,16 +5,10 @@ It is not typically instantiated directly, but is returned by the run method of
|
|
5
5
|
|
6
6
|
from __future__ import annotations
|
7
7
|
import json
|
8
|
-
import hashlib
|
9
8
|
import random
|
10
9
|
from collections import UserList, defaultdict
|
11
10
|
from typing import Optional, Callable, Any, Type, Union, List
|
12
11
|
|
13
|
-
from pygments import highlight
|
14
|
-
from pygments.lexers import JsonLexer
|
15
|
-
from pygments.formatters import HtmlFormatter
|
16
|
-
from IPython.display import HTML
|
17
|
-
|
18
12
|
from simpleeval import EvalWithCompoundTypes
|
19
13
|
|
20
14
|
from edsl.exceptions.results import (
|
@@ -24,29 +18,17 @@ from edsl.exceptions.results import (
|
|
24
18
|
ResultsMutateError,
|
25
19
|
ResultsFilterError,
|
26
20
|
)
|
27
|
-
|
28
|
-
from edsl.language_models.LanguageModel import LanguageModel
|
29
|
-
from edsl.results.Dataset import Dataset
|
30
|
-
from edsl.results.Result import Result
|
21
|
+
|
31
22
|
from edsl.results.ResultsExportMixin import ResultsExportMixin
|
32
|
-
from edsl.scenarios import Scenario
|
33
|
-
|
34
|
-
# from edsl.scenarios.ScenarioList import ScenarioList
|
35
|
-
from edsl.surveys import Survey
|
36
|
-
from edsl.data.Cache import Cache
|
37
|
-
from edsl.utilities import (
|
38
|
-
is_valid_variable_name,
|
39
|
-
shorten_string,
|
40
|
-
)
|
41
|
-
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
42
|
-
from edsl.utilities.utilities import dict_hash
|
43
23
|
from edsl.results.ResultsToolsMixin import ResultsToolsMixin
|
44
|
-
|
45
24
|
from edsl.results.ResultsDBMixin import ResultsDBMixin
|
46
25
|
from edsl.results.ResultsGGMixin import ResultsGGMixin
|
26
|
+
from edsl.results.ResultsFetchMixin import ResultsFetchMixin
|
27
|
+
|
28
|
+
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
29
|
+
from edsl.utilities.utilities import dict_hash
|
47
30
|
|
48
31
|
from edsl.Base import Base
|
49
|
-
from edsl.results.ResultsFetchMixin import ResultsFetchMixin
|
50
32
|
|
51
33
|
|
52
34
|
class Mixins(
|
@@ -56,7 +38,22 @@ class Mixins(
|
|
56
38
|
ResultsGGMixin,
|
57
39
|
ResultsToolsMixin,
|
58
40
|
):
|
59
|
-
|
41
|
+
def print_long(self, max_rows=None) -> None:
|
42
|
+
"""Print the results in long format.
|
43
|
+
|
44
|
+
>>> from edsl.results import Results
|
45
|
+
>>> r = Results.example()
|
46
|
+
>>> r.select('how_feeling').print_long(max_rows = 2)
|
47
|
+
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┓
|
48
|
+
┃ Result index ┃ Key ┃ Value ┃
|
49
|
+
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━┩
|
50
|
+
│ 0 │ how_feeling │ OK │
|
51
|
+
│ 1 │ how_feeling │ Great │
|
52
|
+
└──────────────┴─────────────┴───────┘
|
53
|
+
"""
|
54
|
+
from edsl.utilities.interface import print_results_long
|
55
|
+
|
56
|
+
print_results_long(self, max_rows=max_rows)
|
60
57
|
|
61
58
|
|
62
59
|
class Results(UserList, Mixins, Base):
|
@@ -84,10 +81,10 @@ class Results(UserList, Mixins, Base):
|
|
84
81
|
|
85
82
|
def __init__(
|
86
83
|
self,
|
87
|
-
survey: Optional[Survey] = None,
|
88
|
-
data: Optional[list[Result]] = None,
|
84
|
+
survey: Optional["Survey"] = None,
|
85
|
+
data: Optional[list["Result"]] = None,
|
89
86
|
created_columns: Optional[list[str]] = None,
|
90
|
-
cache: Optional[Cache] = None,
|
87
|
+
cache: Optional["Cache"] = None,
|
91
88
|
job_uuid: Optional[str] = None,
|
92
89
|
total_results: Optional[int] = None,
|
93
90
|
):
|
@@ -100,6 +97,8 @@ class Results(UserList, Mixins, Base):
|
|
100
97
|
:param total_results: An integer representing the total number of results.
|
101
98
|
"""
|
102
99
|
super().__init__(data)
|
100
|
+
from edsl.data.Cache import Cache
|
101
|
+
|
103
102
|
self.survey = survey
|
104
103
|
self.created_columns = created_columns or []
|
105
104
|
self._job_uuid = job_uuid
|
@@ -125,6 +124,10 @@ class Results(UserList, Mixins, Base):
|
|
125
124
|
raise TypeError("Invalid argument type")
|
126
125
|
|
127
126
|
def _update_results(self) -> None:
|
127
|
+
from edsl import Agent, Scenario
|
128
|
+
from edsl.language_models import LanguageModel
|
129
|
+
from edsl.results import Result
|
130
|
+
|
128
131
|
if self._job_uuid and len(self.data) < self._total_results:
|
129
132
|
results = [
|
130
133
|
Result(
|
@@ -168,7 +171,13 @@ class Results(UserList, Mixins, Base):
|
|
168
171
|
return f"Results(data = {self.data}, survey = {repr(self.survey)}, created_columns = {self.created_columns})"
|
169
172
|
|
170
173
|
def _repr_html_(self) -> str:
|
174
|
+
from IPython.display import HTML
|
175
|
+
|
171
176
|
json_str = json.dumps(self.to_dict()["data"], indent=4)
|
177
|
+
from pygments import highlight
|
178
|
+
from pygments.lexers import JsonLexer
|
179
|
+
from pygments.formatters import HtmlFormatter
|
180
|
+
|
172
181
|
formatted_json = highlight(
|
173
182
|
json_str,
|
174
183
|
JsonLexer(),
|
@@ -177,6 +186,8 @@ class Results(UserList, Mixins, Base):
|
|
177
186
|
return HTML(formatted_json).data
|
178
187
|
|
179
188
|
def _to_dict(self, sort=False):
|
189
|
+
from edsl.data.Cache import Cache
|
190
|
+
|
180
191
|
if sort:
|
181
192
|
data = sorted([result for result in self.data], key=lambda x: hash(x))
|
182
193
|
else:
|
@@ -226,6 +237,31 @@ class Results(UserList, Mixins, Base):
|
|
226
237
|
def hashes(self) -> set:
|
227
238
|
return set(hash(result) for result in self.data)
|
228
239
|
|
240
|
+
def sample(self, n: int) -> "Results":
|
241
|
+
"""Return a random sample of the results.
|
242
|
+
|
243
|
+
:param n: The number of samples to return.
|
244
|
+
|
245
|
+
>>> from edsl.results import Results
|
246
|
+
>>> r = Results.example()
|
247
|
+
>>> len(r.sample(2))
|
248
|
+
2
|
249
|
+
"""
|
250
|
+
indices = None
|
251
|
+
|
252
|
+
for entry in self:
|
253
|
+
key, values = list(entry.items())[0]
|
254
|
+
if indices is None: # gets the indices for the first time
|
255
|
+
indices = list(range(len(values)))
|
256
|
+
sampled_indices = random.sample(indices, n)
|
257
|
+
if n > len(indices):
|
258
|
+
raise ValueError(
|
259
|
+
f"Cannot sample {n} items from a list of length {len(indices)}."
|
260
|
+
)
|
261
|
+
entry[key] = [values[i] for i in sampled_indices]
|
262
|
+
|
263
|
+
return self
|
264
|
+
|
229
265
|
@classmethod
|
230
266
|
@remove_edsl_version
|
231
267
|
def from_dict(cls, data: dict[str, Any]) -> Results:
|
@@ -241,12 +277,20 @@ class Results(UserList, Mixins, Base):
|
|
241
277
|
>>> r == r2
|
242
278
|
True
|
243
279
|
"""
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
280
|
+
from edsl import Survey, Cache
|
281
|
+
from edsl.results.Result import Result
|
282
|
+
|
283
|
+
try:
|
284
|
+
results = cls(
|
285
|
+
survey=Survey.from_dict(data["survey"]),
|
286
|
+
data=[Result.from_dict(r) for r in data["data"]],
|
287
|
+
created_columns=data.get("created_columns", None),
|
288
|
+
cache=(
|
289
|
+
Cache.from_dict(data.get("cache")) if "cache" in data else Cache()
|
290
|
+
),
|
291
|
+
)
|
292
|
+
except Exception as e:
|
293
|
+
breakpoint()
|
250
294
|
return results
|
251
295
|
|
252
296
|
######################
|
@@ -313,6 +357,8 @@ class Results(UserList, Mixins, Base):
|
|
313
357
|
>>> r.answer_keys
|
314
358
|
{'how_feeling': 'How are you this {{ period }}?', 'how_feeling_yesterday': 'How were you feeling yesterday {{ period }}?'}
|
315
359
|
"""
|
360
|
+
from edsl.utilities.utilities import shorten_string
|
361
|
+
|
316
362
|
if not self.survey:
|
317
363
|
raise Exception("Survey is not defined so no answer keys are available.")
|
318
364
|
|
@@ -327,7 +373,7 @@ class Results(UserList, Mixins, Base):
|
|
327
373
|
return sorted_dict
|
328
374
|
|
329
375
|
@property
|
330
|
-
def agents(self) -> AgentList:
|
376
|
+
def agents(self) -> "AgentList":
|
331
377
|
"""Return a list of all of the agents in the Results.
|
332
378
|
|
333
379
|
Example:
|
@@ -336,10 +382,12 @@ class Results(UserList, Mixins, Base):
|
|
336
382
|
>>> r.agents
|
337
383
|
AgentList([Agent(traits = {'status': 'Joyful'}), Agent(traits = {'status': 'Joyful'}), Agent(traits = {'status': 'Sad'}), Agent(traits = {'status': 'Sad'})])
|
338
384
|
"""
|
385
|
+
from edsl import AgentList
|
386
|
+
|
339
387
|
return AgentList([r.agent for r in self.data])
|
340
388
|
|
341
389
|
@property
|
342
|
-
def models(self) -> list[Type[LanguageModel]]:
|
390
|
+
def models(self) -> list[Type["LanguageModel"]]:
|
343
391
|
"""Return a list of all of the models in the Results.
|
344
392
|
|
345
393
|
Example:
|
@@ -461,7 +509,7 @@ class Results(UserList, Mixins, Base):
|
|
461
509
|
)
|
462
510
|
return data_type, key
|
463
511
|
|
464
|
-
def first(self) -> Result:
|
512
|
+
def first(self) -> "Result":
|
465
513
|
"""Return the first observation in the results.
|
466
514
|
|
467
515
|
Example:
|
@@ -579,6 +627,8 @@ class Results(UserList, Mixins, Base):
|
|
579
627
|
)
|
580
628
|
raw_var_name, expression = new_var_string.split("=", 1)
|
581
629
|
var_name = raw_var_name.strip()
|
630
|
+
from edsl.utilities.utilities import is_valid_variable_name
|
631
|
+
|
582
632
|
if not is_valid_variable_name(var_name):
|
583
633
|
raise ResultsInvalidNameError(f"{var_name} is not a valid variable name.")
|
584
634
|
|
@@ -590,7 +640,7 @@ class Results(UserList, Mixins, Base):
|
|
590
640
|
names=result.combined_dict, functions=functions_dict
|
591
641
|
)
|
592
642
|
|
593
|
-
def new_result(old_result: Result, var_name: str) -> Result:
|
643
|
+
def new_result(old_result: "Result", var_name: str) -> "Result":
|
594
644
|
evaluator = create_evaluator(old_result)
|
595
645
|
value = evaluator.eval(expression)
|
596
646
|
new_result = old_result.copy()
|
@@ -680,7 +730,7 @@ class Results(UserList, Mixins, Base):
|
|
680
730
|
|
681
731
|
return Results(survey=self.survey, data=new_data, created_columns=None)
|
682
732
|
|
683
|
-
def select(self, *columns: Union[str, list[str]]) -> Dataset:
|
733
|
+
def select(self, *columns: Union[str, list[str]]) -> "Dataset":
|
684
734
|
"""
|
685
735
|
Select data from the results and format it.
|
686
736
|
|
@@ -692,6 +742,7 @@ class Results(UserList, Mixins, Base):
|
|
692
742
|
>>> results.select('how_feeling')
|
693
743
|
Dataset([{'answer.how_feeling': ['OK', 'Great', 'Terrible', 'OK']}])
|
694
744
|
"""
|
745
|
+
|
695
746
|
if len(self) == 0:
|
696
747
|
raise Exception("No data to select from---the Results object is empty.")
|
697
748
|
|
@@ -748,6 +799,7 @@ class Results(UserList, Mixins, Base):
|
|
748
799
|
return items_in_order.index(single_key)
|
749
800
|
|
750
801
|
sorted(new_data, key=sort_by_key_order)
|
802
|
+
from edsl.results.Dataset import Dataset
|
751
803
|
|
752
804
|
return Dataset(new_data)
|
753
805
|
|
@@ -906,7 +958,7 @@ class Results(UserList, Mixins, Base):
|
|
906
958
|
|
907
959
|
:param debug: if False, uses actual API calls
|
908
960
|
"""
|
909
|
-
from edsl.jobs import Jobs
|
961
|
+
from edsl.jobs.Jobs import Jobs
|
910
962
|
from edsl.data.Cache import Cache
|
911
963
|
|
912
964
|
c = Cache()
|
edsl/results/ResultsDBMixin.py
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
"""Mixin for working with SQLite respresentation of a 'Results' object."""
|
2
2
|
|
3
|
-
import pandas as pd
|
4
3
|
import sqlite3
|
5
|
-
from sqlalchemy import create_engine
|
6
4
|
from enum import Enum
|
7
5
|
from typing import Literal, Union, Optional
|
8
6
|
|
@@ -92,6 +90,8 @@ class ResultsDBMixin:
|
|
92
90
|
conn.commit()
|
93
91
|
return conn
|
94
92
|
elif shape == SQLDataShape.WIDE:
|
93
|
+
from sqlalchemy import create_engine
|
94
|
+
|
95
95
|
engine = create_engine("sqlite:///:memory:")
|
96
96
|
df = self.to_pandas(remove_prefix=remove_prefix)
|
97
97
|
df.to_sql("self", engine, index=False, if_exists="replace")
|
@@ -121,7 +121,7 @@ class ResultsDBMixin:
|
|
121
121
|
to_list=False,
|
122
122
|
to_latex=False,
|
123
123
|
filename: Optional[str] = None,
|
124
|
-
) -> Union[pd.DataFrame, str]:
|
124
|
+
) -> Union["pd.DataFrame", str]:
|
125
125
|
"""Execute a SQL query and return the results as a DataFrame.
|
126
126
|
|
127
127
|
:param query: The SQL query to execute
|
@@ -151,6 +151,8 @@ class ResultsDBMixin:
|
|
151
151
|
2 Terrible
|
152
152
|
3 OK
|
153
153
|
"""
|
154
|
+
import pandas as pd
|
155
|
+
|
154
156
|
shape_enum = self._get_shape_enum(shape)
|
155
157
|
|
156
158
|
conn = self._db(shape=shape_enum, remove_prefix=remove_prefix)
|
@@ -205,6 +207,8 @@ class ResultsDBMixin:
|
|
205
207
|
...
|
206
208
|
<BLANKLINE>
|
207
209
|
"""
|
210
|
+
import pandas as pd
|
211
|
+
|
208
212
|
shape_enum = self._get_shape_enum(shape)
|
209
213
|
conn = self._db(shape=shape_enum, remove_prefix=remove_prefix)
|
210
214
|
|