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,259 +1,259 @@
|
|
1
|
-
"""A mixin class for exporting surveys to different formats."""
|
2
|
-
|
3
|
-
from typing import Union, Optional
|
4
|
-
|
5
|
-
import subprocess
|
6
|
-
import platform
|
7
|
-
import os
|
8
|
-
import tempfile
|
9
|
-
|
10
|
-
|
11
|
-
def open_docx(file_path):
|
12
|
-
"""
|
13
|
-
Open a docx file using the default application in a cross-platform manner.
|
14
|
-
|
15
|
-
:param file_path: str, path to the docx file
|
16
|
-
"""
|
17
|
-
file_path = os.path.abspath(file_path)
|
18
|
-
|
19
|
-
if platform.system() == "Darwin": # macOS
|
20
|
-
subprocess.call(("open", file_path))
|
21
|
-
elif platform.system() == "Windows": # Windows
|
22
|
-
os.startfile(file_path)
|
23
|
-
else: # linux variants
|
24
|
-
subprocess.call(("xdg-open", file_path))
|
25
|
-
|
26
|
-
|
27
|
-
class SurveyExportMixin:
|
28
|
-
"""A mixin class for exporting surveys to different formats."""
|
29
|
-
|
30
|
-
def css(self):
|
31
|
-
from edsl.surveys.SurveyCSS import SurveyCSS
|
32
|
-
|
33
|
-
return SurveyCSS.default_style().generate_css()
|
34
|
-
|
35
|
-
def get_description(self) -> str:
|
36
|
-
"""Return the description of the survey."""
|
37
|
-
from edsl import QuestionFreeText
|
38
|
-
|
39
|
-
question_texts = "\n".join([q.question_text for q in self._questions])
|
40
|
-
q = QuestionFreeText(
|
41
|
-
question_name="description",
|
42
|
-
question_text=f"""A survey was conducted with the following questions:
|
43
|
-
{question_texts}
|
44
|
-
Please write a description of the survey.
|
45
|
-
""",
|
46
|
-
)
|
47
|
-
return q.run().select("description").first()
|
48
|
-
|
49
|
-
def docx(
|
50
|
-
self,
|
51
|
-
return_document_object: bool = False,
|
52
|
-
filename: Optional[str] = None,
|
53
|
-
open_file: bool = False,
|
54
|
-
) -> Union["Document", None]:
|
55
|
-
"""Generate a docx document for the survey."""
|
56
|
-
from docx import Document
|
57
|
-
|
58
|
-
doc = Document()
|
59
|
-
doc.add_heading("EDSL Survey")
|
60
|
-
doc.add_paragraph(f"\n")
|
61
|
-
for index, question in enumerate(self._questions):
|
62
|
-
h = doc.add_paragraph() # Add question as a paragraph
|
63
|
-
h.add_run(f"Question {index + 1} ({question.question_name})").bold = True
|
64
|
-
h.add_run(f"; {question.question_type}").italic = True
|
65
|
-
p = doc.add_paragraph()
|
66
|
-
p.add_run(question.question_text)
|
67
|
-
if question.question_type == "linear_scale":
|
68
|
-
for key, value in getattr(question, "option_labels", {}).items():
|
69
|
-
doc.add_paragraph(str(key) + ": " + str(value), style="ListBullet")
|
70
|
-
else:
|
71
|
-
if hasattr(question, "question_options"):
|
72
|
-
for option in getattr(question, "question_options", []):
|
73
|
-
doc.add_paragraph(str(option), style="ListBullet")
|
74
|
-
|
75
|
-
if return_document_object and filename is None:
|
76
|
-
return doc
|
77
|
-
|
78
|
-
if filename is None:
|
79
|
-
with tempfile.NamedTemporaryFile(
|
80
|
-
"w", delete=False, suffix=".docx", dir=os.getcwd()
|
81
|
-
) as f:
|
82
|
-
filename = f.name
|
83
|
-
|
84
|
-
doc.save(filename)
|
85
|
-
print("The survey has been saved to", filename)
|
86
|
-
if open_file:
|
87
|
-
open_docx(filename)
|
88
|
-
return
|
89
|
-
|
90
|
-
def show(self):
|
91
|
-
self.to_scenario_list(questions_only=False, rename=True).print(format="rich")
|
92
|
-
|
93
|
-
def to_scenario_list(
|
94
|
-
self, questions_only: bool = True, rename=False
|
95
|
-
) -> "ScenarioList":
|
96
|
-
from edsl import ScenarioList, Scenario
|
97
|
-
|
98
|
-
# from edsl.questions import QuestionBase
|
99
|
-
|
100
|
-
if questions_only:
|
101
|
-
to_iterate_over = self._questions
|
102
|
-
else:
|
103
|
-
to_iterate_over = self.recombined_questions_and_instructions()
|
104
|
-
|
105
|
-
if rename:
|
106
|
-
renaming_dict = {
|
107
|
-
"name": "identifier",
|
108
|
-
"question_name": "identifier",
|
109
|
-
"question_text": "text",
|
110
|
-
}
|
111
|
-
else:
|
112
|
-
renaming_dict = {}
|
113
|
-
|
114
|
-
all_keys = set([])
|
115
|
-
scenarios = ScenarioList()
|
116
|
-
for item in to_iterate_over:
|
117
|
-
d = item.to_dict()
|
118
|
-
if item.__class__.__name__ == "Instruction":
|
119
|
-
d["question_type"] = "NA / instruction"
|
120
|
-
for key in renaming_dict:
|
121
|
-
if key in d:
|
122
|
-
d[renaming_dict[key]] = d.pop(key)
|
123
|
-
all_keys.update(d.keys())
|
124
|
-
scenarios.append(Scenario(d))
|
125
|
-
|
126
|
-
for scenario in scenarios:
|
127
|
-
for key in all_keys:
|
128
|
-
if key not in scenario:
|
129
|
-
scenario[key] = None
|
130
|
-
|
131
|
-
return scenarios
|
132
|
-
|
133
|
-
def code(self, filename: str = None, survey_var_name: str = "survey") -> list[str]:
|
134
|
-
"""Create the Python code representation of a survey.
|
135
|
-
|
136
|
-
:param filename: The name of the file to save the code to.
|
137
|
-
:param survey_var_name: The name of the survey variable.
|
138
|
-
|
139
|
-
>>> from edsl.surveys import Survey
|
140
|
-
>>> survey = Survey.example()
|
141
|
-
>>> print(survey.code())
|
142
|
-
from edsl.surveys.Survey import Survey
|
143
|
-
...
|
144
|
-
...
|
145
|
-
survey = Survey(questions=[q0, q1, q2])
|
146
|
-
...
|
147
|
-
"""
|
148
|
-
import black
|
149
|
-
|
150
|
-
header_lines = ["from edsl.surveys.Survey import Survey"]
|
151
|
-
header_lines.append("from edsl import Question")
|
152
|
-
lines = ["\n".join(header_lines)]
|
153
|
-
for question in self._questions:
|
154
|
-
question.question_text = question["question_text"].replace("\n", " ")
|
155
|
-
# remove dublicate spaces
|
156
|
-
question.question_text = " ".join(question.question_text.split())
|
157
|
-
lines.append(f"{question.question_name} = " + repr(question))
|
158
|
-
lines.append(
|
159
|
-
f"{survey_var_name} = Survey(questions = [{', '.join(self.question_names)}])"
|
160
|
-
)
|
161
|
-
# return lines
|
162
|
-
code_string = "\n".join(lines)
|
163
|
-
formatted_code = black.format_str(code_string, mode=black.FileMode())
|
164
|
-
|
165
|
-
if filename:
|
166
|
-
print("The code has been saved to", filename)
|
167
|
-
print("The survey itself is saved to 'survey' object")
|
168
|
-
with open(filename, "w") as file:
|
169
|
-
file.write(formatted_code)
|
170
|
-
return
|
171
|
-
|
172
|
-
return formatted_code
|
173
|
-
|
174
|
-
def html(
|
175
|
-
self,
|
176
|
-
scenario: Optional[dict] = None,
|
177
|
-
filename: Optional[str] = None,
|
178
|
-
return_link=False,
|
179
|
-
css: Optional[str] = None,
|
180
|
-
cta: Optional[str] = "Open HTML file",
|
181
|
-
include_question_name=False,
|
182
|
-
):
|
183
|
-
from IPython.display import display, HTML
|
184
|
-
import tempfile
|
185
|
-
import os
|
186
|
-
from edsl.utilities.utilities import is_notebook
|
187
|
-
|
188
|
-
if scenario is None:
|
189
|
-
scenario = {}
|
190
|
-
|
191
|
-
if css is None:
|
192
|
-
css = self.css()
|
193
|
-
|
194
|
-
if filename is None:
|
195
|
-
current_directory = os.getcwd()
|
196
|
-
filename = tempfile.NamedTemporaryFile(
|
197
|
-
"w", delete=False, suffix=".html", dir=current_directory
|
198
|
-
).name
|
199
|
-
|
200
|
-
html_header = f"""<html>
|
201
|
-
<head><title></title>
|
202
|
-
<style>
|
203
|
-
{ css }
|
204
|
-
</style>
|
205
|
-
</head>
|
206
|
-
<body>
|
207
|
-
<div class="survey_container">
|
208
|
-
"""
|
209
|
-
|
210
|
-
html_footer = """
|
211
|
-
</div>
|
212
|
-
</body>
|
213
|
-
</html>"""
|
214
|
-
|
215
|
-
output = html_header
|
216
|
-
|
217
|
-
with open(filename, "w") as f:
|
218
|
-
f.write(html_header)
|
219
|
-
for question in self._questions:
|
220
|
-
f.write(
|
221
|
-
question.html(
|
222
|
-
scenario=scenario, include_question_name=include_question_name
|
223
|
-
)
|
224
|
-
)
|
225
|
-
output += question.html(
|
226
|
-
scenario=scenario, include_question_name=include_question_name
|
227
|
-
)
|
228
|
-
f.write(html_footer)
|
229
|
-
output += html_footer
|
230
|
-
|
231
|
-
if is_notebook():
|
232
|
-
html_url = f"/files/{filename}"
|
233
|
-
html_link = f'<a href="{html_url}" target="_blank">{cta}</a>'
|
234
|
-
display(HTML(html_link))
|
235
|
-
|
236
|
-
import html
|
237
|
-
|
238
|
-
escaped_output = html.escape(output)
|
239
|
-
iframe = f""""
|
240
|
-
<iframe srcdoc="{ escaped_output }" style="width: 800px; height: 600px;"></iframe>
|
241
|
-
"""
|
242
|
-
display(HTML(iframe))
|
243
|
-
|
244
|
-
else:
|
245
|
-
print(f"Survey saved to {filename}")
|
246
|
-
import webbrowser
|
247
|
-
import os
|
248
|
-
|
249
|
-
webbrowser.open(f"file://{os.path.abspath(filename)}")
|
250
|
-
# webbrowser.open(filename)
|
251
|
-
|
252
|
-
if return_link:
|
253
|
-
return filename
|
254
|
-
|
255
|
-
|
256
|
-
if __name__ == "__main__":
|
257
|
-
import doctest
|
258
|
-
|
259
|
-
doctest.testmod(optionflags=doctest.ELLIPSIS)
|
1
|
+
"""A mixin class for exporting surveys to different formats."""
|
2
|
+
|
3
|
+
from typing import Union, Optional
|
4
|
+
|
5
|
+
import subprocess
|
6
|
+
import platform
|
7
|
+
import os
|
8
|
+
import tempfile
|
9
|
+
|
10
|
+
|
11
|
+
def open_docx(file_path):
|
12
|
+
"""
|
13
|
+
Open a docx file using the default application in a cross-platform manner.
|
14
|
+
|
15
|
+
:param file_path: str, path to the docx file
|
16
|
+
"""
|
17
|
+
file_path = os.path.abspath(file_path)
|
18
|
+
|
19
|
+
if platform.system() == "Darwin": # macOS
|
20
|
+
subprocess.call(("open", file_path))
|
21
|
+
elif platform.system() == "Windows": # Windows
|
22
|
+
os.startfile(file_path)
|
23
|
+
else: # linux variants
|
24
|
+
subprocess.call(("xdg-open", file_path))
|
25
|
+
|
26
|
+
|
27
|
+
class SurveyExportMixin:
|
28
|
+
"""A mixin class for exporting surveys to different formats."""
|
29
|
+
|
30
|
+
def css(self):
|
31
|
+
from edsl.surveys.SurveyCSS import SurveyCSS
|
32
|
+
|
33
|
+
return SurveyCSS.default_style().generate_css()
|
34
|
+
|
35
|
+
def get_description(self) -> str:
|
36
|
+
"""Return the description of the survey."""
|
37
|
+
from edsl import QuestionFreeText
|
38
|
+
|
39
|
+
question_texts = "\n".join([q.question_text for q in self._questions])
|
40
|
+
q = QuestionFreeText(
|
41
|
+
question_name="description",
|
42
|
+
question_text=f"""A survey was conducted with the following questions:
|
43
|
+
{question_texts}
|
44
|
+
Please write a description of the survey.
|
45
|
+
""",
|
46
|
+
)
|
47
|
+
return q.run().select("description").first()
|
48
|
+
|
49
|
+
def docx(
|
50
|
+
self,
|
51
|
+
return_document_object: bool = False,
|
52
|
+
filename: Optional[str] = None,
|
53
|
+
open_file: bool = False,
|
54
|
+
) -> Union["Document", None]:
|
55
|
+
"""Generate a docx document for the survey."""
|
56
|
+
from docx import Document
|
57
|
+
|
58
|
+
doc = Document()
|
59
|
+
doc.add_heading("EDSL Survey")
|
60
|
+
doc.add_paragraph(f"\n")
|
61
|
+
for index, question in enumerate(self._questions):
|
62
|
+
h = doc.add_paragraph() # Add question as a paragraph
|
63
|
+
h.add_run(f"Question {index + 1} ({question.question_name})").bold = True
|
64
|
+
h.add_run(f"; {question.question_type}").italic = True
|
65
|
+
p = doc.add_paragraph()
|
66
|
+
p.add_run(question.question_text)
|
67
|
+
if question.question_type == "linear_scale":
|
68
|
+
for key, value in getattr(question, "option_labels", {}).items():
|
69
|
+
doc.add_paragraph(str(key) + ": " + str(value), style="ListBullet")
|
70
|
+
else:
|
71
|
+
if hasattr(question, "question_options"):
|
72
|
+
for option in getattr(question, "question_options", []):
|
73
|
+
doc.add_paragraph(str(option), style="ListBullet")
|
74
|
+
|
75
|
+
if return_document_object and filename is None:
|
76
|
+
return doc
|
77
|
+
|
78
|
+
if filename is None:
|
79
|
+
with tempfile.NamedTemporaryFile(
|
80
|
+
"w", delete=False, suffix=".docx", dir=os.getcwd()
|
81
|
+
) as f:
|
82
|
+
filename = f.name
|
83
|
+
|
84
|
+
doc.save(filename)
|
85
|
+
print("The survey has been saved to", filename)
|
86
|
+
if open_file:
|
87
|
+
open_docx(filename)
|
88
|
+
return
|
89
|
+
|
90
|
+
def show(self):
|
91
|
+
self.to_scenario_list(questions_only=False, rename=True).print(format="rich")
|
92
|
+
|
93
|
+
def to_scenario_list(
|
94
|
+
self, questions_only: bool = True, rename=False
|
95
|
+
) -> "ScenarioList":
|
96
|
+
from edsl import ScenarioList, Scenario
|
97
|
+
|
98
|
+
# from edsl.questions import QuestionBase
|
99
|
+
|
100
|
+
if questions_only:
|
101
|
+
to_iterate_over = self._questions
|
102
|
+
else:
|
103
|
+
to_iterate_over = self.recombined_questions_and_instructions()
|
104
|
+
|
105
|
+
if rename:
|
106
|
+
renaming_dict = {
|
107
|
+
"name": "identifier",
|
108
|
+
"question_name": "identifier",
|
109
|
+
"question_text": "text",
|
110
|
+
}
|
111
|
+
else:
|
112
|
+
renaming_dict = {}
|
113
|
+
|
114
|
+
all_keys = set([])
|
115
|
+
scenarios = ScenarioList()
|
116
|
+
for item in to_iterate_over:
|
117
|
+
d = item.to_dict()
|
118
|
+
if item.__class__.__name__ == "Instruction":
|
119
|
+
d["question_type"] = "NA / instruction"
|
120
|
+
for key in renaming_dict:
|
121
|
+
if key in d:
|
122
|
+
d[renaming_dict[key]] = d.pop(key)
|
123
|
+
all_keys.update(d.keys())
|
124
|
+
scenarios.append(Scenario(d))
|
125
|
+
|
126
|
+
for scenario in scenarios:
|
127
|
+
for key in all_keys:
|
128
|
+
if key not in scenario:
|
129
|
+
scenario[key] = None
|
130
|
+
|
131
|
+
return scenarios
|
132
|
+
|
133
|
+
def code(self, filename: str = None, survey_var_name: str = "survey") -> list[str]:
|
134
|
+
"""Create the Python code representation of a survey.
|
135
|
+
|
136
|
+
:param filename: The name of the file to save the code to.
|
137
|
+
:param survey_var_name: The name of the survey variable.
|
138
|
+
|
139
|
+
>>> from edsl.surveys import Survey
|
140
|
+
>>> survey = Survey.example()
|
141
|
+
>>> print(survey.code())
|
142
|
+
from edsl.surveys.Survey import Survey
|
143
|
+
...
|
144
|
+
...
|
145
|
+
survey = Survey(questions=[q0, q1, q2])
|
146
|
+
...
|
147
|
+
"""
|
148
|
+
import black
|
149
|
+
|
150
|
+
header_lines = ["from edsl.surveys.Survey import Survey"]
|
151
|
+
header_lines.append("from edsl import Question")
|
152
|
+
lines = ["\n".join(header_lines)]
|
153
|
+
for question in self._questions:
|
154
|
+
question.question_text = question["question_text"].replace("\n", " ")
|
155
|
+
# remove dublicate spaces
|
156
|
+
question.question_text = " ".join(question.question_text.split())
|
157
|
+
lines.append(f"{question.question_name} = " + repr(question))
|
158
|
+
lines.append(
|
159
|
+
f"{survey_var_name} = Survey(questions = [{', '.join(self.question_names)}])"
|
160
|
+
)
|
161
|
+
# return lines
|
162
|
+
code_string = "\n".join(lines)
|
163
|
+
formatted_code = black.format_str(code_string, mode=black.FileMode())
|
164
|
+
|
165
|
+
if filename:
|
166
|
+
print("The code has been saved to", filename)
|
167
|
+
print("The survey itself is saved to 'survey' object")
|
168
|
+
with open(filename, "w") as file:
|
169
|
+
file.write(formatted_code)
|
170
|
+
return
|
171
|
+
|
172
|
+
return formatted_code
|
173
|
+
|
174
|
+
def html(
|
175
|
+
self,
|
176
|
+
scenario: Optional[dict] = None,
|
177
|
+
filename: Optional[str] = None,
|
178
|
+
return_link=False,
|
179
|
+
css: Optional[str] = None,
|
180
|
+
cta: Optional[str] = "Open HTML file",
|
181
|
+
include_question_name=False,
|
182
|
+
):
|
183
|
+
from IPython.display import display, HTML
|
184
|
+
import tempfile
|
185
|
+
import os
|
186
|
+
from edsl.utilities.utilities import is_notebook
|
187
|
+
|
188
|
+
if scenario is None:
|
189
|
+
scenario = {}
|
190
|
+
|
191
|
+
if css is None:
|
192
|
+
css = self.css()
|
193
|
+
|
194
|
+
if filename is None:
|
195
|
+
current_directory = os.getcwd()
|
196
|
+
filename = tempfile.NamedTemporaryFile(
|
197
|
+
"w", delete=False, suffix=".html", dir=current_directory
|
198
|
+
).name
|
199
|
+
|
200
|
+
html_header = f"""<html>
|
201
|
+
<head><title></title>
|
202
|
+
<style>
|
203
|
+
{ css }
|
204
|
+
</style>
|
205
|
+
</head>
|
206
|
+
<body>
|
207
|
+
<div class="survey_container">
|
208
|
+
"""
|
209
|
+
|
210
|
+
html_footer = """
|
211
|
+
</div>
|
212
|
+
</body>
|
213
|
+
</html>"""
|
214
|
+
|
215
|
+
output = html_header
|
216
|
+
|
217
|
+
with open(filename, "w") as f:
|
218
|
+
f.write(html_header)
|
219
|
+
for question in self._questions:
|
220
|
+
f.write(
|
221
|
+
question.html(
|
222
|
+
scenario=scenario, include_question_name=include_question_name
|
223
|
+
)
|
224
|
+
)
|
225
|
+
output += question.html(
|
226
|
+
scenario=scenario, include_question_name=include_question_name
|
227
|
+
)
|
228
|
+
f.write(html_footer)
|
229
|
+
output += html_footer
|
230
|
+
|
231
|
+
if is_notebook():
|
232
|
+
html_url = f"/files/{filename}"
|
233
|
+
html_link = f'<a href="{html_url}" target="_blank">{cta}</a>'
|
234
|
+
display(HTML(html_link))
|
235
|
+
|
236
|
+
import html
|
237
|
+
|
238
|
+
escaped_output = html.escape(output)
|
239
|
+
iframe = f""""
|
240
|
+
<iframe srcdoc="{ escaped_output }" style="width: 800px; height: 600px;"></iframe>
|
241
|
+
"""
|
242
|
+
display(HTML(iframe))
|
243
|
+
|
244
|
+
else:
|
245
|
+
print(f"Survey saved to {filename}")
|
246
|
+
import webbrowser
|
247
|
+
import os
|
248
|
+
|
249
|
+
webbrowser.open(f"file://{os.path.abspath(filename)}")
|
250
|
+
# webbrowser.open(filename)
|
251
|
+
|
252
|
+
if return_link:
|
253
|
+
return filename
|
254
|
+
|
255
|
+
|
256
|
+
if __name__ == "__main__":
|
257
|
+
import doctest
|
258
|
+
|
259
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|