edsl 0.1.14__py3-none-any.whl → 0.1.40__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 +348 -38
- edsl/BaseDiff.py +260 -0
- edsl/TemplateLoader.py +24 -0
- edsl/__init__.py +46 -10
- edsl/__version__.py +1 -0
- edsl/agents/Agent.py +842 -144
- edsl/agents/AgentList.py +521 -25
- edsl/agents/Invigilator.py +250 -374
- edsl/agents/InvigilatorBase.py +257 -0
- edsl/agents/PromptConstructor.py +272 -0
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/descriptors.py +43 -13
- edsl/agents/prompt_helpers.py +129 -0
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -0
- edsl/auto/StageBase.py +243 -0
- edsl/auto/StageGenerateSurvey.py +178 -0
- edsl/auto/StageLabelQuestions.py +125 -0
- edsl/auto/StagePersona.py +61 -0
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -0
- edsl/auto/StagePersonaDimensionValues.py +74 -0
- edsl/auto/StagePersonaDimensions.py +69 -0
- edsl/auto/StageQuestions.py +74 -0
- edsl/auto/SurveyCreatorPipeline.py +21 -0
- edsl/auto/utilities.py +218 -0
- edsl/base/Base.py +279 -0
- edsl/config.py +121 -104
- edsl/conversation/Conversation.py +290 -0
- edsl/conversation/car_buying.py +59 -0
- edsl/conversation/chips.py +95 -0
- edsl/conversation/mug_negotiation.py +81 -0
- edsl/conversation/next_speaker_utilities.py +93 -0
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -0
- edsl/coop/__init__.py +1 -0
- edsl/coop/coop.py +1029 -134
- edsl/coop/utils.py +131 -0
- edsl/data/Cache.py +560 -89
- edsl/data/CacheEntry.py +230 -0
- edsl/data/CacheHandler.py +168 -0
- edsl/data/RemoteCacheSync.py +186 -0
- edsl/data/SQLiteDict.py +292 -0
- edsl/data/__init__.py +5 -3
- edsl/data/orm.py +6 -33
- edsl/data_transfer_models.py +74 -27
- edsl/enums.py +165 -8
- edsl/exceptions/BaseException.py +21 -0
- edsl/exceptions/__init__.py +52 -46
- edsl/exceptions/agents.py +33 -15
- edsl/exceptions/cache.py +5 -0
- edsl/exceptions/coop.py +8 -0
- edsl/exceptions/general.py +34 -0
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +15 -0
- edsl/exceptions/language_models.py +46 -1
- edsl/exceptions/questions.py +80 -5
- edsl/exceptions/results.py +16 -5
- edsl/exceptions/scenarios.py +29 -0
- edsl/exceptions/surveys.py +13 -10
- edsl/inference_services/AnthropicService.py +106 -0
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -0
- edsl/inference_services/AzureAI.py +215 -0
- edsl/inference_services/DeepInfraService.py +18 -0
- edsl/inference_services/GoogleService.py +143 -0
- edsl/inference_services/GroqService.py +20 -0
- edsl/inference_services/InferenceServiceABC.py +80 -0
- edsl/inference_services/InferenceServicesCollection.py +138 -0
- edsl/inference_services/MistralAIService.py +120 -0
- edsl/inference_services/OllamaService.py +18 -0
- edsl/inference_services/OpenAIService.py +236 -0
- edsl/inference_services/PerplexityService.py +160 -0
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -0
- edsl/inference_services/TogetherAIService.py +172 -0
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -0
- edsl/inference_services/rate_limits_cache.py +25 -0
- edsl/inference_services/registry.py +41 -0
- edsl/inference_services/write_available.py +10 -0
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +21 -20
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +684 -204
- edsl/jobs/JobsChecks.py +172 -0
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -0
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -0
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -0
- edsl/jobs/buckets/ModelBuckets.py +65 -0
- edsl/jobs/buckets/TokenBucket.py +283 -0
- 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 +392 -0
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -0
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -0
- edsl/jobs/interviews/InterviewStatistic.py +63 -0
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -0
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -0
- edsl/jobs/interviews/InterviewStatusLog.py +92 -0
- edsl/jobs/interviews/ReportErrors.py +66 -0
- edsl/jobs/interviews/interview_status_enum.py +9 -0
- 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 -110
- edsl/jobs/runners/JobsRunnerStatus.py +298 -0
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -0
- edsl/jobs/tasks/TaskCreators.py +64 -0
- edsl/jobs/tasks/TaskHistory.py +470 -0
- edsl/jobs/tasks/TaskStatusLog.py +23 -0
- edsl/jobs/tasks/task_status_enum.py +161 -0
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -0
- edsl/jobs/tokens/TokenUsage.py +34 -0
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +507 -386
- edsl/language_models/ModelList.py +164 -0
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -0
- edsl/language_models/__init__.py +1 -8
- edsl/language_models/fake_openai_call.py +15 -0
- edsl/language_models/fake_openai_service.py +61 -0
- 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 +109 -41
- edsl/language_models/utilities.py +65 -0
- edsl/notebooks/Notebook.py +263 -0
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -0
- edsl/prompts/Prompt.py +222 -93
- edsl/prompts/__init__.py +1 -1
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -0
- edsl/questions/QuestionBasePromptsMixin.py +221 -0
- edsl/questions/QuestionBudget.py +164 -67
- edsl/questions/QuestionCheckBox.py +281 -62
- edsl/questions/QuestionDict.py +343 -0
- edsl/questions/QuestionExtract.py +136 -50
- edsl/questions/QuestionFreeText.py +79 -55
- edsl/questions/QuestionFunctional.py +138 -41
- edsl/questions/QuestionList.py +184 -57
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +293 -69
- edsl/questions/QuestionNumerical.py +109 -56
- edsl/questions/QuestionRank.py +244 -49
- edsl/questions/Quick.py +41 -0
- edsl/questions/SimpleAskMixin.py +74 -0
- edsl/questions/__init__.py +9 -6
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +153 -38
- edsl/questions/compose_questions.py +13 -7
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -0
- edsl/questions/derived/QuestionLikertFive.py +28 -26
- edsl/questions/derived/QuestionLinearScale.py +41 -28
- edsl/questions/derived/QuestionTopK.py +34 -26
- edsl/questions/derived/QuestionYesNo.py +40 -27
- edsl/questions/descriptors.py +228 -74
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -0
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -0
- edsl/questions/prompt_templates/question_extract.jinja +11 -0
- edsl/questions/prompt_templates/question_free_text.jinja +3 -0
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -0
- edsl/questions/prompt_templates/question_list.jinja +17 -0
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -0
- edsl/questions/prompt_templates/question_numerical.jinja +37 -0
- edsl/questions/question_base_gen_mixin.py +168 -0
- edsl/questions/question_registry.py +130 -46
- edsl/questions/register_questions_meta.py +71 -0
- edsl/questions/response_validator_abc.py +188 -0
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +5 -2
- edsl/questions/templates/__init__.py +0 -0
- edsl/questions/templates/budget/__init__.py +0 -0
- edsl/questions/templates/budget/answering_instructions.jinja +7 -0
- edsl/questions/templates/budget/question_presentation.jinja +7 -0
- edsl/questions/templates/checkbox/__init__.py +0 -0
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -0
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -0
- edsl/questions/templates/dict/__init__.py +0 -0
- edsl/questions/templates/dict/answering_instructions.jinja +21 -0
- edsl/questions/templates/dict/question_presentation.jinja +1 -0
- edsl/questions/templates/extract/__init__.py +0 -0
- edsl/questions/templates/extract/answering_instructions.jinja +7 -0
- edsl/questions/templates/extract/question_presentation.jinja +1 -0
- edsl/questions/templates/free_text/__init__.py +0 -0
- edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
- edsl/questions/templates/free_text/question_presentation.jinja +1 -0
- edsl/questions/templates/likert_five/__init__.py +0 -0
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -0
- edsl/questions/templates/likert_five/question_presentation.jinja +12 -0
- edsl/questions/templates/linear_scale/__init__.py +0 -0
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -0
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -0
- edsl/questions/templates/list/__init__.py +0 -0
- edsl/questions/templates/list/answering_instructions.jinja +4 -0
- edsl/questions/templates/list/question_presentation.jinja +5 -0
- edsl/questions/templates/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/__init__.py +0 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -0
- edsl/questions/templates/multiple_choice/html.jinja +0 -0
- edsl/questions/templates/multiple_choice/question_presentation.jinja +12 -0
- edsl/questions/templates/numerical/__init__.py +0 -0
- edsl/questions/templates/numerical/answering_instructions.jinja +7 -0
- edsl/questions/templates/numerical/question_presentation.jinja +7 -0
- edsl/questions/templates/rank/__init__.py +0 -0
- edsl/questions/templates/rank/answering_instructions.jinja +11 -0
- edsl/questions/templates/rank/question_presentation.jinja +15 -0
- edsl/questions/templates/top_k/__init__.py +0 -0
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -0
- edsl/questions/templates/top_k/question_presentation.jinja +22 -0
- edsl/questions/templates/yes_no/__init__.py +0 -0
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -0
- edsl/questions/templates/yes_no/question_presentation.jinja +12 -0
- edsl/results/CSSParameterizer.py +108 -0
- edsl/results/Dataset.py +550 -19
- edsl/results/DatasetExportMixin.py +594 -0
- edsl/results/DatasetTree.py +295 -0
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +477 -173
- edsl/results/Results.py +987 -269
- edsl/results/ResultsExportMixin.py +28 -125
- edsl/results/ResultsGGMixin.py +83 -15
- edsl/results/TableDisplay.py +125 -0
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +1 -1
- edsl/results/file_exports.py +252 -0
- edsl/results/results_fetch_mixin.py +33 -0
- edsl/results/results_selector.py +145 -0
- edsl/results/results_tools_mixin.py +98 -0
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +78 -0
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -0
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +543 -0
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +431 -62
- edsl/scenarios/ScenarioHtmlMixin.py +65 -0
- edsl/scenarios/ScenarioList.py +1415 -45
- edsl/scenarios/ScenarioListExportMixin.py +45 -0
- edsl/scenarios/ScenarioListPdfMixin.py +239 -0
- edsl/scenarios/__init__.py +2 -0
- 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 +49 -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/scenario_join.py +131 -0
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -0
- edsl/study/ObjectEntry.py +173 -0
- edsl/study/ProofOfWork.py +113 -0
- edsl/study/SnapShot.py +80 -0
- edsl/study/Study.py +521 -0
- edsl/study/__init__.py +4 -0
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +92 -11
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +9 -4
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +156 -35
- edsl/surveys/Rule.py +221 -74
- edsl/surveys/RuleCollection.py +241 -61
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1079 -339
- edsl/surveys/SurveyCSS.py +273 -0
- edsl/surveys/SurveyExportMixin.py +235 -40
- edsl/surveys/SurveyFlowVisualization.py +181 -0
- edsl/surveys/SurveyQualtricsImport.py +284 -0
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +4 -2
- edsl/surveys/base.py +19 -3
- edsl/surveys/descriptors.py +17 -6
- edsl/surveys/instructions/ChangeInstruction.py +48 -0
- edsl/surveys/instructions/Instruction.py +56 -0
- edsl/surveys/instructions/InstructionCollection.py +82 -0
- edsl/surveys/instructions/__init__.py +0 -0
- edsl/templates/error_reporting/base.html +24 -0
- edsl/templates/error_reporting/exceptions_by_model.html +35 -0
- edsl/templates/error_reporting/exceptions_by_question_name.html +17 -0
- edsl/templates/error_reporting/exceptions_by_type.html +17 -0
- edsl/templates/error_reporting/interview_details.html +116 -0
- edsl/templates/error_reporting/interviews.html +19 -0
- edsl/templates/error_reporting/overview.html +5 -0
- edsl/templates/error_reporting/performance_plot.html +2 -0
- edsl/templates/error_reporting/report.css +74 -0
- edsl/templates/error_reporting/report.html +118 -0
- edsl/templates/error_reporting/report.js +25 -0
- edsl/tools/__init__.py +1 -0
- edsl/tools/clusters.py +192 -0
- edsl/tools/embeddings.py +27 -0
- edsl/tools/embeddings_plotting.py +118 -0
- edsl/tools/plotting.py +112 -0
- edsl/tools/summarize.py +18 -0
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +5 -0
- edsl/utilities/__init__.py +21 -20
- edsl/utilities/ast_utilities.py +3 -0
- edsl/utilities/data/Registry.py +2 -0
- edsl/utilities/decorators.py +41 -0
- edsl/utilities/gcp_bucket/__init__.py +0 -0
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
- edsl/utilities/interface.py +310 -60
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -0
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -0
- edsl/utilities/restricted_python.py +70 -0
- edsl/utilities/utilities.py +203 -13
- edsl-0.1.40.dist-info/METADATA +111 -0
- edsl-0.1.40.dist-info/RECORD +362 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/WHEEL +1 -1
- edsl/agents/AgentListExportMixin.py +0 -24
- edsl/coop/old.py +0 -31
- edsl/data/Database.py +0 -141
- edsl/data/crud.py +0 -121
- edsl/jobs/Interview.py +0 -417
- edsl/jobs/JobsRunner.py +0 -63
- edsl/jobs/JobsRunnerStatusMixin.py +0 -115
- edsl/jobs/base.py +0 -47
- edsl/jobs/buckets.py +0 -166
- edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
- edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
- edsl/jobs/task_management.py +0 -218
- edsl/jobs/token_tracking.py +0 -78
- edsl/language_models/DeepInfra.py +0 -69
- edsl/language_models/OpenAI.py +0 -98
- edsl/language_models/model_interfaces/GeminiPro.py +0 -66
- edsl/language_models/model_interfaces/LanguageModelOpenAIFour.py +0 -8
- edsl/language_models/model_interfaces/LanguageModelOpenAIThreeFiveTurbo.py +0 -8
- edsl/language_models/model_interfaces/LlamaTwo13B.py +0 -21
- edsl/language_models/model_interfaces/LlamaTwo70B.py +0 -21
- edsl/language_models/model_interfaces/Mixtral8x7B.py +0 -24
- edsl/language_models/registry.py +0 -81
- edsl/language_models/schemas.py +0 -15
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/prompts/QuestionInstructionsBase.py +0 -6
- edsl/prompts/library/agent_instructions.py +0 -29
- edsl/prompts/library/agent_persona.py +0 -17
- edsl/prompts/library/question_budget.py +0 -26
- edsl/prompts/library/question_checkbox.py +0 -32
- edsl/prompts/library/question_extract.py +0 -19
- edsl/prompts/library/question_freetext.py +0 -14
- edsl/prompts/library/question_linear_scale.py +0 -20
- edsl/prompts/library/question_list.py +0 -22
- edsl/prompts/library/question_multiple_choice.py +0 -44
- edsl/prompts/library/question_numerical.py +0 -31
- edsl/prompts/library/question_rank.py +0 -21
- edsl/prompts/prompt_config.py +0 -33
- edsl/prompts/registry.py +0 -185
- edsl/questions/Question.py +0 -240
- edsl/report/InputOutputDataTypes.py +0 -134
- edsl/report/RegressionMixin.py +0 -28
- edsl/report/ReportOutputs.py +0 -1228
- edsl/report/ResultsFetchMixin.py +0 -106
- edsl/report/ResultsOutputMixin.py +0 -14
- edsl/report/demo.ipynb +0 -645
- edsl/results/ResultsDBMixin.py +0 -184
- edsl/surveys/SurveyFlowVisualizationMixin.py +0 -92
- edsl/trackers/Tracker.py +0 -91
- edsl/trackers/TrackerAPI.py +0 -196
- edsl/trackers/TrackerTasks.py +0 -70
- edsl/utilities/pastebin.py +0 -141
- edsl-0.1.14.dist-info/METADATA +0 -69
- edsl-0.1.14.dist-info/RECORD +0 -141
- /edsl/{language_models/model_interfaces → inference_services}/__init__.py +0 -0
- /edsl/{report/__init__.py → jobs/runners/JobsRunnerStatusData.py} +0 -0
- /edsl/{trackers/__init__.py → language_models/ServiceDataSources.py} +0 -0
- {edsl-0.1.14.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -1,142 +1,45 @@
|
|
1
|
-
|
2
|
-
import csv
|
3
|
-
import io
|
4
|
-
from IPython.display import HTML, display
|
5
|
-
import pandas as pd
|
6
|
-
from edsl.utilities import (
|
7
|
-
print_list_of_dicts_with_rich,
|
8
|
-
print_list_of_dicts_as_html_table,
|
9
|
-
print_dict_with_rich,
|
10
|
-
)
|
1
|
+
"""Mixin class for exporting results."""
|
11
2
|
|
3
|
+
from functools import wraps
|
4
|
+
from typing import Literal, Optional, Union
|
12
5
|
|
13
|
-
|
14
|
-
def convert_decorator(func):
|
15
|
-
def wrapper(self, *args, **kwargs):
|
16
|
-
if self.__class__.__name__ == "Results":
|
17
|
-
return func(self.select(), *args, **kwargs)
|
18
|
-
elif self.__class__.__name__ == "Dataset":
|
19
|
-
return func(self, *args, **kwargs)
|
20
|
-
else:
|
21
|
-
raise Exception(
|
22
|
-
f"Class {self.__class__.__name__} not recognized as a Results or Dataset object."
|
23
|
-
)
|
6
|
+
from edsl.results.DatasetExportMixin import DatasetExportMixin
|
24
7
|
|
25
|
-
return wrapper
|
26
8
|
|
27
|
-
|
28
|
-
|
29
|
-
"Helper function that turns the results into a tabular format."
|
30
|
-
d = {}
|
31
|
-
full_header = sorted(list(self.relevant_columns()))
|
32
|
-
for entry in self.data:
|
33
|
-
key, list_of_values = list(entry.items())[0]
|
34
|
-
d[key] = list_of_values
|
35
|
-
if remove_prefix:
|
36
|
-
header = [h.split(".")[-1] for h in full_header]
|
37
|
-
else:
|
38
|
-
header = full_header
|
39
|
-
num_observations = len(list(self[0].values())[0])
|
40
|
-
rows = []
|
41
|
-
# rows.append(header)
|
42
|
-
for i in range(num_observations):
|
43
|
-
row = [d[h][i] for h in full_header]
|
44
|
-
rows.append(row)
|
45
|
-
return header, rows
|
46
|
-
|
47
|
-
def print_long(self):
|
48
|
-
""" """
|
49
|
-
for result in self:
|
50
|
-
if hasattr(result, "combined_dict"):
|
51
|
-
d = result.combined_dict
|
52
|
-
else:
|
53
|
-
d = result
|
54
|
-
print_dict_with_rich(d)
|
55
|
-
|
56
|
-
@convert_decorator
|
57
|
-
def print(
|
58
|
-
self,
|
59
|
-
pretty_labels=None,
|
60
|
-
filename=None,
|
61
|
-
html=False,
|
62
|
-
interactive=False,
|
63
|
-
split_at_dot=True,
|
64
|
-
):
|
65
|
-
if pretty_labels is None:
|
66
|
-
pretty_labels = {}
|
9
|
+
def to_dataset(func):
|
10
|
+
"""Convert the Results object to a Dataset object before calling the function."""
|
67
11
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
12
|
+
@wraps(func)
|
13
|
+
def wrapper(self, *args, **kwargs):
|
14
|
+
"""Return the function with the Results object converted to a Dataset object."""
|
15
|
+
if self.__class__.__name__ == "Results":
|
16
|
+
return func(self.select(), *args, **kwargs)
|
17
|
+
elif self.__class__.__name__ == "AgentList":
|
18
|
+
return func(self.to_dataset(), *args, **kwargs)
|
72
19
|
else:
|
73
|
-
|
74
|
-
print_list_of_dicts_with_rich(
|
75
|
-
new_data, filename=filename, split_at_dot=split_at_dot
|
76
|
-
)
|
77
|
-
else:
|
78
|
-
print_list_of_dicts_as_html_table(
|
79
|
-
new_data, filename=None, interactive=interactive
|
80
|
-
)
|
20
|
+
return func(self, *args, **kwargs)
|
81
21
|
|
82
|
-
|
83
|
-
|
84
|
-
"""
|
85
|
-
>>> r = create_example_results()
|
86
|
-
>>> r.select('how_feeling').to_csv()
|
87
|
-
'result.how_feeling\\r\\nBad\\r\\nBad\\r\\nGreat\\r\\nGreat\\r\\n'
|
88
|
-
"""
|
89
|
-
header, rows = self._make_tabular(remove_prefix)
|
22
|
+
wrapper._is_wrapped = True
|
23
|
+
return wrapper
|
90
24
|
|
91
|
-
if filename is not None:
|
92
|
-
with open(filename, "w") as f:
|
93
|
-
writer = csv.writer(f)
|
94
|
-
writer.writerow(header)
|
95
|
-
writer.writerows(rows)
|
96
|
-
else:
|
97
|
-
output = io.StringIO()
|
98
|
-
writer = csv.writer(output)
|
99
|
-
writer.writerow(header)
|
100
|
-
writer.writerows(rows)
|
101
25
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
else:
|
108
|
-
return output.getvalue()
|
26
|
+
def decorate_methods_from_mixin(cls, mixin_cls):
|
27
|
+
for attr_name, attr_value in mixin_cls.__dict__.items():
|
28
|
+
if callable(attr_value) and not attr_name.startswith("__"):
|
29
|
+
setattr(cls, attr_name, to_dataset(attr_value))
|
30
|
+
return cls
|
109
31
|
|
110
|
-
@convert_decorator
|
111
|
-
def to_pandas(self, remove_prefix=False):
|
112
|
-
csv_string = self.to_csv(remove_prefix=remove_prefix)
|
113
|
-
csv_buffer = io.StringIO(csv_string)
|
114
|
-
df = pd.read_csv(csv_buffer)
|
115
|
-
df_sorted = df.sort_index(axis=1) # Sort columns alphabetically
|
116
|
-
return df_sorted
|
117
|
-
# return df
|
118
32
|
|
119
|
-
|
120
|
-
|
121
|
-
df = self.to_pandas(remove_prefix=remove_prefix)
|
122
|
-
df = df.convert_dtypes()
|
123
|
-
list_of_dicts = df.to_dict(orient="records")
|
124
|
-
# Convert any pd.NA values to None
|
125
|
-
list_of_dicts = [
|
126
|
-
{k: (None if pd.isna(v) else v) for k, v in record.items()}
|
127
|
-
for record in list_of_dicts
|
128
|
-
]
|
129
|
-
return list_of_dicts
|
33
|
+
class ResultsExportMixin(DatasetExportMixin):
|
34
|
+
"""Mixin class for exporting Results objects."""
|
130
35
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
return list(self[0].values())[0]
|
135
|
-
else:
|
136
|
-
return tuple([list(x.values())[0] for x in self])
|
36
|
+
def __init_subclass__(cls, **kwargs):
|
37
|
+
super().__init_subclass__(**kwargs)
|
38
|
+
decorate_methods_from_mixin(cls, DatasetExportMixin)
|
137
39
|
|
138
40
|
|
139
41
|
if __name__ == "__main__":
|
42
|
+
# pass
|
140
43
|
import doctest
|
141
44
|
|
142
|
-
doctest.testmod()
|
45
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|
edsl/results/ResultsGGMixin.py
CHANGED
@@ -1,17 +1,47 @@
|
|
1
|
+
"""Mixin class for ggplot2 plotting."""
|
2
|
+
|
1
3
|
import subprocess
|
2
|
-
import pandas as pd
|
3
4
|
import tempfile
|
4
|
-
|
5
|
-
import matplotlib.image as mpimg
|
5
|
+
from typing import Optional
|
6
6
|
|
7
7
|
|
8
8
|
class ResultsGGMixin:
|
9
|
-
|
10
|
-
|
9
|
+
"""Mixin class for ggplot2 plotting."""
|
10
|
+
|
11
|
+
def ggplot2(
|
12
|
+
self,
|
13
|
+
ggplot_code: str,
|
14
|
+
filename: str = None,
|
15
|
+
shape="wide",
|
16
|
+
sql: str = None,
|
17
|
+
remove_prefix: bool = True,
|
18
|
+
debug: bool = False,
|
19
|
+
height=4,
|
20
|
+
width=6,
|
21
|
+
format="svg",
|
22
|
+
factor_orders: Optional[dict] = None,
|
23
|
+
):
|
24
|
+
"""Create a ggplot2 plot from a DataFrame.
|
25
|
+
|
26
|
+
:param ggplot_code: The ggplot2 code to execute.
|
27
|
+
:param filename: The filename to save the plot to.
|
28
|
+
:param shape: The shape of the data in the DataFrame (wide or long).
|
29
|
+
:param sql: The SQL query to execute beforehand to manipulate the data.
|
30
|
+
:param remove_prefix: Whether to remove the prefix from the column names.
|
31
|
+
:param debug: Whether to print the R code instead of executing it.
|
32
|
+
:param height: The height of the plot in inches.
|
33
|
+
:param width: The width of the plot in inches.
|
34
|
+
:param format: The format to save the plot in (png or svg).
|
35
|
+
:param factor_orders: A dictionary of factor columns and their order.
|
36
|
+
"""
|
37
|
+
|
38
|
+
if sql == None:
|
39
|
+
sql = "select * from self"
|
40
|
+
|
11
41
|
if shape == "long":
|
12
|
-
df = self.sql(
|
42
|
+
df = self.sql(sql, shape="long")
|
13
43
|
elif shape == "wide":
|
14
|
-
df = self.sql(
|
44
|
+
df = self.sql(sql, shape="wide", remove_prefix=remove_prefix)
|
15
45
|
|
16
46
|
# Convert DataFrame to CSV format
|
17
47
|
csv_data = df.to_csv(index=False)
|
@@ -20,18 +50,32 @@ class ResultsGGMixin:
|
|
20
50
|
csv_data_escaped = csv_data.replace("\n", "\\n").replace("'", "\\'")
|
21
51
|
read_csv_code = f"self <- read.csv(text = '{csv_data_escaped}', sep = ',')\n"
|
22
52
|
|
53
|
+
if factor_orders is not None:
|
54
|
+
for factor, order in factor_orders.items():
|
55
|
+
# read_csv_code += f"""self${{{factor}}} <- factor(self${{{factor}}}, levels=c({','.join(['"{}"'.format(x) for x in order])}))"""
|
56
|
+
|
57
|
+
level_string = ", ".join([f'"{x}"' for x in order])
|
58
|
+
read_csv_code += (
|
59
|
+
f"self${factor} <- factor(self${factor}, levels=c({level_string}))"
|
60
|
+
)
|
61
|
+
read_csv_code += "\n"
|
62
|
+
|
23
63
|
# Load ggplot2 library
|
24
64
|
load_ggplot2 = "library(ggplot2)\n"
|
25
65
|
|
26
66
|
# Check if a filename is provided for the plot, if not create a temporary one
|
27
67
|
if not filename:
|
28
|
-
filename = tempfile.mktemp(suffix=".
|
68
|
+
filename = tempfile.mktemp(suffix=f".{format}")
|
29
69
|
|
30
70
|
# Combine all R script parts
|
31
71
|
full_r_code = load_ggplot2 + read_csv_code + ggplot_code
|
32
72
|
|
33
73
|
# Add command to save the plot to a file
|
34
|
-
full_r_code += f'\nggsave("{filename}", plot = last_plot(), width =
|
74
|
+
full_r_code += f'\nggsave("{filename}", plot = last_plot(), width = {width}, height = {height}, device = "{format}")'
|
75
|
+
|
76
|
+
if debug:
|
77
|
+
print(full_r_code)
|
78
|
+
return
|
35
79
|
|
36
80
|
result = subprocess.run(
|
37
81
|
["Rscript", "-"],
|
@@ -41,13 +85,37 @@ class ResultsGGMixin:
|
|
41
85
|
stderr=subprocess.PIPE,
|
42
86
|
)
|
43
87
|
|
88
|
+
if result.returncode != 0:
|
89
|
+
if result.returncode == 127: # 'command not found'
|
90
|
+
raise RuntimeError(
|
91
|
+
"Rscript is probably not installed. Please install R from https://cran.r-project.org/"
|
92
|
+
)
|
93
|
+
else:
|
94
|
+
raise RuntimeError(
|
95
|
+
f"An error occurred while running Rscript: {result.stderr}"
|
96
|
+
)
|
97
|
+
|
44
98
|
if result.stderr:
|
45
99
|
print("Error in R script:", result.stderr)
|
46
100
|
else:
|
47
|
-
self._display_plot(filename)
|
101
|
+
self._display_plot(filename, width, height)
|
48
102
|
|
49
|
-
def _display_plot(self, filename):
|
50
|
-
|
51
|
-
plt
|
52
|
-
|
53
|
-
|
103
|
+
def _display_plot(self, filename: str, width: float, height: float):
|
104
|
+
"""Display the plot in the notebook."""
|
105
|
+
import matplotlib.pyplot as plt
|
106
|
+
import matplotlib.image as mpimg
|
107
|
+
|
108
|
+
if filename.endswith(".png"):
|
109
|
+
img = mpimg.imread(filename)
|
110
|
+
plt.figure(
|
111
|
+
figsize=(width, height)
|
112
|
+
) # Set the figure size (width, height) in inches
|
113
|
+
plt.imshow(img)
|
114
|
+
plt.axis("off")
|
115
|
+
plt.show()
|
116
|
+
elif filename.endswith(".svg"):
|
117
|
+
from IPython.display import SVG, display
|
118
|
+
|
119
|
+
display(SVG(filename=filename))
|
120
|
+
else:
|
121
|
+
print("Unsupported file format. Please provide a PNG or SVG file.")
|
@@ -0,0 +1,125 @@
|
|
1
|
+
from typing import (
|
2
|
+
Protocol,
|
3
|
+
List,
|
4
|
+
Any,
|
5
|
+
Optional,
|
6
|
+
TYPE_CHECKING,
|
7
|
+
Sequence,
|
8
|
+
Union,
|
9
|
+
Literal,
|
10
|
+
)
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from edsl.results.Dataset import Dataset
|
14
|
+
|
15
|
+
from edsl.results.table_data_class import TableData
|
16
|
+
|
17
|
+
from edsl.results.table_renderers import DataTablesRenderer, PandasStyleRenderer
|
18
|
+
|
19
|
+
Row = Sequence[Union[str, int, float, bool, None]]
|
20
|
+
TableFormat = Literal[
|
21
|
+
"grid", "simple", "pipe", "orgtbl", "rst", "mediawiki", "html", "latex"
|
22
|
+
]
|
23
|
+
|
24
|
+
|
25
|
+
class TableRenderer(Protocol):
|
26
|
+
"""Table renderer protocol"""
|
27
|
+
|
28
|
+
def render_html(self, table_data: TableData) -> str:
|
29
|
+
pass
|
30
|
+
|
31
|
+
|
32
|
+
# Modified TableDisplay class
|
33
|
+
class TableDisplay:
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
headers: Sequence[str],
|
37
|
+
data: Sequence[Row],
|
38
|
+
tablefmt: Optional[TableFormat] = None,
|
39
|
+
raw_data_set: "Dataset" = None,
|
40
|
+
renderer_class: Optional[TableRenderer] = None,
|
41
|
+
):
|
42
|
+
assert len(headers) == len(data[0]) # Check if headers and data are consistent
|
43
|
+
|
44
|
+
self.headers = headers
|
45
|
+
self.data = data
|
46
|
+
self.tablefmt = tablefmt
|
47
|
+
self.raw_data_set = raw_data_set
|
48
|
+
|
49
|
+
self.renderer_class = renderer_class or PandasStyleRenderer
|
50
|
+
|
51
|
+
# Handle printing parameters from raw_data_set
|
52
|
+
if hasattr(raw_data_set, "print_parameters"):
|
53
|
+
self.printing_parameters = (
|
54
|
+
raw_data_set.print_parameters if raw_data_set.print_parameters else {}
|
55
|
+
)
|
56
|
+
else:
|
57
|
+
self.printing_parameters = {}
|
58
|
+
|
59
|
+
def _repr_html_(self) -> str:
|
60
|
+
table_data = TableData(
|
61
|
+
headers=self.headers,
|
62
|
+
data=self.data,
|
63
|
+
parameters=self.printing_parameters,
|
64
|
+
raw_data_set=self.raw_data_set,
|
65
|
+
)
|
66
|
+
return self.renderer_class(table_data).render_html()
|
67
|
+
|
68
|
+
def __repr__(self):
|
69
|
+
from tabulate import tabulate
|
70
|
+
|
71
|
+
return tabulate(self.data, headers=self.headers, tablefmt=self.tablefmt)
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def from_dictionary(
|
75
|
+
cls,
|
76
|
+
dictionary: dict,
|
77
|
+
tablefmt: Optional[TableFormat] = None,
|
78
|
+
renderer: Optional[TableRenderer] = None,
|
79
|
+
) -> "TableDisplay":
|
80
|
+
headers = list(dictionary.keys())
|
81
|
+
data = [list(dictionary.values())]
|
82
|
+
return cls(headers, data, tablefmt, renderer_class=renderer)
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def from_dictionary_wide(
|
86
|
+
cls,
|
87
|
+
dictionary: dict,
|
88
|
+
tablefmt: Optional[TableFormat] = None,
|
89
|
+
renderer: Optional[TableRenderer] = None,
|
90
|
+
) -> "TableDisplay":
|
91
|
+
headers = ["key", "value"]
|
92
|
+
data = [[k, v] for k, v in dictionary.items()]
|
93
|
+
return cls(headers, data, tablefmt, renderer_class=renderer)
|
94
|
+
|
95
|
+
@classmethod
|
96
|
+
def from_dataset(
|
97
|
+
cls,
|
98
|
+
dataset: "Dataset",
|
99
|
+
tablefmt: Optional[TableFormat] = None,
|
100
|
+
renderer: Optional[TableRenderer] = None,
|
101
|
+
) -> "TableDisplay":
|
102
|
+
headers, data = dataset._tabular()
|
103
|
+
return cls(headers, data, tablefmt, dataset, renderer_class=renderer)
|
104
|
+
|
105
|
+
def long(self) -> "TableDisplay":
|
106
|
+
"""Convert to long format"""
|
107
|
+
new_header = ["row", "key", "value"]
|
108
|
+
new_data = []
|
109
|
+
for index, row in enumerate(self.data):
|
110
|
+
new_data.extend([[index, k, v] for k, v in zip(self.headers, row)])
|
111
|
+
return TableDisplay(
|
112
|
+
new_header, new_data, self.tablefmt, renderer_class=self.renderer_class
|
113
|
+
)
|
114
|
+
|
115
|
+
|
116
|
+
# Example usage:
|
117
|
+
if __name__ == "__main__":
|
118
|
+
headers = ["Name", "Age", "City"]
|
119
|
+
data = [["John", 30, "New York"], ["Jane", 25, "London"]]
|
120
|
+
|
121
|
+
# Using default (Pandas) renderer
|
122
|
+
table1 = TableDisplay(headers, data)
|
123
|
+
|
124
|
+
# Using DataTables renderer
|
125
|
+
table2 = TableDisplay(headers, data, renderer=DataTablesRenderer())
|
@@ -0,0 +1,50 @@
|
|
1
|
+
try:
|
2
|
+
import gradio as gr
|
3
|
+
except ImportError:
|
4
|
+
print("Gradio is not installed. Please install it using `pip install gradio`")
|
5
|
+
|
6
|
+
import time
|
7
|
+
|
8
|
+
|
9
|
+
class TextEditor:
|
10
|
+
def __init__(self, initial_text=""):
|
11
|
+
self.text = initial_text
|
12
|
+
self._text_saved = False
|
13
|
+
|
14
|
+
def save_text(self, new_text):
|
15
|
+
self.text = new_text
|
16
|
+
self._text_saved = True
|
17
|
+
return "Text saved successfully!"
|
18
|
+
|
19
|
+
def edit_gui(self):
|
20
|
+
js_code = """
|
21
|
+
async (text) => {
|
22
|
+
await navigator.clipboard.writeText(text);
|
23
|
+
return "Copied to clipboard!";
|
24
|
+
}
|
25
|
+
"""
|
26
|
+
|
27
|
+
with gr.Blocks() as interface:
|
28
|
+
text_area = gr.Textbox(
|
29
|
+
value=self.text, lines=10, label="Edit Text", placeholder="Type here..."
|
30
|
+
)
|
31
|
+
|
32
|
+
with gr.Row():
|
33
|
+
save_btn = gr.Button("Save")
|
34
|
+
copy_btn = gr.Button("Copy to Clipboard")
|
35
|
+
|
36
|
+
output = gr.Textbox(label="Status")
|
37
|
+
|
38
|
+
save_btn.click(fn=self.save_text, inputs=[text_area], outputs=[output])
|
39
|
+
|
40
|
+
# Add copy functionality
|
41
|
+
copy_btn.click(
|
42
|
+
fn=None, inputs=text_area, outputs=output, api_name=False, js=js_code
|
43
|
+
)
|
44
|
+
|
45
|
+
interface.launch(share=False, prevent_thread_lock=True)
|
46
|
+
|
47
|
+
while not self._text_saved:
|
48
|
+
time.sleep(0.1)
|
49
|
+
|
50
|
+
return self.text
|
edsl/results/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from edsl.results.Result import Result
|
1
|
+
# from edsl.results.Result import Result
|
2
2
|
from edsl.results.Results import Results
|