edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev5__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 +413 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +57 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +1071 -867
- edsl/agents/AgentList.py +551 -413
- edsl/agents/Invigilator.py +284 -233
- edsl/agents/InvigilatorBase.py +257 -270
- edsl/agents/PromptConstructor.py +272 -354
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +2 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -117
- edsl/auto/StageBase.py +243 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +74 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +218 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +177 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +59 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1106 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +573 -555
- edsl/data/CacheEntry.py +230 -233
- edsl/data/CacheHandler.py +168 -149
- edsl/data/RemoteCacheSync.py +186 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +5 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +74 -73
- edsl/enums.py +202 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +54 -42
- edsl/exceptions/cache.py +5 -5
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +109 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +29 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +106 -87
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -120
- edsl/inference_services/AzureAI.py +215 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +143 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +80 -147
- edsl/inference_services/InferenceServicesCollection.py +138 -97
- edsl/inference_services/MistralAIService.py +120 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +236 -224
- edsl/inference_services/PerplexityService.py +160 -163
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -89
- edsl/inference_services/TogetherAIService.py +172 -170
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +43 -56
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +823 -898
- edsl/jobs/JobsChecks.py +172 -147
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +283 -251
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +396 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
- edsl/jobs/runners/JobsRunnerStatus.py +297 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +470 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +161 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +626 -668
- edsl/language_models/ModelList.py +164 -155
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +2 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +156 -156
- edsl/language_models/utilities.py +65 -64
- edsl/notebooks/Notebook.py +263 -258
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +352 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -664
- edsl/questions/QuestionBasePromptsMixin.py +221 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +180 -182
- edsl/questions/QuestionFreeText.py +113 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +223 -231
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +330 -286
- edsl/questions/QuestionNumerical.py +151 -153
- edsl/questions/QuestionRank.py +314 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/SimpleAskMixin.py +74 -73
- edsl/questions/__init__.py +27 -26
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +90 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +427 -413
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
- edsl/questions/question_registry.py +177 -177
- edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -108
- edsl/results/Dataset.py +587 -424
- edsl/results/DatasetExportMixin.py +594 -731
- edsl/results/DatasetTree.py +295 -275
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +557 -465
- edsl/results/Results.py +1183 -1165
- edsl/results/ResultsExportMixin.py +45 -43
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/TableDisplay.py +125 -198
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +2 -2
- edsl/results/file_exports.py +252 -0
- edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
- edsl/results/{Selector.py → results_selector.py} +145 -135
- edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +77 -77
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +511 -632
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +498 -601
- edsl/scenarios/ScenarioHtmlMixin.py +65 -64
- edsl/scenarios/ScenarioList.py +1458 -1287
- edsl/scenarios/ScenarioListExportMixin.py +45 -52
- edsl/scenarios/ScenarioListPdfMixin.py +239 -261
- edsl/scenarios/__init__.py +3 -4
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +38 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +521 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +327 -326
- edsl/surveys/RuleCollection.py +385 -387
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1280 -1801
- edsl/surveys/SurveyCSS.py +273 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +5 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +60 -56
- edsl/surveys/instructions/ChangeInstruction.py +48 -49
- edsl/surveys/instructions/Instruction.py +56 -65
- edsl/surveys/instructions/InstructionCollection.py +82 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -19
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +436 -424
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/METADATA +13 -11
- edsl-0.1.39.dev5.dist-info/RECORD +358 -0
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/WHEEL +1 -1
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.39.dev3.dist-info/RECORD +0 -277
@@ -1,177 +1,177 @@
|
|
1
|
-
"""This module provides a factory class for creating question objects."""
|
2
|
-
|
3
|
-
import textwrap
|
4
|
-
from uuid import UUID
|
5
|
-
from typing import Any, Optional, Union
|
6
|
-
|
7
|
-
|
8
|
-
from edsl.questions.QuestionBase import RegisterQuestionsMeta
|
9
|
-
|
10
|
-
|
11
|
-
class Meta(type):
|
12
|
-
"""Metaclass for QuestionBase that provides a __repr__ method that lists all available questions."""
|
13
|
-
|
14
|
-
def __repr__(cls):
|
15
|
-
"""Return a string that lists all available questions."""
|
16
|
-
|
17
|
-
s = textwrap.dedent(
|
18
|
-
"""
|
19
|
-
You can use the Question class to create objects by name.
|
20
|
-
For example, to create a multiple choice question, you can do:
|
21
|
-
|
22
|
-
>>> from edsl import Question
|
23
|
-
>>> q = Question('multiple_choice', question_text='What is your favorite color?', question_name='color')
|
24
|
-
|
25
|
-
Question Types:\n"""
|
26
|
-
)
|
27
|
-
for question_type, question_class in cls.available(
|
28
|
-
show_class_names=True
|
29
|
-
).items():
|
30
|
-
line_info = (
|
31
|
-
f"{question_type} ({question_class.__name__}): {question_class.__doc__}"
|
32
|
-
)
|
33
|
-
s += line_info + "\n"
|
34
|
-
return s
|
35
|
-
|
36
|
-
|
37
|
-
class Question(metaclass=Meta):
|
38
|
-
"""Factory class for creating question objects."""
|
39
|
-
|
40
|
-
def __new__(cls, question_type, *args, **kwargs):
|
41
|
-
"""Create a new question object."""
|
42
|
-
get_question_classes = RegisterQuestionsMeta.question_types_to_classes()
|
43
|
-
|
44
|
-
subclass = get_question_classes.get(question_type, None)
|
45
|
-
if subclass is None:
|
46
|
-
raise ValueError(
|
47
|
-
f"No question registered with question_type {question_type}"
|
48
|
-
)
|
49
|
-
|
50
|
-
# Create an instance of the selected subclass
|
51
|
-
instance = object.__new__(subclass)
|
52
|
-
instance.__init__(*args, **kwargs)
|
53
|
-
return instance
|
54
|
-
|
55
|
-
@classmethod
|
56
|
-
def example(cls, question_type: str):
|
57
|
-
"""Return an example question of the given type."""
|
58
|
-
get_question_classes = RegisterQuestionsMeta.question_types_to_classes()
|
59
|
-
q = get_question_classes.get(question_type, None)
|
60
|
-
return q.example()
|
61
|
-
|
62
|
-
@classmethod
|
63
|
-
def pull(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
64
|
-
"""Pull the object from coop."""
|
65
|
-
from edsl.coop import Coop
|
66
|
-
|
67
|
-
coop = Coop()
|
68
|
-
return coop.get(uuid, url, "question")
|
69
|
-
|
70
|
-
@classmethod
|
71
|
-
def delete(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
72
|
-
"""Delete the object from coop."""
|
73
|
-
from edsl.coop import Coop
|
74
|
-
|
75
|
-
coop = Coop()
|
76
|
-
return coop.delete(uuid, url)
|
77
|
-
|
78
|
-
@classmethod
|
79
|
-
def patch(
|
80
|
-
cls,
|
81
|
-
uuid: Optional[Union[str, UUID]] = None,
|
82
|
-
url: Optional[str] = None,
|
83
|
-
description: Optional[str] = None,
|
84
|
-
value: Optional[Any] = None,
|
85
|
-
visibility: Optional[str] = None,
|
86
|
-
):
|
87
|
-
"""Patch the object on coop."""
|
88
|
-
from edsl.coop import Coop
|
89
|
-
|
90
|
-
coop = Coop()
|
91
|
-
return coop.patch(uuid, url, description, value, visibility)
|
92
|
-
|
93
|
-
@classmethod
|
94
|
-
def list_question_types(cls):
|
95
|
-
"""Return a list of available question types.
|
96
|
-
|
97
|
-
>>> from edsl import Question
|
98
|
-
>>> Question.list_question_types()
|
99
|
-
['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
|
100
|
-
"""
|
101
|
-
return [
|
102
|
-
q
|
103
|
-
for q in sorted(
|
104
|
-
list(RegisterQuestionsMeta.question_types_to_classes().keys())
|
105
|
-
)
|
106
|
-
if q not in ["budget"]
|
107
|
-
]
|
108
|
-
|
109
|
-
@classmethod
|
110
|
-
def available(cls, show_class_names: bool = False) -> Union[list, dict]:
|
111
|
-
"""Return a list of available question types.
|
112
|
-
|
113
|
-
:param show_class_names: If True, return a dictionary of question types to class names. If False, return a set of question types.
|
114
|
-
|
115
|
-
Example usage:
|
116
|
-
|
117
|
-
"""
|
118
|
-
from edsl.results.Dataset import Dataset
|
119
|
-
|
120
|
-
exclude = ["budget"]
|
121
|
-
if show_class_names:
|
122
|
-
return RegisterQuestionsMeta.question_types_to_classes()
|
123
|
-
else:
|
124
|
-
question_list = [
|
125
|
-
q
|
126
|
-
for q in sorted(
|
127
|
-
set(RegisterQuestionsMeta.question_types_to_classes().keys())
|
128
|
-
)
|
129
|
-
if q not in exclude
|
130
|
-
]
|
131
|
-
d = RegisterQuestionsMeta.question_types_to_classes()
|
132
|
-
question_classes = [d[q] for q in question_list]
|
133
|
-
example_questions = [repr(q.example()) for q in question_classes]
|
134
|
-
|
135
|
-
return Dataset(
|
136
|
-
[
|
137
|
-
{"question_type": [q for q in question_list]},
|
138
|
-
{"question_class": [q.__name__ for q in question_classes]},
|
139
|
-
{"example_question": example_questions},
|
140
|
-
],
|
141
|
-
print_parameters={"containerHeight": "auto"},
|
142
|
-
)
|
143
|
-
|
144
|
-
|
145
|
-
def get_question_class(question_type):
|
146
|
-
"""Return the class for the given question type."""
|
147
|
-
q2c = RegisterQuestionsMeta.question_types_to_classes()
|
148
|
-
if question_type not in q2c:
|
149
|
-
raise ValueError(
|
150
|
-
f"The question type, {question_type}, is not recognized. Recognied types are: {q2c.keys()}"
|
151
|
-
)
|
152
|
-
return q2c.get(question_type)
|
153
|
-
|
154
|
-
|
155
|
-
question_purpose = {
|
156
|
-
"multiple_choice": "When options are known and limited",
|
157
|
-
"free_text": "When options are unknown or unlimited",
|
158
|
-
"checkbox": "When multiple options can be selected",
|
159
|
-
"numerical": "When the answer is a single numerical value e.g., a float",
|
160
|
-
"linear_scale": "When options are text, but can be ordered, e.g., daily, weekly, monthly, etc.",
|
161
|
-
"yes_no": "When the question can be fully answered with either a yes or a no",
|
162
|
-
"list": "When the answer should be a list of items",
|
163
|
-
"rank": "When the answer should be a ranked list of items",
|
164
|
-
"budget": "When the answer should be an amount allocated among a set of options",
|
165
|
-
"top_k": "When the answer should be a list of the top k items",
|
166
|
-
"likert_five": "When the answer should be a value on the Likert scale from 1 to 5",
|
167
|
-
"extract": "When the answer should be information extracted or extrapolated from a text in a given format",
|
168
|
-
}
|
169
|
-
|
170
|
-
|
171
|
-
if __name__ == "__main__":
|
172
|
-
print(Question.available())
|
173
|
-
|
174
|
-
# q = Question("free_text", question_text="How are you doing?", question_name="test")
|
175
|
-
# results = q.run()
|
176
|
-
|
177
|
-
q = Question.pull(id=76)
|
1
|
+
"""This module provides a factory class for creating question objects."""
|
2
|
+
|
3
|
+
import textwrap
|
4
|
+
from uuid import UUID
|
5
|
+
from typing import Any, Optional, Union
|
6
|
+
|
7
|
+
|
8
|
+
from edsl.questions.QuestionBase import RegisterQuestionsMeta
|
9
|
+
|
10
|
+
|
11
|
+
class Meta(type):
|
12
|
+
"""Metaclass for QuestionBase that provides a __repr__ method that lists all available questions."""
|
13
|
+
|
14
|
+
def __repr__(cls):
|
15
|
+
"""Return a string that lists all available questions."""
|
16
|
+
|
17
|
+
s = textwrap.dedent(
|
18
|
+
"""
|
19
|
+
You can use the Question class to create objects by name.
|
20
|
+
For example, to create a multiple choice question, you can do:
|
21
|
+
|
22
|
+
>>> from edsl import Question
|
23
|
+
>>> q = Question('multiple_choice', question_text='What is your favorite color?', question_name='color')
|
24
|
+
|
25
|
+
Question Types:\n"""
|
26
|
+
)
|
27
|
+
for question_type, question_class in cls.available(
|
28
|
+
show_class_names=True
|
29
|
+
).items():
|
30
|
+
line_info = (
|
31
|
+
f"{question_type} ({question_class.__name__}): {question_class.__doc__}"
|
32
|
+
)
|
33
|
+
s += line_info + "\n"
|
34
|
+
return s
|
35
|
+
|
36
|
+
|
37
|
+
class Question(metaclass=Meta):
|
38
|
+
"""Factory class for creating question objects."""
|
39
|
+
|
40
|
+
def __new__(cls, question_type, *args, **kwargs):
|
41
|
+
"""Create a new question object."""
|
42
|
+
get_question_classes = RegisterQuestionsMeta.question_types_to_classes()
|
43
|
+
|
44
|
+
subclass = get_question_classes.get(question_type, None)
|
45
|
+
if subclass is None:
|
46
|
+
raise ValueError(
|
47
|
+
f"No question registered with question_type {question_type}"
|
48
|
+
)
|
49
|
+
|
50
|
+
# Create an instance of the selected subclass
|
51
|
+
instance = object.__new__(subclass)
|
52
|
+
instance.__init__(*args, **kwargs)
|
53
|
+
return instance
|
54
|
+
|
55
|
+
@classmethod
|
56
|
+
def example(cls, question_type: str):
|
57
|
+
"""Return an example question of the given type."""
|
58
|
+
get_question_classes = RegisterQuestionsMeta.question_types_to_classes()
|
59
|
+
q = get_question_classes.get(question_type, None)
|
60
|
+
return q.example()
|
61
|
+
|
62
|
+
@classmethod
|
63
|
+
def pull(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
64
|
+
"""Pull the object from coop."""
|
65
|
+
from edsl.coop import Coop
|
66
|
+
|
67
|
+
coop = Coop()
|
68
|
+
return coop.get(uuid, url, "question")
|
69
|
+
|
70
|
+
@classmethod
|
71
|
+
def delete(cls, uuid: Optional[Union[str, UUID]] = None, url: Optional[str] = None):
|
72
|
+
"""Delete the object from coop."""
|
73
|
+
from edsl.coop import Coop
|
74
|
+
|
75
|
+
coop = Coop()
|
76
|
+
return coop.delete(uuid, url)
|
77
|
+
|
78
|
+
@classmethod
|
79
|
+
def patch(
|
80
|
+
cls,
|
81
|
+
uuid: Optional[Union[str, UUID]] = None,
|
82
|
+
url: Optional[str] = None,
|
83
|
+
description: Optional[str] = None,
|
84
|
+
value: Optional[Any] = None,
|
85
|
+
visibility: Optional[str] = None,
|
86
|
+
):
|
87
|
+
"""Patch the object on coop."""
|
88
|
+
from edsl.coop import Coop
|
89
|
+
|
90
|
+
coop = Coop()
|
91
|
+
return coop.patch(uuid, url, description, value, visibility)
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def list_question_types(cls):
|
95
|
+
"""Return a list of available question types.
|
96
|
+
|
97
|
+
>>> from edsl import Question
|
98
|
+
>>> Question.list_question_types()
|
99
|
+
['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'matrix', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
|
100
|
+
"""
|
101
|
+
return [
|
102
|
+
q
|
103
|
+
for q in sorted(
|
104
|
+
list(RegisterQuestionsMeta.question_types_to_classes().keys())
|
105
|
+
)
|
106
|
+
if q not in ["budget"]
|
107
|
+
]
|
108
|
+
|
109
|
+
@classmethod
|
110
|
+
def available(cls, show_class_names: bool = False) -> Union[list, dict]:
|
111
|
+
"""Return a list of available question types.
|
112
|
+
|
113
|
+
:param show_class_names: If True, return a dictionary of question types to class names. If False, return a set of question types.
|
114
|
+
|
115
|
+
Example usage:
|
116
|
+
|
117
|
+
"""
|
118
|
+
from edsl.results.Dataset import Dataset
|
119
|
+
|
120
|
+
exclude = ["budget"]
|
121
|
+
if show_class_names:
|
122
|
+
return RegisterQuestionsMeta.question_types_to_classes()
|
123
|
+
else:
|
124
|
+
question_list = [
|
125
|
+
q
|
126
|
+
for q in sorted(
|
127
|
+
set(RegisterQuestionsMeta.question_types_to_classes().keys())
|
128
|
+
)
|
129
|
+
if q not in exclude
|
130
|
+
]
|
131
|
+
d = RegisterQuestionsMeta.question_types_to_classes()
|
132
|
+
question_classes = [d[q] for q in question_list]
|
133
|
+
example_questions = [repr(q.example()) for q in question_classes]
|
134
|
+
|
135
|
+
return Dataset(
|
136
|
+
[
|
137
|
+
{"question_type": [q for q in question_list]},
|
138
|
+
{"question_class": [q.__name__ for q in question_classes]},
|
139
|
+
{"example_question": example_questions},
|
140
|
+
],
|
141
|
+
print_parameters={"containerHeight": "auto"},
|
142
|
+
)
|
143
|
+
|
144
|
+
|
145
|
+
def get_question_class(question_type):
|
146
|
+
"""Return the class for the given question type."""
|
147
|
+
q2c = RegisterQuestionsMeta.question_types_to_classes()
|
148
|
+
if question_type not in q2c:
|
149
|
+
raise ValueError(
|
150
|
+
f"The question type, {question_type}, is not recognized. Recognied types are: {q2c.keys()}"
|
151
|
+
)
|
152
|
+
return q2c.get(question_type)
|
153
|
+
|
154
|
+
|
155
|
+
question_purpose = {
|
156
|
+
"multiple_choice": "When options are known and limited",
|
157
|
+
"free_text": "When options are unknown or unlimited",
|
158
|
+
"checkbox": "When multiple options can be selected",
|
159
|
+
"numerical": "When the answer is a single numerical value e.g., a float",
|
160
|
+
"linear_scale": "When options are text, but can be ordered, e.g., daily, weekly, monthly, etc.",
|
161
|
+
"yes_no": "When the question can be fully answered with either a yes or a no",
|
162
|
+
"list": "When the answer should be a list of items",
|
163
|
+
"rank": "When the answer should be a ranked list of items",
|
164
|
+
"budget": "When the answer should be an amount allocated among a set of options",
|
165
|
+
"top_k": "When the answer should be a list of the top k items",
|
166
|
+
"likert_five": "When the answer should be a value on the Likert scale from 1 to 5",
|
167
|
+
"extract": "When the answer should be information extracted or extrapolated from a text in a given format",
|
168
|
+
}
|
169
|
+
|
170
|
+
|
171
|
+
if __name__ == "__main__":
|
172
|
+
print(Question.available())
|
173
|
+
|
174
|
+
# q = Question("free_text", question_text="How are you doing?", question_name="test")
|
175
|
+
# results = q.run()
|
176
|
+
|
177
|
+
q = Question.pull(id=76)
|
@@ -1,71 +1,71 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from abc import ABCMeta
|
3
|
-
|
4
|
-
from edsl.enums import QuestionType
|
5
|
-
from edsl.exceptions.questions import QuestionMissingTypeError, QuestionBadTypeError
|
6
|
-
|
7
|
-
import inspect
|
8
|
-
|
9
|
-
|
10
|
-
class RegisterQuestionsMeta(ABCMeta):
|
11
|
-
"""Metaclass to register output elements in a registry i.e., those that have a parent."""
|
12
|
-
|
13
|
-
_registry = {} # Initialize the registry as a dictionary
|
14
|
-
|
15
|
-
def __init__(cls, name, bases, dct):
|
16
|
-
"""Initialize the class and adds it to the registry if it's not the base class."""
|
17
|
-
super(RegisterQuestionsMeta, cls).__init__(name, bases, dct)
|
18
|
-
if (
|
19
|
-
name != "QuestionBase"
|
20
|
-
and name != "QuestionFunctional"
|
21
|
-
and name != "QuestionAddTwoNumbers"
|
22
|
-
):
|
23
|
-
## Enforce that all questions have a question_type class attribute
|
24
|
-
## and it comes from our enum of valid question types.
|
25
|
-
required_attributes = [
|
26
|
-
"question_type",
|
27
|
-
"_response_model",
|
28
|
-
"response_validator_class",
|
29
|
-
]
|
30
|
-
for attr in required_attributes:
|
31
|
-
if not hasattr(cls, attr):
|
32
|
-
raise QuestionMissingTypeError(
|
33
|
-
f"Question must have a {attr} class attribute"
|
34
|
-
)
|
35
|
-
|
36
|
-
init_signature = inspect.signature(cls.__init__)
|
37
|
-
init_params = [p for p in init_signature.parameters if p != "self"]
|
38
|
-
required_params = [
|
39
|
-
"question_presentation",
|
40
|
-
"answering_instructions",
|
41
|
-
"question_name",
|
42
|
-
"question_text",
|
43
|
-
]
|
44
|
-
for param in required_params:
|
45
|
-
if param not in init_params:
|
46
|
-
raise QuestionBadTypeError(
|
47
|
-
f"Question type {name} must have a question_presentation parameter in its __init__ method"
|
48
|
-
)
|
49
|
-
|
50
|
-
if name != "QuestionBase":
|
51
|
-
RegisterQuestionsMeta._registry[name] = cls
|
52
|
-
|
53
|
-
@classmethod
|
54
|
-
def get_registered_classes(cls):
|
55
|
-
"""Return the registry of registered classes."""
|
56
|
-
return cls._registry
|
57
|
-
|
58
|
-
@classmethod
|
59
|
-
def question_types_to_classes(
|
60
|
-
cls,
|
61
|
-
):
|
62
|
-
"""Return a dictionary of question types to classes."""
|
63
|
-
d = {}
|
64
|
-
for classname, cls in cls._registry.items():
|
65
|
-
if hasattr(cls, "question_type"):
|
66
|
-
d[cls.question_type] = cls
|
67
|
-
else:
|
68
|
-
raise Exception(
|
69
|
-
f"Class {classname} does not have a question_type class attribute"
|
70
|
-
)
|
71
|
-
return d
|
1
|
+
from __future__ import annotations
|
2
|
+
from abc import ABCMeta
|
3
|
+
|
4
|
+
from edsl.enums import QuestionType
|
5
|
+
from edsl.exceptions.questions import QuestionMissingTypeError, QuestionBadTypeError
|
6
|
+
|
7
|
+
import inspect
|
8
|
+
|
9
|
+
|
10
|
+
class RegisterQuestionsMeta(ABCMeta):
|
11
|
+
"""Metaclass to register output elements in a registry i.e., those that have a parent."""
|
12
|
+
|
13
|
+
_registry = {} # Initialize the registry as a dictionary
|
14
|
+
|
15
|
+
def __init__(cls, name, bases, dct):
|
16
|
+
"""Initialize the class and adds it to the registry if it's not the base class."""
|
17
|
+
super(RegisterQuestionsMeta, cls).__init__(name, bases, dct)
|
18
|
+
if (
|
19
|
+
name != "QuestionBase"
|
20
|
+
and name != "QuestionFunctional"
|
21
|
+
and name != "QuestionAddTwoNumbers"
|
22
|
+
):
|
23
|
+
## Enforce that all questions have a question_type class attribute
|
24
|
+
## and it comes from our enum of valid question types.
|
25
|
+
required_attributes = [
|
26
|
+
"question_type",
|
27
|
+
"_response_model",
|
28
|
+
"response_validator_class",
|
29
|
+
]
|
30
|
+
for attr in required_attributes:
|
31
|
+
if not hasattr(cls, attr):
|
32
|
+
raise QuestionMissingTypeError(
|
33
|
+
f"Question must have a {attr} class attribute"
|
34
|
+
)
|
35
|
+
|
36
|
+
init_signature = inspect.signature(cls.__init__)
|
37
|
+
init_params = [p for p in init_signature.parameters if p != "self"]
|
38
|
+
required_params = [
|
39
|
+
"question_presentation",
|
40
|
+
"answering_instructions",
|
41
|
+
"question_name",
|
42
|
+
"question_text",
|
43
|
+
]
|
44
|
+
for param in required_params:
|
45
|
+
if param not in init_params:
|
46
|
+
raise QuestionBadTypeError(
|
47
|
+
f"Question type {name} must have a question_presentation parameter in its __init__ method"
|
48
|
+
)
|
49
|
+
|
50
|
+
if name != "QuestionBase":
|
51
|
+
RegisterQuestionsMeta._registry[name] = cls
|
52
|
+
|
53
|
+
@classmethod
|
54
|
+
def get_registered_classes(cls):
|
55
|
+
"""Return the registry of registered classes."""
|
56
|
+
return cls._registry
|
57
|
+
|
58
|
+
@classmethod
|
59
|
+
def question_types_to_classes(
|
60
|
+
cls,
|
61
|
+
):
|
62
|
+
"""Return a dictionary of question types to classes."""
|
63
|
+
d = {}
|
64
|
+
for classname, cls in cls._registry.items():
|
65
|
+
if hasattr(cls, "question_type"):
|
66
|
+
d[cls.question_type] = cls
|
67
|
+
else:
|
68
|
+
raise Exception(
|
69
|
+
f"Class {classname} does not have a question_type class attribute"
|
70
|
+
)
|
71
|
+
return d
|