edsl 0.1.38.dev3__py3-none-any.whl → 0.1.38.dev4__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 (256) hide show
  1. edsl/Base.py +332 -303
  2. edsl/BaseDiff.py +260 -260
  3. edsl/TemplateLoader.py +24 -24
  4. edsl/__init__.py +49 -49
  5. edsl/__version__.py +1 -1
  6. edsl/agents/Agent.py +867 -858
  7. edsl/agents/AgentList.py +413 -362
  8. edsl/agents/Invigilator.py +233 -222
  9. edsl/agents/InvigilatorBase.py +265 -284
  10. edsl/agents/PromptConstructor.py +354 -353
  11. edsl/agents/__init__.py +3 -3
  12. edsl/agents/descriptors.py +99 -99
  13. edsl/agents/prompt_helpers.py +129 -129
  14. edsl/auto/AutoStudy.py +117 -117
  15. edsl/auto/StageBase.py +230 -230
  16. edsl/auto/StageGenerateSurvey.py +178 -178
  17. edsl/auto/StageLabelQuestions.py +125 -125
  18. edsl/auto/StagePersona.py +61 -61
  19. edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
  20. edsl/auto/StagePersonaDimensionValues.py +74 -74
  21. edsl/auto/StagePersonaDimensions.py +69 -69
  22. edsl/auto/StageQuestions.py +73 -73
  23. edsl/auto/SurveyCreatorPipeline.py +21 -21
  24. edsl/auto/utilities.py +224 -224
  25. edsl/base/Base.py +279 -279
  26. edsl/config.py +157 -149
  27. edsl/conversation/Conversation.py +290 -290
  28. edsl/conversation/car_buying.py +58 -58
  29. edsl/conversation/chips.py +95 -95
  30. edsl/conversation/mug_negotiation.py +81 -81
  31. edsl/conversation/next_speaker_utilities.py +93 -93
  32. edsl/coop/PriceFetcher.py +54 -54
  33. edsl/coop/__init__.py +2 -2
  34. edsl/coop/coop.py +1028 -961
  35. edsl/coop/utils.py +131 -131
  36. edsl/data/Cache.py +555 -530
  37. edsl/data/CacheEntry.py +233 -228
  38. edsl/data/CacheHandler.py +149 -149
  39. edsl/data/RemoteCacheSync.py +78 -97
  40. edsl/data/SQLiteDict.py +292 -292
  41. edsl/data/__init__.py +4 -4
  42. edsl/data/orm.py +10 -10
  43. edsl/data_transfer_models.py +73 -73
  44. edsl/enums.py +175 -173
  45. edsl/exceptions/BaseException.py +21 -21
  46. edsl/exceptions/__init__.py +54 -54
  47. edsl/exceptions/agents.py +42 -42
  48. edsl/exceptions/cache.py +5 -5
  49. edsl/exceptions/configuration.py +16 -16
  50. edsl/exceptions/coop.py +10 -10
  51. edsl/exceptions/data.py +14 -14
  52. edsl/exceptions/general.py +34 -34
  53. edsl/exceptions/jobs.py +33 -33
  54. edsl/exceptions/language_models.py +63 -63
  55. edsl/exceptions/prompts.py +15 -15
  56. edsl/exceptions/questions.py +91 -91
  57. edsl/exceptions/results.py +29 -29
  58. edsl/exceptions/scenarios.py +22 -22
  59. edsl/exceptions/surveys.py +37 -37
  60. edsl/inference_services/AnthropicService.py +87 -87
  61. edsl/inference_services/AwsBedrock.py +120 -120
  62. edsl/inference_services/AzureAI.py +217 -217
  63. edsl/inference_services/DeepInfraService.py +18 -18
  64. edsl/inference_services/GoogleService.py +148 -156
  65. edsl/inference_services/GroqService.py +20 -20
  66. edsl/inference_services/InferenceServiceABC.py +147 -147
  67. edsl/inference_services/InferenceServicesCollection.py +97 -97
  68. edsl/inference_services/MistralAIService.py +123 -123
  69. edsl/inference_services/OllamaService.py +18 -18
  70. edsl/inference_services/OpenAIService.py +224 -224
  71. edsl/inference_services/PerplexityService.py +163 -0
  72. edsl/inference_services/TestService.py +89 -89
  73. edsl/inference_services/TogetherAIService.py +170 -170
  74. edsl/inference_services/models_available_cache.py +118 -118
  75. edsl/inference_services/rate_limits_cache.py +25 -25
  76. edsl/inference_services/registry.py +41 -39
  77. edsl/inference_services/write_available.py +10 -10
  78. edsl/jobs/Answers.py +56 -56
  79. edsl/jobs/Jobs.py +898 -1358
  80. edsl/jobs/JobsChecks.py +147 -0
  81. edsl/jobs/JobsPrompts.py +268 -0
  82. edsl/jobs/JobsRemoteInferenceHandler.py +239 -0
  83. edsl/jobs/__init__.py +1 -1
  84. edsl/jobs/buckets/BucketCollection.py +63 -63
  85. edsl/jobs/buckets/ModelBuckets.py +65 -65
  86. edsl/jobs/buckets/TokenBucket.py +251 -251
  87. edsl/jobs/interviews/Interview.py +661 -661
  88. edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
  89. edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
  90. edsl/jobs/interviews/InterviewStatistic.py +63 -63
  91. edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
  92. edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
  93. edsl/jobs/interviews/InterviewStatusLog.py +92 -92
  94. edsl/jobs/interviews/ReportErrors.py +66 -66
  95. edsl/jobs/interviews/interview_status_enum.py +9 -9
  96. edsl/jobs/runners/JobsRunnerAsyncio.py +466 -361
  97. edsl/jobs/runners/JobsRunnerStatus.py +330 -332
  98. edsl/jobs/tasks/QuestionTaskCreator.py +242 -242
  99. edsl/jobs/tasks/TaskCreators.py +64 -64
  100. edsl/jobs/tasks/TaskHistory.py +450 -451
  101. edsl/jobs/tasks/TaskStatusLog.py +23 -23
  102. edsl/jobs/tasks/task_status_enum.py +163 -163
  103. edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
  104. edsl/jobs/tokens/TokenUsage.py +34 -34
  105. edsl/language_models/KeyLookup.py +30 -30
  106. edsl/language_models/LanguageModel.py +668 -708
  107. edsl/language_models/ModelList.py +155 -109
  108. edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
  109. edsl/language_models/__init__.py +3 -3
  110. edsl/language_models/fake_openai_call.py +15 -15
  111. edsl/language_models/fake_openai_service.py +61 -61
  112. edsl/language_models/registry.py +190 -137
  113. edsl/language_models/repair.py +156 -156
  114. edsl/language_models/unused/ReplicateBase.py +83 -83
  115. edsl/language_models/utilities.py +64 -64
  116. edsl/notebooks/Notebook.py +258 -258
  117. edsl/notebooks/__init__.py +1 -1
  118. edsl/prompts/Prompt.py +362 -357
  119. edsl/prompts/__init__.py +2 -2
  120. edsl/questions/AnswerValidatorMixin.py +289 -289
  121. edsl/questions/QuestionBase.py +664 -660
  122. edsl/questions/QuestionBaseGenMixin.py +161 -161
  123. edsl/questions/QuestionBasePromptsMixin.py +217 -217
  124. edsl/questions/QuestionBudget.py +227 -227
  125. edsl/questions/QuestionCheckBox.py +359 -359
  126. edsl/questions/QuestionExtract.py +182 -183
  127. edsl/questions/QuestionFreeText.py +114 -114
  128. edsl/questions/QuestionFunctional.py +166 -166
  129. edsl/questions/QuestionList.py +231 -231
  130. edsl/questions/QuestionMultipleChoice.py +286 -286
  131. edsl/questions/QuestionNumerical.py +153 -153
  132. edsl/questions/QuestionRank.py +324 -324
  133. edsl/questions/Quick.py +41 -41
  134. edsl/questions/RegisterQuestionsMeta.py +71 -71
  135. edsl/questions/ResponseValidatorABC.py +174 -174
  136. edsl/questions/SimpleAskMixin.py +73 -73
  137. edsl/questions/__init__.py +26 -26
  138. edsl/questions/compose_questions.py +98 -98
  139. edsl/questions/decorators.py +21 -21
  140. edsl/questions/derived/QuestionLikertFive.py +76 -76
  141. edsl/questions/derived/QuestionLinearScale.py +87 -87
  142. edsl/questions/derived/QuestionTopK.py +93 -93
  143. edsl/questions/derived/QuestionYesNo.py +82 -82
  144. edsl/questions/descriptors.py +413 -413
  145. edsl/questions/prompt_templates/question_budget.jinja +13 -13
  146. edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
  147. edsl/questions/prompt_templates/question_extract.jinja +11 -11
  148. edsl/questions/prompt_templates/question_free_text.jinja +3 -3
  149. edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
  150. edsl/questions/prompt_templates/question_list.jinja +17 -17
  151. edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
  152. edsl/questions/prompt_templates/question_numerical.jinja +36 -36
  153. edsl/questions/question_registry.py +177 -147
  154. edsl/questions/settings.py +12 -12
  155. edsl/questions/templates/budget/answering_instructions.jinja +7 -7
  156. edsl/questions/templates/budget/question_presentation.jinja +7 -7
  157. edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
  158. edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
  159. edsl/questions/templates/extract/answering_instructions.jinja +7 -7
  160. edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
  161. edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
  162. edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
  163. edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
  164. edsl/questions/templates/list/answering_instructions.jinja +3 -3
  165. edsl/questions/templates/list/question_presentation.jinja +5 -5
  166. edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
  167. edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
  168. edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
  169. edsl/questions/templates/numerical/question_presentation.jinja +6 -6
  170. edsl/questions/templates/rank/answering_instructions.jinja +11 -11
  171. edsl/questions/templates/rank/question_presentation.jinja +15 -15
  172. edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
  173. edsl/questions/templates/top_k/question_presentation.jinja +22 -22
  174. edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
  175. edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
  176. edsl/results/CSSParameterizer.py +108 -0
  177. edsl/results/Dataset.py +424 -293
  178. edsl/results/DatasetExportMixin.py +731 -717
  179. edsl/results/DatasetTree.py +275 -145
  180. edsl/results/Result.py +465 -456
  181. edsl/results/Results.py +1165 -1071
  182. edsl/results/ResultsDBMixin.py +238 -238
  183. edsl/results/ResultsExportMixin.py +43 -43
  184. edsl/results/ResultsFetchMixin.py +33 -33
  185. edsl/results/ResultsGGMixin.py +121 -121
  186. edsl/results/ResultsToolsMixin.py +98 -98
  187. edsl/results/Selector.py +135 -135
  188. edsl/results/TableDisplay.py +198 -0
  189. edsl/results/__init__.py +2 -2
  190. edsl/results/table_display.css +78 -0
  191. edsl/results/tree_explore.py +115 -115
  192. edsl/scenarios/FileStore.py +632 -458
  193. edsl/scenarios/Scenario.py +601 -544
  194. edsl/scenarios/ScenarioHtmlMixin.py +64 -64
  195. edsl/scenarios/ScenarioJoin.py +127 -0
  196. edsl/scenarios/ScenarioList.py +1287 -1112
  197. edsl/scenarios/ScenarioListExportMixin.py +52 -52
  198. edsl/scenarios/ScenarioListPdfMixin.py +261 -261
  199. edsl/scenarios/__init__.py +4 -4
  200. edsl/shared.py +1 -1
  201. edsl/study/ObjectEntry.py +173 -173
  202. edsl/study/ProofOfWork.py +113 -113
  203. edsl/study/SnapShot.py +80 -80
  204. edsl/study/Study.py +528 -528
  205. edsl/study/__init__.py +4 -4
  206. edsl/surveys/DAG.py +148 -148
  207. edsl/surveys/Memory.py +31 -31
  208. edsl/surveys/MemoryPlan.py +244 -244
  209. edsl/surveys/Rule.py +326 -326
  210. edsl/surveys/RuleCollection.py +387 -387
  211. edsl/surveys/Survey.py +1801 -1787
  212. edsl/surveys/SurveyCSS.py +261 -261
  213. edsl/surveys/SurveyExportMixin.py +259 -259
  214. edsl/surveys/SurveyFlowVisualizationMixin.py +179 -121
  215. edsl/surveys/SurveyQualtricsImport.py +284 -284
  216. edsl/surveys/__init__.py +3 -3
  217. edsl/surveys/base.py +53 -53
  218. edsl/surveys/descriptors.py +56 -56
  219. edsl/surveys/instructions/ChangeInstruction.py +49 -49
  220. edsl/surveys/instructions/Instruction.py +65 -53
  221. edsl/surveys/instructions/InstructionCollection.py +77 -77
  222. edsl/templates/error_reporting/base.html +23 -23
  223. edsl/templates/error_reporting/exceptions_by_model.html +34 -34
  224. edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
  225. edsl/templates/error_reporting/exceptions_by_type.html +16 -16
  226. edsl/templates/error_reporting/interview_details.html +115 -115
  227. edsl/templates/error_reporting/interviews.html +19 -10
  228. edsl/templates/error_reporting/overview.html +4 -4
  229. edsl/templates/error_reporting/performance_plot.html +1 -1
  230. edsl/templates/error_reporting/report.css +73 -73
  231. edsl/templates/error_reporting/report.html +117 -117
  232. edsl/templates/error_reporting/report.js +25 -25
  233. edsl/tools/__init__.py +1 -1
  234. edsl/tools/clusters.py +192 -192
  235. edsl/tools/embeddings.py +27 -27
  236. edsl/tools/embeddings_plotting.py +118 -118
  237. edsl/tools/plotting.py +112 -112
  238. edsl/tools/summarize.py +18 -18
  239. edsl/utilities/SystemInfo.py +28 -28
  240. edsl/utilities/__init__.py +22 -22
  241. edsl/utilities/ast_utilities.py +25 -25
  242. edsl/utilities/data/Registry.py +6 -6
  243. edsl/utilities/data/__init__.py +1 -1
  244. edsl/utilities/data/scooter_results.json +1 -1
  245. edsl/utilities/decorators.py +77 -77
  246. edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
  247. edsl/utilities/interface.py +627 -627
  248. edsl/utilities/naming_utilities.py +263 -263
  249. edsl/utilities/repair_functions.py +28 -28
  250. edsl/utilities/restricted_python.py +70 -70
  251. edsl/utilities/utilities.py +424 -409
  252. {edsl-0.1.38.dev3.dist-info → edsl-0.1.38.dev4.dist-info}/LICENSE +21 -21
  253. {edsl-0.1.38.dev3.dist-info → edsl-0.1.38.dev4.dist-info}/METADATA +2 -1
  254. edsl-0.1.38.dev4.dist-info/RECORD +277 -0
  255. edsl-0.1.38.dev3.dist-info/RECORD +0 -269
  256. {edsl-0.1.38.dev3.dist-info → edsl-0.1.38.dev4.dist-info}/WHEEL +0 -0
