edsl 0.1.39__py3-none-any.whl → 0.1.39.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 +116 -197
- edsl/__init__.py +7 -15
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +147 -351
- edsl/agents/AgentList.py +73 -211
- edsl/agents/Invigilator.py +50 -101
- edsl/agents/InvigilatorBase.py +70 -62
- edsl/agents/PromptConstructor.py +225 -143
- edsl/agents/__init__.py +1 -0
- edsl/agents/prompt_helpers.py +3 -3
- edsl/auto/AutoStudy.py +5 -18
- edsl/auto/StageBase.py +40 -53
- edsl/auto/StageQuestions.py +1 -2
- edsl/auto/utilities.py +6 -0
- edsl/config.py +2 -22
- edsl/conversation/car_buying.py +1 -2
- edsl/coop/PriceFetcher.py +1 -1
- edsl/coop/coop.py +47 -125
- edsl/coop/utils.py +14 -14
- edsl/data/Cache.py +27 -45
- edsl/data/CacheEntry.py +15 -12
- edsl/data/CacheHandler.py +12 -31
- edsl/data/RemoteCacheSync.py +46 -154
- edsl/data/__init__.py +3 -4
- edsl/data_transfer_models.py +1 -2
- edsl/enums.py +0 -27
- edsl/exceptions/__init__.py +50 -50
- edsl/exceptions/agents.py +0 -12
- edsl/exceptions/questions.py +6 -24
- edsl/exceptions/scenarios.py +0 -7
- edsl/inference_services/AnthropicService.py +19 -38
- edsl/inference_services/AwsBedrock.py +2 -0
- edsl/inference_services/AzureAI.py +2 -0
- edsl/inference_services/GoogleService.py +12 -7
- edsl/inference_services/InferenceServiceABC.py +85 -18
- edsl/inference_services/InferenceServicesCollection.py +79 -120
- edsl/inference_services/MistralAIService.py +3 -0
- edsl/inference_services/OpenAIService.py +35 -47
- edsl/inference_services/PerplexityService.py +3 -0
- edsl/inference_services/TestService.py +10 -11
- edsl/inference_services/TogetherAIService.py +3 -5
- edsl/jobs/Answers.py +14 -1
- edsl/jobs/Jobs.py +431 -356
- edsl/jobs/JobsChecks.py +10 -35
- edsl/jobs/JobsPrompts.py +4 -6
- edsl/jobs/JobsRemoteInferenceHandler.py +133 -205
- edsl/jobs/buckets/BucketCollection.py +3 -44
- edsl/jobs/buckets/TokenBucket.py +21 -53
- edsl/jobs/interviews/Interview.py +408 -143
- edsl/jobs/runners/JobsRunnerAsyncio.py +403 -88
- edsl/jobs/runners/JobsRunnerStatus.py +165 -133
- edsl/jobs/tasks/QuestionTaskCreator.py +19 -21
- edsl/jobs/tasks/TaskHistory.py +18 -38
- edsl/jobs/tasks/task_status_enum.py +2 -0
- edsl/language_models/KeyLookup.py +30 -0
- edsl/language_models/LanguageModel.py +236 -194
- edsl/language_models/ModelList.py +19 -28
- edsl/language_models/__init__.py +2 -1
- edsl/language_models/registry.py +190 -0
- edsl/language_models/repair.py +2 -2
- edsl/language_models/unused/ReplicateBase.py +83 -0
- edsl/language_models/utilities.py +4 -5
- edsl/notebooks/Notebook.py +14 -19
- edsl/prompts/Prompt.py +39 -29
- edsl/questions/{answer_validator_mixin.py → AnswerValidatorMixin.py} +2 -47
- edsl/questions/QuestionBase.py +214 -68
- edsl/questions/{question_base_gen_mixin.py → QuestionBaseGenMixin.py} +50 -57
- edsl/questions/QuestionBasePromptsMixin.py +3 -7
- edsl/questions/QuestionBudget.py +1 -1
- edsl/questions/QuestionCheckBox.py +3 -3
- edsl/questions/QuestionExtract.py +7 -5
- edsl/questions/QuestionFreeText.py +3 -2
- edsl/questions/QuestionList.py +18 -10
- edsl/questions/QuestionMultipleChoice.py +23 -67
- edsl/questions/QuestionNumerical.py +4 -2
- edsl/questions/QuestionRank.py +17 -7
- edsl/questions/{response_validator_abc.py → ResponseValidatorABC.py} +26 -40
- edsl/questions/SimpleAskMixin.py +3 -4
- edsl/questions/__init__.py +1 -2
- edsl/questions/derived/QuestionLinearScale.py +3 -6
- edsl/questions/derived/QuestionTopK.py +1 -1
- edsl/questions/descriptors.py +3 -17
- edsl/questions/question_registry.py +1 -1
- edsl/results/CSSParameterizer.py +1 -1
- edsl/results/Dataset.py +7 -170
- edsl/results/DatasetExportMixin.py +305 -168
- edsl/results/DatasetTree.py +8 -28
- edsl/results/Result.py +206 -298
- edsl/results/Results.py +131 -149
- edsl/results/ResultsDBMixin.py +238 -0
- edsl/results/ResultsExportMixin.py +0 -2
- edsl/results/{results_selector.py → Selector.py} +13 -23
- edsl/results/TableDisplay.py +171 -98
- edsl/results/__init__.py +1 -1
- edsl/scenarios/FileStore.py +239 -150
- edsl/scenarios/Scenario.py +193 -90
- edsl/scenarios/ScenarioHtmlMixin.py +3 -4
- edsl/scenarios/{scenario_join.py → ScenarioJoin.py} +6 -10
- edsl/scenarios/ScenarioList.py +244 -415
- edsl/scenarios/ScenarioListExportMixin.py +7 -0
- edsl/scenarios/ScenarioListPdfMixin.py +37 -15
- edsl/scenarios/__init__.py +2 -1
- edsl/study/ObjectEntry.py +1 -1
- edsl/study/SnapShot.py +1 -1
- edsl/study/Study.py +12 -5
- edsl/surveys/Rule.py +4 -5
- edsl/surveys/RuleCollection.py +27 -25
- edsl/surveys/Survey.py +791 -270
- edsl/surveys/SurveyCSS.py +8 -20
- edsl/surveys/{SurveyFlowVisualization.py → SurveyFlowVisualizationMixin.py} +9 -11
- edsl/surveys/__init__.py +2 -4
- edsl/surveys/descriptors.py +2 -6
- edsl/surveys/instructions/ChangeInstruction.py +2 -1
- edsl/surveys/instructions/Instruction.py +13 -4
- edsl/surveys/instructions/InstructionCollection.py +6 -11
- edsl/templates/error_reporting/interview_details.html +1 -1
- edsl/templates/error_reporting/report.html +1 -1
- edsl/tools/plotting.py +1 -1
- edsl/utilities/utilities.py +23 -35
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/METADATA +10 -12
- edsl-0.1.39.dev1.dist-info/RECORD +277 -0
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/WHEEL +1 -1
- edsl/agents/QuestionInstructionPromptBuilder.py +0 -128
- edsl/agents/QuestionTemplateReplacementsBuilder.py +0 -137
- edsl/agents/question_option_processor.py +0 -172
- edsl/coop/CoopFunctionsMixin.py +0 -15
- edsl/coop/ExpectedParrotKeyHandler.py +0 -125
- edsl/exceptions/inference_services.py +0 -5
- edsl/inference_services/AvailableModelCacheHandler.py +0 -184
- edsl/inference_services/AvailableModelFetcher.py +0 -215
- edsl/inference_services/ServiceAvailability.py +0 -135
- edsl/inference_services/data_structures.py +0 -134
- edsl/jobs/AnswerQuestionFunctionConstructor.py +0 -223
- edsl/jobs/FetchInvigilator.py +0 -47
- edsl/jobs/InterviewTaskManager.py +0 -98
- edsl/jobs/InterviewsConstructor.py +0 -50
- edsl/jobs/JobsComponentConstructor.py +0 -189
- edsl/jobs/JobsRemoteInferenceLogger.py +0 -239
- edsl/jobs/RequestTokenEstimator.py +0 -30
- edsl/jobs/async_interview_runner.py +0 -138
- edsl/jobs/buckets/TokenBucketAPI.py +0 -211
- edsl/jobs/buckets/TokenBucketClient.py +0 -191
- edsl/jobs/check_survey_scenario_compatibility.py +0 -85
- edsl/jobs/data_structures.py +0 -120
- edsl/jobs/decorators.py +0 -35
- edsl/jobs/jobs_status_enums.py +0 -9
- edsl/jobs/loggers/HTMLTableJobLogger.py +0 -304
- edsl/jobs/results_exceptions_handler.py +0 -98
- edsl/language_models/ComputeCost.py +0 -63
- edsl/language_models/PriceManager.py +0 -127
- edsl/language_models/RawResponseHandler.py +0 -106
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/key_management/KeyLookup.py +0 -63
- edsl/language_models/key_management/KeyLookupBuilder.py +0 -273
- edsl/language_models/key_management/KeyLookupCollection.py +0 -38
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +0 -131
- edsl/language_models/model.py +0 -256
- edsl/notebooks/NotebookToLaTeX.py +0 -142
- edsl/questions/ExceptionExplainer.py +0 -77
- edsl/questions/HTMLQuestion.py +0 -103
- edsl/questions/QuestionMatrix.py +0 -265
- edsl/questions/data_structures.py +0 -20
- edsl/questions/loop_processor.py +0 -149
- edsl/questions/response_validator_factory.py +0 -34
- edsl/questions/templates/matrix/__init__.py +0 -1
- edsl/questions/templates/matrix/answering_instructions.jinja +0 -5
- edsl/questions/templates/matrix/question_presentation.jinja +0 -20
- edsl/results/MarkdownToDocx.py +0 -122
- edsl/results/MarkdownToPDF.py +0 -111
- edsl/results/TextEditor.py +0 -50
- edsl/results/file_exports.py +0 -252
- edsl/results/smart_objects.py +0 -96
- edsl/results/table_data_class.py +0 -12
- edsl/results/table_renderers.py +0 -118
- edsl/scenarios/ConstructDownloadLink.py +0 -109
- edsl/scenarios/DocumentChunker.py +0 -102
- edsl/scenarios/DocxScenario.py +0 -16
- edsl/scenarios/PdfExtractor.py +0 -40
- edsl/scenarios/directory_scanner.py +0 -96
- edsl/scenarios/file_methods.py +0 -85
- edsl/scenarios/handlers/__init__.py +0 -13
- edsl/scenarios/handlers/csv.py +0 -49
- edsl/scenarios/handlers/docx.py +0 -76
- edsl/scenarios/handlers/html.py +0 -37
- edsl/scenarios/handlers/json.py +0 -111
- edsl/scenarios/handlers/latex.py +0 -5
- edsl/scenarios/handlers/md.py +0 -51
- edsl/scenarios/handlers/pdf.py +0 -68
- edsl/scenarios/handlers/png.py +0 -39
- edsl/scenarios/handlers/pptx.py +0 -105
- edsl/scenarios/handlers/py.py +0 -294
- edsl/scenarios/handlers/sql.py +0 -313
- edsl/scenarios/handlers/sqlite.py +0 -149
- edsl/scenarios/handlers/txt.py +0 -33
- edsl/scenarios/scenario_selector.py +0 -156
- edsl/surveys/ConstructDAG.py +0 -92
- edsl/surveys/EditSurvey.py +0 -221
- edsl/surveys/InstructionHandler.py +0 -100
- edsl/surveys/MemoryManagement.py +0 -72
- edsl/surveys/RuleManager.py +0 -172
- edsl/surveys/Simulator.py +0 -75
- edsl/surveys/SurveyToApp.py +0 -141
- edsl/utilities/PrettyList.py +0 -56
- edsl/utilities/is_notebook.py +0 -18
- edsl/utilities/is_valid_variable_name.py +0 -11
- edsl/utilities/remove_edsl_version.py +0 -24
- edsl-0.1.39.dist-info/RECORD +0 -358
- /edsl/questions/{register_questions_meta.py → RegisterQuestionsMeta.py} +0 -0
- /edsl/results/{results_fetch_mixin.py → ResultsFetchMixin.py} +0 -0
- /edsl/results/{results_tools_mixin.py → ResultsToolsMixin.py} +0 -0
- {edsl-0.1.39.dist-info → edsl-0.1.39.dev1.dist-info}/LICENSE +0 -0
edsl/results/Results.py
CHANGED
@@ -9,9 +9,13 @@ import random
|
|
9
9
|
from collections import UserList, defaultdict
|
10
10
|
from typing import Optional, Callable, Any, Type, Union, List, TYPE_CHECKING
|
11
11
|
|
12
|
-
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from edsl import Survey, Cache, AgentList, ModelList, ScenarioList
|
14
|
+
from edsl.results.Result import Result
|
15
|
+
from edsl.jobs.tasks.TaskHistory import TaskHistory
|
16
|
+
|
17
|
+
from simpleeval import EvalWithCompoundTypes
|
13
18
|
|
14
|
-
from edsl.Base import Base
|
15
19
|
from edsl.exceptions.results import (
|
16
20
|
ResultsError,
|
17
21
|
ResultsBadMutationstringError,
|
@@ -22,27 +26,25 @@ from edsl.exceptions.results import (
|
|
22
26
|
ResultsDeserializationError,
|
23
27
|
)
|
24
28
|
|
25
|
-
if TYPE_CHECKING:
|
26
|
-
from edsl.surveys.Survey import Survey
|
27
|
-
from edsl.data.Cache import Cache
|
28
|
-
from edsl.agents.AgentList import AgentList
|
29
|
-
from edsl.language_models.model import Model
|
30
|
-
from edsl.scenarios.ScenarioList import ScenarioList
|
31
|
-
from edsl.results.Result import Result
|
32
|
-
from edsl.jobs.tasks.TaskHistory import TaskHistory
|
33
|
-
from edsl.language_models.ModelList import ModelList
|
34
|
-
from simpleeval import EvalWithCompoundTypes
|
35
|
-
|
36
29
|
from edsl.results.ResultsExportMixin import ResultsExportMixin
|
30
|
+
from edsl.results.ResultsToolsMixin import ResultsToolsMixin
|
31
|
+
from edsl.results.ResultsDBMixin import ResultsDBMixin
|
37
32
|
from edsl.results.ResultsGGMixin import ResultsGGMixin
|
38
|
-
from edsl.results.
|
39
|
-
|
33
|
+
from edsl.results.ResultsFetchMixin import ResultsFetchMixin
|
34
|
+
|
35
|
+
from edsl.utilities.decorators import remove_edsl_version
|
36
|
+
from edsl.utilities.utilities import dict_hash
|
37
|
+
|
38
|
+
|
39
|
+
from edsl.Base import Base
|
40
40
|
|
41
41
|
|
42
42
|
class Mixins(
|
43
43
|
ResultsExportMixin,
|
44
|
+
ResultsDBMixin,
|
44
45
|
ResultsFetchMixin,
|
45
46
|
ResultsGGMixin,
|
47
|
+
ResultsToolsMixin,
|
46
48
|
):
|
47
49
|
def long(self):
|
48
50
|
return self.table().long()
|
@@ -89,7 +91,6 @@ class Results(UserList, Mixins, Base):
|
|
89
91
|
"question_type",
|
90
92
|
"comment",
|
91
93
|
"generated_tokens",
|
92
|
-
"cache_used",
|
93
94
|
]
|
94
95
|
|
95
96
|
def __init__(
|
@@ -128,43 +129,22 @@ class Results(UserList, Mixins, Base):
|
|
128
129
|
def _summary(self) -> dict:
|
129
130
|
import reprlib
|
130
131
|
|
132
|
+
# import yaml
|
133
|
+
|
131
134
|
d = {
|
132
|
-
"
|
133
|
-
"
|
134
|
-
"
|
135
|
-
"
|
136
|
-
"
|
135
|
+
"EDSL Class": "Results",
|
136
|
+
# "docs_url": self.__documentation__,
|
137
|
+
"# of agents": len(set(self.agents)),
|
138
|
+
"# of distinct models": len(set(self.models)),
|
139
|
+
"# of observations": len(self),
|
140
|
+
"# Scenarios": len(set(self.scenarios)),
|
141
|
+
"Survey Length (# questions)": len(self.survey),
|
137
142
|
"Survey question names": reprlib.repr(self.survey.question_names),
|
143
|
+
"Object hash": hash(self),
|
138
144
|
}
|
139
145
|
return d
|
140
146
|
|
141
|
-
def
|
142
|
-
item_order = getattr(item, "order", None)
|
143
|
-
if item_order is not None:
|
144
|
-
# Get list of orders, putting None at the end
|
145
|
-
orders = [getattr(x, "order", None) for x in self]
|
146
|
-
# Filter to just the non-None orders for bisect
|
147
|
-
sorted_orders = [x for x in orders if x is not None]
|
148
|
-
if sorted_orders:
|
149
|
-
index = bisect_left(sorted_orders, item_order)
|
150
|
-
# Account for any None values before this position
|
151
|
-
index += orders[:index].count(None)
|
152
|
-
else:
|
153
|
-
# If no sorted items yet, insert before any unordered items
|
154
|
-
index = 0
|
155
|
-
self.data.insert(index, item)
|
156
|
-
else:
|
157
|
-
# No order - append to end
|
158
|
-
self.data.append(item)
|
159
|
-
|
160
|
-
def append(self, item):
|
161
|
-
self.insert(item)
|
162
|
-
|
163
|
-
def extend(self, other):
|
164
|
-
for item in other:
|
165
|
-
self.insert(item)
|
166
|
-
|
167
|
-
def compute_job_cost(self, include_cached_responses_in_cost: bool = False) -> float:
|
147
|
+
def compute_job_cost(self, include_cached_responses_in_cost=False) -> float:
|
168
148
|
"""
|
169
149
|
Computes the cost of a completed job in USD.
|
170
150
|
"""
|
@@ -278,6 +258,24 @@ class Results(UserList, Mixins, Base):
|
|
278
258
|
|
279
259
|
raise TypeError("Invalid argument type")
|
280
260
|
|
261
|
+
def _update_results(self) -> None:
|
262
|
+
from edsl import Agent, Scenario
|
263
|
+
from edsl.language_models import LanguageModel
|
264
|
+
from edsl.results import Result
|
265
|
+
|
266
|
+
if self._job_uuid and len(self.data) < self._total_results:
|
267
|
+
results = [
|
268
|
+
Result(
|
269
|
+
agent=Agent.from_dict(json.loads(r.agent)),
|
270
|
+
scenario=Scenario.from_dict(json.loads(r.scenario)),
|
271
|
+
model=LanguageModel.from_dict(json.loads(r.model)),
|
272
|
+
iteration=1,
|
273
|
+
answer=json.loads(r.answer),
|
274
|
+
)
|
275
|
+
for r in CRUD.read_results(self._job_uuid)
|
276
|
+
]
|
277
|
+
self.data = results
|
278
|
+
|
281
279
|
def __add__(self, other: Results) -> Results:
|
282
280
|
"""Add two Results objects together.
|
283
281
|
They must have the same survey and created columns.
|
@@ -305,10 +303,13 @@ class Results(UserList, Mixins, Base):
|
|
305
303
|
)
|
306
304
|
|
307
305
|
def __repr__(self) -> str:
|
308
|
-
|
306
|
+
import reprlib
|
307
|
+
|
308
|
+
return f"Results(data = {reprlib.repr(self.data)}, survey = {repr(self.survey)}, created_columns = {self.created_columns})"
|
309
309
|
|
310
310
|
def table(
|
311
311
|
self,
|
312
|
+
# selector_string: Optional[str] = "*.*",
|
312
313
|
*fields,
|
313
314
|
tablefmt: Optional[str] = None,
|
314
315
|
pretty_labels: Optional[dict] = None,
|
@@ -344,14 +345,28 @@ class Results(UserList, Mixins, Base):
|
|
344
345
|
print_parameters=print_parameters,
|
345
346
|
)
|
346
347
|
)
|
348
|
+
# return (
|
349
|
+
# self.select(f"{selector_string}")
|
350
|
+
# .to_scenario_list()
|
351
|
+
# .table(*fields, tablefmt=tablefmt)
|
352
|
+
# )
|
353
|
+
|
354
|
+
def _repr_html_(self) -> str:
|
355
|
+
d = self._summary()
|
356
|
+
from edsl import Scenario
|
357
|
+
|
358
|
+
footer = f"<a href={self.__documentation__}>(docs)</a>"
|
359
|
+
|
360
|
+
s = Scenario(d)
|
361
|
+
td = s.to_dataset().table(tablefmt="html")
|
362
|
+
return td._repr_html_() + footer
|
347
363
|
|
348
364
|
def to_dict(
|
349
365
|
self,
|
350
|
-
sort
|
351
|
-
add_edsl_version
|
352
|
-
include_cache
|
353
|
-
include_task_history
|
354
|
-
include_cache_info: bool = True,
|
366
|
+
sort=False,
|
367
|
+
add_edsl_version=False,
|
368
|
+
include_cache=False,
|
369
|
+
include_task_history=False,
|
355
370
|
) -> dict[str, Any]:
|
356
371
|
from edsl.data.Cache import Cache
|
357
372
|
|
@@ -362,11 +377,7 @@ class Results(UserList, Mixins, Base):
|
|
362
377
|
|
363
378
|
d = {
|
364
379
|
"data": [
|
365
|
-
result.to_dict(
|
366
|
-
add_edsl_version=add_edsl_version,
|
367
|
-
include_cache_info=include_cache_info,
|
368
|
-
)
|
369
|
-
for result in data
|
380
|
+
result.to_dict(add_edsl_version=add_edsl_version) for result in data
|
370
381
|
],
|
371
382
|
"survey": self.survey.to_dict(add_edsl_version=add_edsl_version),
|
372
383
|
"created_columns": self.created_columns,
|
@@ -393,7 +404,7 @@ class Results(UserList, Mixins, Base):
|
|
393
404
|
|
394
405
|
return d
|
395
406
|
|
396
|
-
def compare(self, other_results
|
407
|
+
def compare(self, other_results):
|
397
408
|
"""
|
398
409
|
Compare two Results objects and return the differences.
|
399
410
|
"""
|
@@ -411,15 +422,11 @@ class Results(UserList, Mixins, Base):
|
|
411
422
|
}
|
412
423
|
|
413
424
|
@property
|
414
|
-
def has_unfixed_exceptions(self)
|
425
|
+
def has_unfixed_exceptions(self):
|
415
426
|
return self.task_history.has_unfixed_exceptions
|
416
427
|
|
417
428
|
def __hash__(self) -> int:
|
418
|
-
|
419
|
-
|
420
|
-
return dict_hash(
|
421
|
-
self.to_dict(sort=True, add_edsl_version=False, include_cache_info=False)
|
422
|
-
)
|
429
|
+
return dict_hash(self.to_dict(sort=True, add_edsl_version=False))
|
423
430
|
|
424
431
|
@property
|
425
432
|
def hashes(self) -> set:
|
@@ -465,35 +472,32 @@ class Results(UserList, Mixins, Base):
|
|
465
472
|
>>> r == r2
|
466
473
|
True
|
467
474
|
"""
|
468
|
-
from edsl
|
469
|
-
from edsl.data.Cache import Cache
|
475
|
+
from edsl import Survey, Cache
|
470
476
|
from edsl.results.Result import Result
|
471
477
|
from edsl.jobs.tasks.TaskHistory import TaskHistory
|
472
|
-
from edsl.agents.Agent import Agent
|
473
|
-
|
474
|
-
survey = Survey.from_dict(data["survey"])
|
475
|
-
results_data = [Result.from_dict(r) for r in data["data"]]
|
476
|
-
created_columns = data.get("created_columns", None)
|
477
|
-
cache = Cache.from_dict(data.get("cache")) if "cache" in data else Cache()
|
478
|
-
task_history = (
|
479
|
-
TaskHistory.from_dict(data.get("task_history"))
|
480
|
-
if "task_history" in data
|
481
|
-
else TaskHistory(interviews=[])
|
482
|
-
)
|
483
|
-
params = {
|
484
|
-
"survey": survey,
|
485
|
-
"data": results_data,
|
486
|
-
"created_columns": created_columns,
|
487
|
-
"cache": cache,
|
488
|
-
"task_history": task_history,
|
489
|
-
}
|
490
478
|
|
491
479
|
try:
|
492
|
-
results = cls(
|
480
|
+
results = cls(
|
481
|
+
survey=Survey.from_dict(data["survey"]),
|
482
|
+
data=[Result.from_dict(r) for r in data["data"]],
|
483
|
+
created_columns=data.get("created_columns", None),
|
484
|
+
cache=(
|
485
|
+
Cache.from_dict(data.get("cache")) if "cache" in data else Cache()
|
486
|
+
),
|
487
|
+
task_history=(
|
488
|
+
TaskHistory.from_dict(data.get("task_history"))
|
489
|
+
if "task_history" in data
|
490
|
+
else TaskHistory(interviews=[])
|
491
|
+
),
|
492
|
+
)
|
493
493
|
except Exception as e:
|
494
494
|
raise ResultsDeserializationError(f"Error in Results.from_dict: {e}")
|
495
495
|
return results
|
496
496
|
|
497
|
+
######################
|
498
|
+
## Convenience methods
|
499
|
+
## & Report methods
|
500
|
+
######################
|
497
501
|
@property
|
498
502
|
def _key_to_data_type(self) -> dict[str, str]:
|
499
503
|
"""
|
@@ -540,12 +544,10 @@ class Results(UserList, Mixins, Base):
|
|
540
544
|
|
541
545
|
>>> r = Results.example()
|
542
546
|
>>> r.columns
|
543
|
-
['agent.
|
547
|
+
['agent.agent_instruction', ...]
|
544
548
|
"""
|
545
549
|
column_names = [f"{v}.{k}" for k, v in self._key_to_data_type.items()]
|
546
|
-
|
547
|
-
|
548
|
-
return PrettyList(sorted(column_names))
|
550
|
+
return sorted(column_names)
|
549
551
|
|
550
552
|
@property
|
551
553
|
def answer_keys(self) -> dict[str, str]:
|
@@ -565,7 +567,7 @@ class Results(UserList, Mixins, Base):
|
|
565
567
|
answer_keys = self._data_type_to_keys["answer"]
|
566
568
|
answer_keys = {k for k in answer_keys if "_comment" not in k}
|
567
569
|
questions_text = [
|
568
|
-
self.survey.
|
570
|
+
self.survey.get_question(k).question_text for k in answer_keys
|
569
571
|
]
|
570
572
|
short_question_text = [shorten_string(q, 80) for q in questions_text]
|
571
573
|
initial_dict = dict(zip(answer_keys, short_question_text))
|
@@ -582,7 +584,7 @@ class Results(UserList, Mixins, Base):
|
|
582
584
|
>>> r.agents
|
583
585
|
AgentList([Agent(traits = {'status': 'Joyful'}), Agent(traits = {'status': 'Joyful'}), Agent(traits = {'status': 'Sad'}), Agent(traits = {'status': 'Sad'})])
|
584
586
|
"""
|
585
|
-
from edsl
|
587
|
+
from edsl import AgentList
|
586
588
|
|
587
589
|
return AgentList([r.agent for r in self.data])
|
588
590
|
|
@@ -596,13 +598,10 @@ class Results(UserList, Mixins, Base):
|
|
596
598
|
>>> r.models[0]
|
597
599
|
Model(model_name = ...)
|
598
600
|
"""
|
599
|
-
from edsl
|
601
|
+
from edsl import ModelList
|
600
602
|
|
601
603
|
return ModelList([r.model for r in self.data])
|
602
604
|
|
603
|
-
def __eq__(self, other):
|
604
|
-
return hash(self) == hash(other)
|
605
|
-
|
606
605
|
@property
|
607
606
|
def scenarios(self) -> ScenarioList:
|
608
607
|
"""Return a list of all of the scenarios in the Results.
|
@@ -611,9 +610,9 @@ class Results(UserList, Mixins, Base):
|
|
611
610
|
|
612
611
|
>>> r = Results.example()
|
613
612
|
>>> r.scenarios
|
614
|
-
ScenarioList([Scenario({'period': 'morning'
|
613
|
+
ScenarioList([Scenario({'period': 'morning'}), Scenario({'period': 'afternoon'}), Scenario({'period': 'morning'}), Scenario({'period': 'afternoon'})])
|
615
614
|
"""
|
616
|
-
from edsl
|
615
|
+
from edsl import ScenarioList
|
617
616
|
|
618
617
|
return ScenarioList([r.scenario for r in self.data])
|
619
618
|
|
@@ -625,7 +624,7 @@ class Results(UserList, Mixins, Base):
|
|
625
624
|
|
626
625
|
>>> r = Results.example()
|
627
626
|
>>> r.agent_keys
|
628
|
-
['
|
627
|
+
['agent_instruction', 'agent_name', 'status']
|
629
628
|
"""
|
630
629
|
return sorted(self._data_type_to_keys["agent"])
|
631
630
|
|
@@ -635,7 +634,7 @@ class Results(UserList, Mixins, Base):
|
|
635
634
|
|
636
635
|
>>> r = Results.example()
|
637
636
|
>>> r.model_keys
|
638
|
-
['frequency_penalty', 'logprobs', 'max_tokens', 'model', '
|
637
|
+
['frequency_penalty', 'logprobs', 'max_tokens', 'model', 'presence_penalty', 'temperature', 'top_logprobs', 'top_p']
|
639
638
|
"""
|
640
639
|
return sorted(self._data_type_to_keys["model"])
|
641
640
|
|
@@ -645,7 +644,7 @@ class Results(UserList, Mixins, Base):
|
|
645
644
|
|
646
645
|
>>> r = Results.example()
|
647
646
|
>>> r.scenario_keys
|
648
|
-
['period'
|
647
|
+
['period']
|
649
648
|
"""
|
650
649
|
return sorted(self._data_type_to_keys["scenario"])
|
651
650
|
|
@@ -671,7 +670,7 @@ class Results(UserList, Mixins, Base):
|
|
671
670
|
|
672
671
|
>>> r = Results.example()
|
673
672
|
>>> r.all_keys
|
674
|
-
['
|
673
|
+
['agent_instruction', 'agent_name', 'frequency_penalty', 'how_feeling', 'how_feeling_yesterday', 'logprobs', 'max_tokens', 'model', 'period', 'presence_penalty', 'status', 'temperature', 'top_logprobs', 'top_p']
|
675
674
|
"""
|
676
675
|
answer_keys = set(self.answer_keys)
|
677
676
|
all_keys = (
|
@@ -692,19 +691,13 @@ class Results(UserList, Mixins, Base):
|
|
692
691
|
"""
|
693
692
|
return self.data[0]
|
694
693
|
|
695
|
-
def answer_truncate(
|
696
|
-
self, column: str, top_n: int = 5, new_var_name: str = None
|
697
|
-
) -> Results:
|
694
|
+
def answer_truncate(self, column: str, top_n=5, new_var_name=None) -> Results:
|
698
695
|
"""Create a new variable that truncates the answers to the top_n.
|
699
696
|
|
700
697
|
:param column: The column to truncate.
|
701
698
|
:param top_n: The number of top answers to keep.
|
702
699
|
:param new_var_name: The name of the new variable. If None, it is the original name + '_truncated'.
|
703
700
|
|
704
|
-
Example:
|
705
|
-
>>> r = Results.example()
|
706
|
-
>>> r.answer_truncate('how_feeling', top_n = 2).select('how_feeling', 'how_feeling_truncated')
|
707
|
-
Dataset([{'answer.how_feeling': ['OK', 'Great', 'Terrible', 'OK']}, {'answer.how_feeling_truncated': ['Other', 'Other', 'Other', 'Other']}])
|
708
701
|
|
709
702
|
|
710
703
|
"""
|
@@ -784,7 +777,7 @@ class Results(UserList, Mixins, Base):
|
|
784
777
|
@staticmethod
|
785
778
|
def _create_evaluator(
|
786
779
|
result: Result, functions_dict: Optional[dict] = None
|
787
|
-
) ->
|
780
|
+
) -> EvalWithCompoundTypes:
|
788
781
|
"""Create an evaluator for the expression.
|
789
782
|
|
790
783
|
>>> from unittest.mock import Mock
|
@@ -807,8 +800,6 @@ class Results(UserList, Mixins, Base):
|
|
807
800
|
...
|
808
801
|
simpleeval.NameNotDefined: 'how_feeling' is not defined for expression 'how_feeling== 'OK''
|
809
802
|
"""
|
810
|
-
from simpleeval import EvalWithCompoundTypes
|
811
|
-
|
812
803
|
if functions_dict is None:
|
813
804
|
functions_dict = {}
|
814
805
|
evaluator = EvalWithCompoundTypes(
|
@@ -867,26 +858,6 @@ class Results(UserList, Mixins, Base):
|
|
867
858
|
created_columns=self.created_columns + [var_name],
|
868
859
|
)
|
869
860
|
|
870
|
-
def add_column(self, column_name: str, values: list) -> Results:
|
871
|
-
"""Adds columns to Results
|
872
|
-
|
873
|
-
>>> r = Results.example()
|
874
|
-
>>> r.add_column('a', [1,2,3, 4]).select('a')
|
875
|
-
Dataset([{'answer.a': [1, 2, 3, 4]}])
|
876
|
-
"""
|
877
|
-
|
878
|
-
assert len(values) == len(
|
879
|
-
self.data
|
880
|
-
), "The number of values must match the number of results."
|
881
|
-
new_results = self.data.copy()
|
882
|
-
for i, result in enumerate(new_results):
|
883
|
-
result["answer"][column_name] = values[i]
|
884
|
-
return Results(
|
885
|
-
survey=self.survey,
|
886
|
-
data=new_results,
|
887
|
-
created_columns=self.created_columns + [column_name],
|
888
|
-
)
|
889
|
-
|
890
861
|
def rename(self, old_name: str, new_name: str) -> Results:
|
891
862
|
"""Rename an answer column in a Results object.
|
892
863
|
|
@@ -925,7 +896,7 @@ class Results(UserList, Mixins, Base):
|
|
925
896
|
n: Optional[int] = None,
|
926
897
|
frac: Optional[float] = None,
|
927
898
|
with_replacement: bool = True,
|
928
|
-
seed: Optional[str] =
|
899
|
+
seed: Optional[str] = "edsl",
|
929
900
|
) -> Results:
|
930
901
|
"""Sample the results.
|
931
902
|
|
@@ -940,7 +911,7 @@ class Results(UserList, Mixins, Base):
|
|
940
911
|
>>> len(r.sample(2))
|
941
912
|
2
|
942
913
|
"""
|
943
|
-
if seed:
|
914
|
+
if seed != "edsl":
|
944
915
|
random.seed(seed)
|
945
916
|
|
946
917
|
if n is None and frac is None:
|
@@ -978,7 +949,7 @@ class Results(UserList, Mixins, Base):
|
|
978
949
|
Dataset([{'answer.how_feeling_yesterday': ['Great', 'Good', 'OK', 'Terrible']}])
|
979
950
|
"""
|
980
951
|
|
981
|
-
from edsl.results.
|
952
|
+
from edsl.results.Selector import Selector
|
982
953
|
|
983
954
|
if len(self) == 0:
|
984
955
|
raise Exception("No data to select from---the Results object is empty.")
|
@@ -993,7 +964,6 @@ class Results(UserList, Mixins, Base):
|
|
993
964
|
return selector.select(*columns)
|
994
965
|
|
995
966
|
def sort_by(self, *columns: str, reverse: bool = False) -> Results:
|
996
|
-
"""Sort the results by one or more columns."""
|
997
967
|
import warnings
|
998
968
|
|
999
969
|
warnings.warn(
|
@@ -1002,7 +972,6 @@ class Results(UserList, Mixins, Base):
|
|
1002
972
|
return self.order_by(*columns, reverse=reverse)
|
1003
973
|
|
1004
974
|
def _parse_column(self, column: str) -> tuple[str, str]:
|
1005
|
-
"""Parse a column name into a data type and key."""
|
1006
975
|
if "." in column:
|
1007
976
|
return column.split(".")
|
1008
977
|
return self._key_to_data_type[column], column
|
@@ -1018,12 +987,20 @@ class Results(UserList, Mixins, Base):
|
|
1018
987
|
Example:
|
1019
988
|
|
1020
989
|
>>> r = Results.example()
|
1021
|
-
>>> r.sort_by('how_feeling', reverse=False).select('how_feeling')
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
990
|
+
>>> r.sort_by('how_feeling', reverse=False).select('how_feeling').print()
|
991
|
+
answer.how_feeling
|
992
|
+
--------------------
|
993
|
+
Great
|
994
|
+
OK
|
995
|
+
OK
|
996
|
+
Terrible
|
997
|
+
>>> r.sort_by('how_feeling', reverse=True).select('how_feeling').print()
|
998
|
+
answer.how_feeling
|
999
|
+
--------------------
|
1000
|
+
Terrible
|
1001
|
+
OK
|
1002
|
+
OK
|
1003
|
+
Great
|
1027
1004
|
"""
|
1028
1005
|
|
1029
1006
|
def to_numeric_if_possible(v):
|
@@ -1055,19 +1032,24 @@ class Results(UserList, Mixins, Base):
|
|
1055
1032
|
Example usage: Create an example `Results` instance and apply filters to it:
|
1056
1033
|
|
1057
1034
|
>>> r = Results.example()
|
1058
|
-
>>> r.filter("how_feeling == 'Great'").select('how_feeling')
|
1059
|
-
|
1035
|
+
>>> r.filter("how_feeling == 'Great'").select('how_feeling').print()
|
1036
|
+
answer.how_feeling
|
1037
|
+
--------------------
|
1038
|
+
Great
|
1060
1039
|
|
1061
1040
|
Example usage: Using an OR operator in the filter expression.
|
1062
1041
|
|
1063
|
-
>>> r = Results.example().filter("how_feeling = 'Great'").select('how_feeling')
|
1042
|
+
>>> r = Results.example().filter("how_feeling = 'Great'").select('how_feeling').print()
|
1064
1043
|
Traceback (most recent call last):
|
1065
1044
|
...
|
1066
1045
|
edsl.exceptions.results.ResultsFilterError: You must use '==' instead of '=' in the filter expression.
|
1067
1046
|
...
|
1068
1047
|
|
1069
|
-
>>> r.filter("how_feeling == 'Great' or how_feeling == 'Terrible'").select('how_feeling')
|
1070
|
-
|
1048
|
+
>>> r.filter("how_feeling == 'Great' or how_feeling == 'Terrible'").select('how_feeling').print()
|
1049
|
+
answer.how_feeling
|
1050
|
+
--------------------
|
1051
|
+
Great
|
1052
|
+
Terrible
|
1071
1053
|
"""
|
1072
1054
|
|
1073
1055
|
def has_single_equals(string):
|