edsl 0.1.31.dev4__py3-none-any.whl → 0.1.33__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 +9 -3
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +8 -3
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +40 -8
- edsl/agents/AgentList.py +43 -0
- edsl/agents/Invigilator.py +136 -221
- edsl/agents/InvigilatorBase.py +148 -59
- edsl/agents/{PromptConstructionMixin.py → PromptConstructor.py} +154 -85
- edsl/agents/__init__.py +1 -0
- edsl/auto/AutoStudy.py +117 -0
- edsl/auto/StageBase.py +230 -0
- edsl/auto/StageGenerateSurvey.py +178 -0
- edsl/auto/StageLabelQuestions.py +125 -0
- edsl/auto/StagePersona.py +61 -0
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
- edsl/auto/StagePersonaDimensionValues.py +74 -0
- edsl/auto/StagePersonaDimensions.py +69 -0
- edsl/auto/StageQuestions.py +73 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +224 -0
- edsl/config.py +48 -47
- edsl/conjure/Conjure.py +6 -0
- edsl/coop/PriceFetcher.py +58 -0
- edsl/coop/coop.py +50 -7
- edsl/data/Cache.py +35 -1
- edsl/data/CacheHandler.py +3 -4
- edsl/data_transfer_models.py +73 -38
- edsl/enums.py +8 -0
- edsl/exceptions/general.py +10 -8
- edsl/exceptions/language_models.py +25 -1
- edsl/exceptions/questions.py +62 -5
- edsl/exceptions/results.py +4 -0
- edsl/inference_services/AnthropicService.py +13 -11
- edsl/inference_services/AwsBedrock.py +112 -0
- edsl/inference_services/AzureAI.py +214 -0
- edsl/inference_services/DeepInfraService.py +4 -3
- edsl/inference_services/GoogleService.py +16 -12
- edsl/inference_services/GroqService.py +5 -4
- edsl/inference_services/InferenceServiceABC.py +58 -3
- edsl/inference_services/InferenceServicesCollection.py +13 -8
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +55 -56
- edsl/inference_services/TestService.py +80 -0
- edsl/inference_services/TogetherAIService.py +170 -0
- edsl/inference_services/models_available_cache.py +25 -0
- edsl/inference_services/registry.py +19 -1
- edsl/jobs/Answers.py +10 -12
- edsl/jobs/FailedQuestion.py +78 -0
- edsl/jobs/Jobs.py +137 -41
- edsl/jobs/buckets/BucketCollection.py +24 -15
- edsl/jobs/buckets/TokenBucket.py +105 -18
- edsl/jobs/interviews/Interview.py +393 -83
- edsl/jobs/interviews/{interview_exception_tracking.py → InterviewExceptionCollection.py} +22 -18
- edsl/jobs/interviews/InterviewExceptionEntry.py +167 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +152 -160
- edsl/jobs/runners/JobsRunnerStatus.py +331 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +30 -23
- edsl/jobs/tasks/TaskCreators.py +1 -1
- edsl/jobs/tasks/TaskHistory.py +205 -126
- edsl/language_models/LanguageModel.py +297 -177
- edsl/language_models/ModelList.py +2 -2
- edsl/language_models/RegisterLanguageModelsMeta.py +14 -29
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- edsl/language_models/registry.py +25 -8
- edsl/language_models/repair.py +0 -19
- edsl/language_models/utilities.py +61 -0
- edsl/notebooks/Notebook.py +20 -2
- edsl/prompts/Prompt.py +52 -2
- edsl/questions/AnswerValidatorMixin.py +23 -26
- edsl/questions/QuestionBase.py +330 -249
- edsl/questions/QuestionBaseGenMixin.py +133 -0
- edsl/questions/QuestionBasePromptsMixin.py +266 -0
- edsl/questions/QuestionBudget.py +99 -42
- edsl/questions/QuestionCheckBox.py +227 -36
- edsl/questions/QuestionExtract.py +98 -28
- edsl/questions/QuestionFreeText.py +47 -31
- edsl/questions/QuestionFunctional.py +7 -0
- edsl/questions/QuestionList.py +141 -23
- edsl/questions/QuestionMultipleChoice.py +159 -66
- edsl/questions/QuestionNumerical.py +88 -47
- edsl/questions/QuestionRank.py +182 -25
- edsl/questions/Quick.py +41 -0
- edsl/questions/RegisterQuestionsMeta.py +31 -12
- edsl/questions/ResponseValidatorABC.py +170 -0
- edsl/questions/__init__.py +3 -4
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +10 -5
- edsl/questions/derived/QuestionLinearScale.py +15 -2
- edsl/questions/derived/QuestionTopK.py +10 -1
- edsl/questions/derived/QuestionYesNo.py +24 -3
- edsl/questions/descriptors.py +43 -7
- edsl/questions/prompt_templates/question_budget.jinja +13 -0
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
- edsl/questions/prompt_templates/question_extract.jinja +11 -0
- edsl/questions/prompt_templates/question_free_text.jinja +3 -0
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
- edsl/questions/prompt_templates/question_list.jinja +17 -0
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
- edsl/questions/prompt_templates/question_numerical.jinja +37 -0
- edsl/questions/question_registry.py +6 -2
- edsl/questions/templates/__init__.py +0 -0
- edsl/questions/templates/budget/__init__.py +0 -0
- edsl/questions/templates/budget/answering_instructions.jinja +7 -0
- edsl/questions/templates/budget/question_presentation.jinja +7 -0
- edsl/questions/templates/checkbox/__init__.py +0 -0
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
- edsl/questions/templates/extract/__init__.py +0 -0
- edsl/questions/templates/extract/answering_instructions.jinja +7 -0
- edsl/questions/templates/extract/question_presentation.jinja +1 -0
- edsl/questions/templates/free_text/__init__.py +0 -0
- edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
- edsl/questions/templates/free_text/question_presentation.jinja +1 -0
- edsl/questions/templates/likert_five/__init__.py +0 -0
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
- edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
- edsl/questions/templates/linear_scale/__init__.py +0 -0
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
- edsl/questions/templates/list/__init__.py +0 -0
- edsl/questions/templates/list/answering_instructions.jinja +4 -0
- edsl/questions/templates/list/question_presentation.jinja +5 -0
- edsl/questions/templates/multiple_choice/__init__.py +0 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
- edsl/questions/templates/multiple_choice/html.jinja +0 -0
- edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
- edsl/questions/templates/numerical/__init__.py +0 -0
- edsl/questions/templates/numerical/answering_instructions.jinja +8 -0
- edsl/questions/templates/numerical/question_presentation.jinja +7 -0
- edsl/questions/templates/rank/__init__.py +0 -0
- edsl/questions/templates/rank/answering_instructions.jinja +11 -0
- edsl/questions/templates/rank/question_presentation.jinja +15 -0
- edsl/questions/templates/top_k/__init__.py +0 -0
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
- edsl/questions/templates/top_k/question_presentation.jinja +22 -0
- edsl/questions/templates/yes_no/__init__.py +0 -0
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
- edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
- edsl/results/Dataset.py +20 -0
- edsl/results/DatasetExportMixin.py +58 -30
- edsl/results/DatasetTree.py +145 -0
- edsl/results/Result.py +32 -5
- edsl/results/Results.py +135 -46
- edsl/results/ResultsDBMixin.py +3 -3
- edsl/results/Selector.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/FileStore.py +71 -10
- edsl/scenarios/Scenario.py +109 -24
- edsl/scenarios/ScenarioImageMixin.py +2 -2
- edsl/scenarios/ScenarioList.py +546 -21
- edsl/scenarios/ScenarioListExportMixin.py +24 -4
- edsl/scenarios/ScenarioListPdfMixin.py +153 -4
- edsl/study/SnapShot.py +8 -1
- edsl/study/Study.py +32 -0
- edsl/surveys/Rule.py +15 -3
- edsl/surveys/RuleCollection.py +21 -5
- edsl/surveys/Survey.py +707 -298
- edsl/surveys/SurveyExportMixin.py +71 -9
- edsl/surveys/SurveyFlowVisualizationMixin.py +2 -1
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- edsl/surveys/instructions/ChangeInstruction.py +47 -0
- edsl/surveys/instructions/Instruction.py +34 -0
- edsl/surveys/instructions/InstructionCollection.py +77 -0
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/templates/error_reporting/base.html +24 -0
- edsl/templates/error_reporting/exceptions_by_model.html +35 -0
- edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
- edsl/templates/error_reporting/exceptions_by_type.html +17 -0
- edsl/templates/error_reporting/interview_details.html +116 -0
- edsl/templates/error_reporting/interviews.html +10 -0
- edsl/templates/error_reporting/overview.html +5 -0
- edsl/templates/error_reporting/performance_plot.html +2 -0
- edsl/templates/error_reporting/report.css +74 -0
- edsl/templates/error_reporting/report.html +118 -0
- edsl/templates/error_reporting/report.js +25 -0
- edsl/utilities/utilities.py +40 -1
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/METADATA +8 -2
- edsl-0.1.33.dist-info/RECORD +295 -0
- edsl/jobs/interviews/InterviewTaskBuildingMixin.py +0 -271
- edsl/jobs/interviews/retry_management.py +0 -37
- edsl/jobs/runners/JobsRunnerStatusMixin.py +0 -303
- edsl/utilities/gcp_bucket/simple_example.py +0 -9
- edsl-0.1.31.dev4.dist-info/RECORD +0 -204
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/LICENSE +0 -0
- {edsl-0.1.31.dev4.dist-info → edsl-0.1.33.dist-info}/WHEEL +0 -0
edsl/Base.py
CHANGED
@@ -47,21 +47,27 @@ class PersistenceMixin:
|
|
47
47
|
self,
|
48
48
|
description: Optional[str] = None,
|
49
49
|
visibility: Optional[str] = "unlisted",
|
50
|
+
expected_parrot_url: Optional[str] = None,
|
50
51
|
):
|
51
52
|
"""Post the object to coop."""
|
52
53
|
from edsl.coop import Coop
|
53
54
|
|
54
|
-
c = Coop()
|
55
|
+
c = Coop(url=expected_parrot_url)
|
55
56
|
return c.create(self, description, visibility)
|
56
57
|
|
57
58
|
@classmethod
|
58
|
-
def pull(
|
59
|
+
def pull(
|
60
|
+
cls,
|
61
|
+
uuid: Optional[Union[str, UUID]] = None,
|
62
|
+
url: Optional[str] = None,
|
63
|
+
expected_parrot_url: Optional[str] = None,
|
64
|
+
):
|
59
65
|
"""Pull the object from coop."""
|
60
66
|
from edsl.coop import Coop
|
61
67
|
from edsl.coop.utils import ObjectRegistry
|
62
68
|
|
63
69
|
object_type = ObjectRegistry.get_object_type_by_edsl_class(cls)
|
64
|
-
coop = Coop()
|
70
|
+
coop = Coop(url=expected_parrot_url)
|
65
71
|
return coop.get(uuid, url, object_type)
|
66
72
|
|
67
73
|
@classmethod
|
edsl/TemplateLoader.py
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
from importlib import resources
|
2
|
+
from jinja2 import BaseLoader, TemplateNotFound
|
3
|
+
import os
|
4
|
+
|
5
|
+
|
6
|
+
class TemplateLoader(BaseLoader):
|
7
|
+
def __init__(self, package_name, templates_dir):
|
8
|
+
self.package_name = package_name
|
9
|
+
self.templates_dir = templates_dir
|
10
|
+
|
11
|
+
def get_source(self, environment, template):
|
12
|
+
try:
|
13
|
+
parts = [self.templates_dir] + template.split("/")
|
14
|
+
template_path = os.path.join(*parts)
|
15
|
+
|
16
|
+
# Use resources.files() to get a Traversable object
|
17
|
+
templates = resources.files(self.package_name).joinpath(self.templates_dir)
|
18
|
+
|
19
|
+
# Use the read_text() method of the Traversable object
|
20
|
+
content = templates.joinpath(template).read_text()
|
21
|
+
|
22
|
+
return content, None, lambda: True
|
23
|
+
except FileNotFoundError:
|
24
|
+
raise TemplateNotFound(template)
|
edsl/__init__.py
CHANGED
@@ -8,9 +8,10 @@ from edsl.__version__ import __version__
|
|
8
8
|
from edsl.config import Config, CONFIG
|
9
9
|
from edsl.agents.Agent import Agent
|
10
10
|
from edsl.agents.AgentList import AgentList
|
11
|
+
|
11
12
|
from edsl.questions import QuestionBase
|
13
|
+
from edsl.questions.question_registry import Question
|
12
14
|
from edsl.questions import QuestionMultipleChoice
|
13
|
-
from edsl.questions import QuestionBudget
|
14
15
|
from edsl.questions import QuestionCheckBox
|
15
16
|
from edsl.questions import QuestionExtract
|
16
17
|
from edsl.questions import QuestionFreeText
|
@@ -19,10 +20,11 @@ from edsl.questions import QuestionLikertFive
|
|
19
20
|
from edsl.questions import QuestionList
|
20
21
|
from edsl.questions import QuestionLinearScale
|
21
22
|
from edsl.questions import QuestionNumerical
|
23
|
+
from edsl.questions import QuestionYesNo
|
24
|
+
from edsl.questions import QuestionBudget
|
22
25
|
from edsl.questions import QuestionRank
|
23
26
|
from edsl.questions import QuestionTopK
|
24
|
-
|
25
|
-
from edsl.questions.question_registry import Question
|
27
|
+
|
26
28
|
from edsl.scenarios import Scenario
|
27
29
|
from edsl.scenarios import ScenarioList
|
28
30
|
|
@@ -40,3 +42,6 @@ from edsl.notebooks.Notebook import Notebook
|
|
40
42
|
from edsl.study.Study import Study
|
41
43
|
from edsl.conjure.Conjure import Conjure
|
42
44
|
from edsl.coop.coop import Coop
|
45
|
+
|
46
|
+
from edsl.surveys.instructions.Instruction import Instruction
|
47
|
+
from edsl.surveys.instructions.ChangeInstruction import ChangeInstruction
|
edsl/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.33"
|
edsl/agents/Agent.py
CHANGED
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
4
4
|
import copy
|
5
5
|
import inspect
|
6
6
|
import types
|
7
|
-
from typing import Callable, Optional, Union
|
7
|
+
from typing import Callable, Optional, Union, Any
|
8
8
|
from uuid import uuid4
|
9
9
|
from edsl.Base import Base
|
10
10
|
|
@@ -228,7 +228,12 @@ class Agent(Base):
|
|
228
228
|
if hasattr(self, "answer_question_directly"):
|
229
229
|
delattr(self, "answer_question_directly")
|
230
230
|
|
231
|
-
def add_direct_question_answering_method(
|
231
|
+
def add_direct_question_answering_method(
|
232
|
+
self,
|
233
|
+
method: Callable,
|
234
|
+
validate_response: bool = False,
|
235
|
+
translate_response: bool = False,
|
236
|
+
) -> None:
|
232
237
|
"""Add a method to the agent that can answer a particular question type.
|
233
238
|
|
234
239
|
:param method: A method that can answer a question directly.
|
@@ -249,6 +254,9 @@ class Agent(Base):
|
|
249
254
|
)
|
250
255
|
# print("Warning: overwriting existing answer_question_directly method")
|
251
256
|
|
257
|
+
self.validate_response = validate_response
|
258
|
+
self.translate_response = translate_response
|
259
|
+
|
252
260
|
signature = inspect.signature(method)
|
253
261
|
for argument in ["question", "scenario", "self"]:
|
254
262
|
if argument not in signature.parameters:
|
@@ -272,6 +280,7 @@ class Agent(Base):
|
|
272
280
|
current_answers: Optional[dict] = None,
|
273
281
|
iteration: int = 1,
|
274
282
|
sidecar_model=None,
|
283
|
+
raise_validation_errors: bool = True,
|
275
284
|
) -> "InvigilatorBase":
|
276
285
|
"""Create an Invigilator.
|
277
286
|
|
@@ -303,7 +312,12 @@ class Agent(Base):
|
|
303
312
|
iteration=iteration,
|
304
313
|
cache=cache,
|
305
314
|
sidecar_model=sidecar_model,
|
315
|
+
raise_validation_errors=raise_validation_errors,
|
306
316
|
)
|
317
|
+
if hasattr(self, "validate_response"):
|
318
|
+
invigilator.validate_response = self.validate_response
|
319
|
+
if hasattr(self, "translate_response"):
|
320
|
+
invigilator.translate_response = self.translate_response
|
307
321
|
return invigilator
|
308
322
|
|
309
323
|
async def async_answer_question(
|
@@ -334,8 +348,8 @@ class Agent(Base):
|
|
334
348
|
>>> a.add_direct_question_answering_method(lambda self, question, scenario: "I am a direct answer.")
|
335
349
|
>>> from edsl import QuestionFreeText
|
336
350
|
>>> q = QuestionFreeText.example()
|
337
|
-
>>> a.answer_question(question = q, cache = False)
|
338
|
-
|
351
|
+
>>> a.answer_question(question = q, cache = False).answer
|
352
|
+
'I am a direct answer.'
|
339
353
|
|
340
354
|
This is a function where an agent returns an answer to a particular question.
|
341
355
|
However, there are several different ways an agent can answer a question, so the
|
@@ -369,6 +383,7 @@ class Agent(Base):
|
|
369
383
|
current_answers: Optional[dict] = None,
|
370
384
|
iteration: int = 0,
|
371
385
|
sidecar_model=None,
|
386
|
+
raise_validation_errors: bool = True,
|
372
387
|
) -> "InvigilatorBase":
|
373
388
|
"""Create an Invigilator."""
|
374
389
|
from edsl import Model
|
@@ -378,7 +393,6 @@ class Agent(Base):
|
|
378
393
|
scenario = scenario or Scenario()
|
379
394
|
|
380
395
|
from edsl.agents.Invigilator import (
|
381
|
-
InvigilatorDebug,
|
382
396
|
InvigilatorHuman,
|
383
397
|
InvigilatorFunctional,
|
384
398
|
InvigilatorAI,
|
@@ -391,8 +405,9 @@ class Agent(Base):
|
|
391
405
|
cache = Cache()
|
392
406
|
|
393
407
|
if debug:
|
408
|
+
raise NotImplementedError("Debug mode is not yet implemented.")
|
394
409
|
# use the question's _simulate_answer method
|
395
|
-
invigilator_class = InvigilatorDebug
|
410
|
+
# invigilator_class = InvigilatorDebug
|
396
411
|
elif hasattr(question, "answer_question_directly"):
|
397
412
|
# It's a functional question and the answer only depends on the agent's traits & the scenario
|
398
413
|
invigilator_class = InvigilatorFunctional
|
@@ -422,6 +437,7 @@ class Agent(Base):
|
|
422
437
|
iteration=iteration,
|
423
438
|
cache=cache,
|
424
439
|
sidecar_model=sidecar_model,
|
440
|
+
raise_validation_errors=raise_validation_errors,
|
425
441
|
)
|
426
442
|
return invigilator
|
427
443
|
|
@@ -497,8 +513,8 @@ class Agent(Base):
|
|
497
513
|
if name == "has_dynamic_traits_function":
|
498
514
|
return self.has_dynamic_traits_function
|
499
515
|
|
500
|
-
if name in self.
|
501
|
-
return self.
|
516
|
+
if name in self._traits:
|
517
|
+
return self._traits[name]
|
502
518
|
raise AttributeError(
|
503
519
|
f"'{type(self).__name__}' object has no attribute '{name}'"
|
504
520
|
)
|
@@ -640,6 +656,22 @@ class Agent(Base):
|
|
640
656
|
column_names = ["Attribute", "Value"]
|
641
657
|
return table_data, column_names
|
642
658
|
|
659
|
+
def add_trait(self, trait_name_or_dict: str, value: Optional[Any] = None) -> Agent:
|
660
|
+
"""Adds a trait to an agent and returns that agent"""
|
661
|
+
if isinstance(trait_name_or_dict, dict) and value is None:
|
662
|
+
self.traits.update(trait_name_or_dict)
|
663
|
+
return self
|
664
|
+
|
665
|
+
if isinstance(trait_name_or_dict, dict) and value:
|
666
|
+
raise ValueError(f"You passed a dict: {trait_name_or_dict}")
|
667
|
+
|
668
|
+
if isinstance(trait_name_or_dict, str):
|
669
|
+
trait = trait_name_or_dict
|
670
|
+
self.traits[trait] = value
|
671
|
+
return self
|
672
|
+
|
673
|
+
raise Exception("Something is not right with adding")
|
674
|
+
|
643
675
|
def remove_trait(self, trait: str) -> Agent:
|
644
676
|
"""Remove a trait from the agent.
|
645
677
|
|
edsl/agents/AgentList.py
CHANGED
@@ -21,6 +21,12 @@ from simpleeval import EvalWithCompoundTypes
|
|
21
21
|
from edsl.Base import Base
|
22
22
|
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
23
23
|
|
24
|
+
from collections.abc import Iterable
|
25
|
+
|
26
|
+
|
27
|
+
def is_iterable(obj):
|
28
|
+
return isinstance(obj, Iterable)
|
29
|
+
|
24
30
|
|
25
31
|
class AgentList(UserList, Base):
|
26
32
|
"""A list of Agents."""
|
@@ -111,6 +117,13 @@ class AgentList(UserList, Base):
|
|
111
117
|
|
112
118
|
return AgentList(new_data)
|
113
119
|
|
120
|
+
@property
|
121
|
+
def all_traits(self):
|
122
|
+
d = {}
|
123
|
+
for agent in self:
|
124
|
+
d.update(agent.traits)
|
125
|
+
return list(d.keys())
|
126
|
+
|
114
127
|
@classmethod
|
115
128
|
def from_csv(cls, file_path: str):
|
116
129
|
"""Load AgentList from a CSV file.
|
@@ -159,6 +172,36 @@ class AgentList(UserList, Base):
|
|
159
172
|
_ = agent.remove_trait(trait)
|
160
173
|
return self
|
161
174
|
|
175
|
+
def add_trait(self, trait, values):
|
176
|
+
"""Adds a new trait to every agent, with values taken from values.
|
177
|
+
|
178
|
+
:param trait: The name of the trait.
|
179
|
+
:param values: The valeues(s) of the trait. If a single value is passed, it is used for all agents.
|
180
|
+
|
181
|
+
>>> al = AgentList.example()
|
182
|
+
>>> al.add_trait('new_trait', 1)
|
183
|
+
AgentList([Agent(traits = {'age': 22, 'hair': 'brown', 'height': 5.5, 'new_trait': 1}), Agent(traits = {'age': 22, 'hair': 'brown', 'height': 5.5, 'new_trait': 1})])
|
184
|
+
>>> al.select('new_trait').to_scenario_list().to_list()
|
185
|
+
[1, 1]
|
186
|
+
>>> al.add_trait('new_trait', [1, 2, 3])
|
187
|
+
Traceback (most recent call last):
|
188
|
+
...
|
189
|
+
ValueError: The passed values have to be the same length as the agent list.
|
190
|
+
"""
|
191
|
+
if not is_iterable(values):
|
192
|
+
value = values
|
193
|
+
for agent in self.data:
|
194
|
+
agent.add_trait(trait, value)
|
195
|
+
return self
|
196
|
+
|
197
|
+
if len(values) != len(self):
|
198
|
+
raise ValueError(
|
199
|
+
"The passed values have to be the same length as the agent list."
|
200
|
+
)
|
201
|
+
for agent, value in zip(self.data, values):
|
202
|
+
agent.add_trait(trait, value)
|
203
|
+
return self
|
204
|
+
|
162
205
|
@staticmethod
|
163
206
|
def get_codebook(file_path: str):
|
164
207
|
"""Return the codebook for a CSV file.
|