@@ -1,87 +1,87 @@
1
- from __future__ import annotations
2
- from typing import Optional
3
-
4
- from edsl.questions.descriptors import QuestionOptionsDescriptor, OptionLabelDescriptor
5
- from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
6
-
7
- from edsl.questions.decorators import inject_exception
8
-
9
-
10
- class QuestionLinearScale(QuestionMultipleChoice):
11
- """This question prompts the agent to respond to a statement on a linear scale."""
12
-
13
- question_type = "linear_scale"
14
- option_labels: Optional[dict[int, str]] = OptionLabelDescriptor()
15
- question_options = QuestionOptionsDescriptor(linear_scale=True)
16
-
17
- def __init__(
18
- self,
19
- question_name: str,
20
- question_text: str,
21
- question_options: list[int],
22
- option_labels: Optional[dict[int, str]] = None,
23
- answering_instructions: Optional[str] = None,
24
- question_presentation: Optional[str] = None,
25
- include_comment: Optional[bool] = True,
26
- ):
27
- """Instantiate a new QuestionLinearScale.
28
-
29
- :param question_name: The name of the question.
30
- :param question_text: The text of the question.
31
- :param question_options: The options the respondent should select from.
32
- :param option_labels: Maps question_options to labels.
33
- :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionLinearScale.default_instructions`.
34
- """
35
- super().__init__(
36
- question_name=question_name,
37
- question_text=question_text,
38
- question_options=question_options,
39
- use_code=False, # question linear scale will have it's own code
40
- include_comment=include_comment,
41
- )
42
- self.question_options = question_options
43
- self.option_labels = (
44
- {int(k): v for k, v in option_labels.items()} if option_labels else {}
45
- )
46
- self.answering_instructions = answering_instructions
47
- self.question_presentation = question_presentation
48
-
49
- ################
50
- # Helpful
51
- ################
52
- @classmethod
53
- @inject_exception
54
- def example(cls, include_comment: bool = True) -> QuestionLinearScale:
55
- """Return an example of a linear scale question."""
56
- return cls(
57
- question_text="How much do you like ice cream?",
58
- question_options=[1, 2, 3, 4, 5],
59
- question_name="ice_cream",
60
- option_labels={1: "I hate it", 5: "I love it"},
61
- include_comment=include_comment,
62
- )
63
-
64
-
65
- def main():
66
- """Create an example of a linear scale question and demonstrate its functionality."""
67
- from edsl.questions.derived.QuestionLinearScale import QuestionLinearScale
68
-
69
- q = QuestionLinearScale.example()
70
- q.question_text
71
- q.question_options
72
- q.question_name
73
- # validate an answer
74
- q._validate_answer({"answer": 3, "comment": "I like custard"})
75
- # translate answer code
76
- q._translate_answer_code_to_answer(3, {})
77
- # simulate answer
78
- q._simulate_answer()
79
- q._simulate_answer(human_readable=False)
80
- q._validate_answer(q._simulate_answer(human_readable=False))
81
- # serialization (inherits from Question)
82
- q.to_dict()
83
- assert q.from_dict(q.to_dict()) == q
84
-
85
- import doctest
86
-
87
- doctest.testmod(optionflags=doctest.ELLIPSIS)
1
+ from __future__ import annotations
2
+ from typing import Optional
3
+
4
+ from edsl.questions.descriptors import QuestionOptionsDescriptor, OptionLabelDescriptor
5
+ from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
6
+
7
+ from edsl.questions.decorators import inject_exception
8
+
9
+
10
+ class QuestionLinearScale(QuestionMultipleChoice):
11
+ """This question prompts the agent to respond to a statement on a linear scale."""
12
+
13
+ question_type = "linear_scale"
14
+ option_labels: Optional[dict[int, str]] = OptionLabelDescriptor()
15
+ question_options = QuestionOptionsDescriptor(linear_scale=True)
16
+
17
+ def __init__(
18
+ self,
19
+ question_name: str,
20
+ question_text: str,
21
+ question_options: list[int],
22
+ option_labels: Optional[dict[int, str]] = None,
23
+ answering_instructions: Optional[str] = None,
24
+ question_presentation: Optional[str] = None,
25
+ include_comment: Optional[bool] = True,
26
+ ):
27
+ """Instantiate a new QuestionLinearScale.
28
+
29
+ :param question_name: The name of the question.
30
+ :param question_text: The text of the question.
31
+ :param question_options: The options the respondent should select from.
32
+ :param option_labels: Maps question_options to labels.
33
+ :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionLinearScale.default_instructions`.
34
+ """
35
+ super().__init__(
36
+ question_name=question_name,
37
+ question_text=question_text,
38
+ question_options=question_options,
39
+ use_code=False, # question linear scale will have it's own code
40
+ include_comment=include_comment,
41
+ )
42
+ self.question_options = question_options
43
+ self.option_labels = (
44
+ {int(k): v for k, v in option_labels.items()} if option_labels else {}
45
+ )
46
+ self.answering_instructions = answering_instructions
47
+ self.question_presentation = question_presentation
48
+
49
+ ################
50
+ # Helpful
51
+ ################
52
+ @classmethod
53
+ @inject_exception
54
+ def example(cls, include_comment: bool = True) -> QuestionLinearScale:
55
+ """Return an example of a linear scale question."""
56
+ return cls(
57
+ question_text="How much do you like ice cream?",
58
+ question_options=[1, 2, 3, 4, 5],
59
+ question_name="ice_cream",
60
+ option_labels={1: "I hate it", 5: "I love it"},
61
+ include_comment=include_comment,
62
+ )
63
+
64
+
65
+ def main():
66
+ """Create an example of a linear scale question and demonstrate its functionality."""
67
+ from edsl.questions.derived.QuestionLinearScale import QuestionLinearScale
68
+
69
+ q = QuestionLinearScale.example()
70
+ q.question_text
71
+ q.question_options
72
+ q.question_name
73
+ # validate an answer
74
+ q._validate_answer({"answer": 3, "comment": "I like custard"})
75
+ # translate answer code
76
+ q._translate_answer_code_to_answer(3, {})
77
+ # simulate answer
78
+ q._simulate_answer()
79
+ q._simulate_answer(human_readable=False)
80
+ q._validate_answer(q._simulate_answer(human_readable=False))
81
+ # serialization (inherits from Question)
82
+ q.to_dict()
83
+ assert q.from_dict(q.to_dict()) == q
84
+
85
+ import doctest
86
+
87
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
@@ -1,93 +1,93 @@
1
- from __future__ import annotations
2
- from typing import Optional
3
-
4
- from edsl.exceptions import QuestionCreationValidationError
5
- from edsl.questions.QuestionCheckBox import QuestionCheckBox
6
- from edsl.questions.decorators import inject_exception
7
-
8
-
9
- class QuestionTopK(QuestionCheckBox):
10
- """This question prompts the agent to select exactly K options from a list."""
11
-
12
- question_type = "top_k"
13
-
14
- def __init__(
15
- self,
16
- question_name: str,
17
- question_text: str,
18
- question_options: list[str],
19
- min_selections: int,
20
- max_selections: int,
21
- question_presentation: Optional[str] = None,
22
- answering_instructions: Optional[str] = None,
23
- include_comment: Optional[bool] = True,
24
- use_code: Optional[bool] = True,
25
- ):
26
- """Initialize the question.
27
-
28
- :param question_name: The name of the question.
29
- :param question_text: The text of the question.
30
- :param question_options: The options the respondent should select from.
31
- :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionTopK.default_instructions`.
32
- :param num_selections: The number of options that must be selected.
33
- """
34
- super().__init__(
35
- question_name=question_name,
36
- question_text=question_text,
37
- question_options=question_options,
38
- min_selections=min_selections,
39
- max_selections=max_selections,
40
- question_presentation=question_presentation,
41
- answering_instructions=answering_instructions,
42
- include_comment=include_comment,
43
- use_code=use_code,
44
- )
45
- if min_selections != max_selections:
46
- raise QuestionCreationValidationError(
47
- "TopK questions must have min_selections == max_selections"
48
- )
49
- if min_selections < 1:
50
- raise QuestionCreationValidationError(
51
- "TopK questions must have min_selections > 0"
52
- )
53
-
54
- ################
55
- # Helpful
56
- ################
57
- @classmethod
58
- @inject_exception
59
- def example(cls, include_comment: bool = True) -> QuestionTopK:
60
- """Return an example question."""
61
- return cls(
62
- question_name="two_fruits",
63
- question_text="Which of the following fruits do you prefer?",
64
- question_options=["apple", "banana", "carrot", "durian"],
65
- min_selections=2,
66
- max_selections=2,
67
- include_comment=include_comment,
68
- )
69
-
70
-
71
- def main():
72
- """Test QuestionTopK."""
73
- from edsl.questions.derived.QuestionTopK import QuestionTopK
74
-
75
- q = QuestionTopK.example()
76
- q.question_text
77
- q.question_options
78
- q.question_name
79
- # validate an answer
80
- q._validate_answer({"answer": [0, 3], "comment": "I like custard"})
81
- # translate answer code
82
- q._translate_answer_code_to_answer([0, 3], {})
83
- # simulate answer
84
- q._simulate_answer()
85
- q._simulate_answer(human_readable=False)
86
- q._validate_answer(q._simulate_answer(human_readable=False))
87
- # serialization (inherits from Question)
88
- q.to_dict()
89
- assert q.from_dict(q.to_dict()) == q
90
-
91
- import doctest
92
-
93
- doctest.testmod(optionflags=doctest.ELLIPSIS)
1
+ from __future__ import annotations
2
+ from typing import Optional
3
+
4
+ from edsl.exceptions import QuestionCreationValidationError
5
+ from edsl.questions.QuestionCheckBox import QuestionCheckBox
6
+ from edsl.questions.decorators import inject_exception
7
+
8
+
9
+ class QuestionTopK(QuestionCheckBox):
10
+ """This question prompts the agent to select exactly K options from a list."""
11
+
12
+ question_type = "top_k"
13
+
14
+ def __init__(
15
+ self,
16
+ question_name: str,
17
+ question_text: str,
18
+ question_options: list[str],
19
+ min_selections: int,
20
+ max_selections: int,
21
+ question_presentation: Optional[str] = None,
22
+ answering_instructions: Optional[str] = None,
23
+ include_comment: Optional[bool] = True,
24
+ use_code: Optional[bool] = True,
25
+ ):
26
+ """Initialize the question.
27
+
28
+ :param question_name: The name of the question.
29
+ :param question_text: The text of the question.
30
+ :param question_options: The options the respondent should select from.
31
+ :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionTopK.default_instructions`.
32
+ :param num_selections: The number of options that must be selected.
33
+ """
34
+ super().__init__(
35
+ question_name=question_name,
36
+ question_text=question_text,
37
+ question_options=question_options,
38
+ min_selections=min_selections,
39
+ max_selections=max_selections,
40
+ question_presentation=question_presentation,
41
+ answering_instructions=answering_instructions,
42
+ include_comment=include_comment,
43
+ use_code=use_code,
44
+ )
45
+ if min_selections != max_selections:
46
+ raise QuestionCreationValidationError(
47
+ "TopK questions must have min_selections == max_selections"
48
+ )
49
+ if min_selections < 1:
50
+ raise QuestionCreationValidationError(
51
+ "TopK questions must have min_selections > 0"
52
+ )
53
+
54
+ ################
55
+ # Helpful
56
+ ################
57
+ @classmethod
58
+ @inject_exception
59
+ def example(cls, include_comment: bool = True) -> QuestionTopK:
60
+ """Return an example question."""
61
+ return cls(
62
+ question_name="two_fruits",
63
+ question_text="Which of the following fruits do you prefer?",
64
+ question_options=["apple", "banana", "carrot", "durian"],
65
+ min_selections=2,
66
+ max_selections=2,
67
+ include_comment=include_comment,
68
+ )
69
+
70
+
71
+ def main():
72
+ """Test QuestionTopK."""
73
+ from edsl.questions.derived.QuestionTopK import QuestionTopK
74
+
75
+ q = QuestionTopK.example()
76
+ q.question_text
77
+ q.question_options
78
+ q.question_name
79
+ # validate an answer
80
+ q._validate_answer({"answer": [0, 3], "comment": "I like custard"})
81
+ # translate answer code
82
+ q._translate_answer_code_to_answer([0, 3], {})
83
+ # simulate answer
84
+ q._simulate_answer()
85
+ q._simulate_answer(human_readable=False)
86
+ q._validate_answer(q._simulate_answer(human_readable=False))
87
+ # serialization (inherits from Question)
88
+ q.to_dict()
89
+ assert q.from_dict(q.to_dict()) == q
90
+
91
+ import doctest
92
+
93
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
@@ -1,82 +1,82 @@
1
- from __future__ import annotations
2
- from typing import Optional
3
- from edsl.questions.descriptors import QuestionOptionsDescriptor
4
- from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
5
-
6
- from edsl.questions.decorators import inject_exception
7
-
8
-
9
- class QuestionYesNo(QuestionMultipleChoice):
10
- """This question prompts the agent to respond with 'Yes' or 'No'."""
11
-
12
- question_type = "yes_no"
13
- question_options = QuestionOptionsDescriptor(num_choices=2)
14
-
15
- def __init__(
16
- self,
17
- question_name: str,
18
- question_text: str,
19
- question_options: list[str] = ["No", "Yes"],
20
- answering_instructions: Optional[str] = None,
21
- question_presentation: Optional[str] = None,
22
- include_comment: Optional[bool] = True,
23
- ):
24
- """Instantiate a new QuestionYesNo.
25
-
26
- :param question_name: The name of the question.
27
- :param question_text: The text of the question.
28
- :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionYesNo.default_instructions`.
29
- """
30
- super().__init__(
31
- question_name=question_name,
32
- question_text=question_text,
33
- question_options=question_options,
34
- use_code=False,
35
- answering_instructions=answering_instructions,
36
- question_presentation=question_presentation,
37
- include_comment=include_comment,
38
- )
39
- self.question_options = question_options
40
-
41
- ################
42
- # Helpful
43
- ################
44
- @classmethod
45
- @inject_exception
46
- def example(cls, include_comment: bool = True) -> QuestionYesNo:
47
- """Return an example of a yes/no question."""
48
- return cls(
49
- question_name="is_it_equal",
50
- question_text="Is 5 + 5 equal to 11?",
51
- include_comment=include_comment,
52
- )
53
-
54
-
55
- def main():
56
- """Create an example of a yes/no question and demonstrate its functionality."""
57
- from edsl.questions.derived.QuestionYesNo import QuestionYesNo
58
-
59
- q = QuestionYesNo.example()
60
- q.question_text
61
- q.question_options
62
- q.question_name
63
- # validate an answer
64
- q._validate_answer({"answer": 0, "comment": "I like custard"})
65
- # translate answer code
66
- q._translate_answer_code_to_answer(0, {})
67
- q._simulate_answer()
68
- q._simulate_answer(human_readable=False)
69
- q._validate_answer(q._simulate_answer(human_readable=False))
70
- # serialization (inherits from Question)
71
- q.to_dict()
72
- assert q.from_dict(q.to_dict()) == q
73
-
74
- import doctest
75
-
76
- doctest.testmod(optionflags=doctest.ELLIPSIS)
77
-
78
-
79
- if __name__ == "__main__":
80
- import doctest
81
-
82
- doctest.testmod(optionflags=doctest.ELLIPSIS)
1
+ from __future__ import annotations
2
+ from typing import Optional
3
+ from edsl.questions.descriptors import QuestionOptionsDescriptor
4
+ from edsl.questions.QuestionMultipleChoice import QuestionMultipleChoice
5
+
6
+ from edsl.questions.decorators import inject_exception
7
+
8
+
9
+ class QuestionYesNo(QuestionMultipleChoice):
10
+ """This question prompts the agent to respond with 'Yes' or 'No'."""
11
+
12
+ question_type = "yes_no"
13
+ question_options = QuestionOptionsDescriptor(num_choices=2)
14
+
15
+ def __init__(
16
+ self,
17
+ question_name: str,
18
+ question_text: str,
19
+ question_options: list[str] = ["No", "Yes"],
20
+ answering_instructions: Optional[str] = None,
21
+ question_presentation: Optional[str] = None,
22
+ include_comment: Optional[bool] = True,
23
+ ):
24
+ """Instantiate a new QuestionYesNo.
25
+
26
+ :param question_name: The name of the question.
27
+ :param question_text: The text of the question.
28
+ :param instructions: Instructions for the question. If not provided, the default instructions are used. To view them, run `QuestionYesNo.default_instructions`.
29
+ """
30
+ super().__init__(
31
+ question_name=question_name,
32
+ question_text=question_text,
33
+ question_options=question_options,
34
+ use_code=False,
35
+ answering_instructions=answering_instructions,
36
+ question_presentation=question_presentation,
37
+ include_comment=include_comment,
38
+ )
39
+ self.question_options = question_options
40
+
41
+ ################
42
+ # Helpful
43
+ ################
44
+ @classmethod
45
+ @inject_exception
46
+ def example(cls, include_comment: bool = True) -> QuestionYesNo:
47
+ """Return an example of a yes/no question."""
48
+ return cls(
49
+ question_name="is_it_equal",
50
+ question_text="Is 5 + 5 equal to 11?",
51
+ include_comment=include_comment,
52
+ )
53
+
54
+
55
+ def main():
56
+ """Create an example of a yes/no question and demonstrate its functionality."""
57
+ from edsl.questions.derived.QuestionYesNo import QuestionYesNo
58
+
59
+ q = QuestionYesNo.example()
60
+ q.question_text
61
+ q.question_options
62
+ q.question_name
63
+ # validate an answer
64
+ q._validate_answer({"answer": 0, "comment": "I like custard"})
65
+ # translate answer code
66
+ q._translate_answer_code_to_answer(0, {})
67
+ q._simulate_answer()
68
+ q._simulate_answer(human_readable=False)
69
+ q._validate_answer(q._simulate_answer(human_readable=False))
70
+ # serialization (inherits from Question)
71
+ q.to_dict()
72
+ assert q.from_dict(q.to_dict()) == q
73
+
74
+ import doctest
75
+
76
+ doctest.testmod(optionflags=doctest.ELLIPSIS)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ import doctest
81
+
82
+ doctest.testmod(optionflags=doctest.ELLIPSIS)