edsl 0.1.15__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 +45 -10
- edsl/__version__.py +1 -1
- 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 +115 -113
- 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 -206
- 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.15.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 -435
- edsl/jobs/JobsRunner.py +0 -63
- edsl/jobs/JobsRunnerStatusMixin.py +0 -115
- edsl/jobs/base.py +0 -47
- edsl/jobs/buckets.py +0 -178
- edsl/jobs/runners/JobsRunnerDryRun.py +0 -19
- edsl/jobs/runners/JobsRunnerStreaming.py +0 -54
- edsl/jobs/task_management.py +0 -215
- 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.15.dist-info/METADATA +0 -69
- edsl-0.1.15.dist-info/RECORD +0 -142
- /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.15.dist-info → edsl-0.1.40.dist-info}/LICENSE +0 -0
@@ -0,0 +1,263 @@
|
|
1
|
+
"""A Notebook is a utility class that allows you to easily share/pull ipynbs from Coop."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
import json
|
5
|
+
from typing import Dict, List, Optional, Union
|
6
|
+
from uuid import uuid4
|
7
|
+
from edsl.Base import Base
|
8
|
+
from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
|
9
|
+
|
10
|
+
|
11
|
+
class Notebook(Base):
|
12
|
+
"""
|
13
|
+
A Notebook is a utility class that allows you to easily share/pull ipynbs from Coop.
|
14
|
+
"""
|
15
|
+
|
16
|
+
default_name = "notebook"
|
17
|
+
|
18
|
+
def __init__(
|
19
|
+
self,
|
20
|
+
path: Optional[str] = None,
|
21
|
+
data: Optional[Dict] = None,
|
22
|
+
name: Optional[str] = None,
|
23
|
+
):
|
24
|
+
"""
|
25
|
+
Initialize a new Notebook.
|
26
|
+
|
27
|
+
:param data: A dictionary representing the notebook data.
|
28
|
+
This dictionary must conform to the official Jupyter Notebook format, as defined by nbformat.
|
29
|
+
:param path: A filepath from which to load the notebook.
|
30
|
+
If no path is provided, assume this code is run in a notebook and try to load the current notebook from file.
|
31
|
+
:param name: A name for the Notebook.
|
32
|
+
"""
|
33
|
+
import nbformat
|
34
|
+
|
35
|
+
# Load current notebook path as fallback (VS Code only)
|
36
|
+
current_notebook_path = globals().get("__vsc_ipynb_file__")
|
37
|
+
if path is not None:
|
38
|
+
with open(path, mode="r", encoding="utf-8") as f:
|
39
|
+
data = nbformat.read(f, as_version=4)
|
40
|
+
self.data = json.loads(json.dumps(data))
|
41
|
+
elif data is not None:
|
42
|
+
nbformat.validate(data)
|
43
|
+
self.data = data
|
44
|
+
elif current_notebook_path is not None:
|
45
|
+
with open(current_notebook_path, mode="r", encoding="utf-8") as f:
|
46
|
+
data = nbformat.read(f, as_version=4)
|
47
|
+
self.data = json.loads(json.dumps(data))
|
48
|
+
else:
|
49
|
+
# TODO: Support for IDEs other than VSCode
|
50
|
+
raise NotImplementedError(
|
51
|
+
"Cannot create a notebook from within itself in this development environment"
|
52
|
+
)
|
53
|
+
|
54
|
+
# TODO: perhaps add sanity check function
|
55
|
+
# 1. could check if the notebook is a valid notebook
|
56
|
+
# 2. could check notebook uses EDSL
|
57
|
+
# ....
|
58
|
+
|
59
|
+
self.name = name or self.default_name
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def from_script(cls, path: str, name: Optional[str] = None) -> "Notebook":
|
63
|
+
import nbformat
|
64
|
+
|
65
|
+
# Read the script file
|
66
|
+
with open(path, "r") as script_file:
|
67
|
+
script_content = script_file.read()
|
68
|
+
|
69
|
+
# Create a new Jupyter notebook
|
70
|
+
nb = nbformat.v4.new_notebook()
|
71
|
+
|
72
|
+
# Add the script content to the first cell
|
73
|
+
first_cell = nbformat.v4.new_code_cell(script_content)
|
74
|
+
nb.cells.append(first_cell)
|
75
|
+
|
76
|
+
# Create a Notebook instance with the notebook data
|
77
|
+
notebook_instance = cls(nb)
|
78
|
+
|
79
|
+
return notebook_instance
|
80
|
+
|
81
|
+
@classmethod
|
82
|
+
def from_current_script(cls) -> "Notebook":
|
83
|
+
import inspect
|
84
|
+
import os
|
85
|
+
|
86
|
+
# Get the path to the current file
|
87
|
+
current_frame = inspect.currentframe()
|
88
|
+
caller_frame = inspect.getouterframes(current_frame, 2)
|
89
|
+
current_file_path = os.path.abspath(caller_frame[1].filename)
|
90
|
+
|
91
|
+
# Use from_script to create the notebook
|
92
|
+
return cls.from_script(current_file_path)
|
93
|
+
|
94
|
+
def __eq__(self, other):
|
95
|
+
"""
|
96
|
+
Check if two Notebooks are equal.
|
97
|
+
This only checks the notebook data.
|
98
|
+
"""
|
99
|
+
return self.data == other.data
|
100
|
+
|
101
|
+
def __hash__(self) -> int:
|
102
|
+
"""
|
103
|
+
Allow the model to be used as a key in a dictionary.
|
104
|
+
"""
|
105
|
+
from edsl.utilities.utilities import dict_hash
|
106
|
+
|
107
|
+
return dict_hash(self.data["cells"])
|
108
|
+
|
109
|
+
def to_dict(self, add_edsl_version=False) -> dict:
|
110
|
+
"""
|
111
|
+
Serialize to a dictionary.
|
112
|
+
"""
|
113
|
+
d = {"name": self.name, "data": self.data}
|
114
|
+
if add_edsl_version:
|
115
|
+
from edsl import __version__
|
116
|
+
|
117
|
+
d["edsl_version"] = __version__
|
118
|
+
d["edsl_class_name"] = self.__class__.__name__
|
119
|
+
return d
|
120
|
+
|
121
|
+
@classmethod
|
122
|
+
@remove_edsl_version
|
123
|
+
def from_dict(cls, d: Dict) -> "Notebook":
|
124
|
+
"""
|
125
|
+
Convert a dictionary representation of a Notebook to a Notebook object.
|
126
|
+
"""
|
127
|
+
return cls(data=d["data"], name=d["name"])
|
128
|
+
|
129
|
+
def to_file(self, path: str):
|
130
|
+
"""
|
131
|
+
Save the notebook at the specified filepath.
|
132
|
+
"""
|
133
|
+
import nbformat
|
134
|
+
|
135
|
+
nbformat.write(nbformat.from_dict(self.data), fp=path)
|
136
|
+
|
137
|
+
def __repr__(self):
|
138
|
+
"""
|
139
|
+
Return representation of Notebook.
|
140
|
+
"""
|
141
|
+
return f'Notebook(data={self.data}, name="""{self.name}""")'
|
142
|
+
|
143
|
+
def _repr_html_(self):
|
144
|
+
"""
|
145
|
+
Return HTML representation of Notebook.
|
146
|
+
"""
|
147
|
+
from nbconvert import HTMLExporter
|
148
|
+
import nbformat
|
149
|
+
|
150
|
+
notebook = nbformat.from_dict(self.data)
|
151
|
+
html_exporter = HTMLExporter(template_name="basic")
|
152
|
+
(body, _) = html_exporter.from_notebook_node(notebook)
|
153
|
+
return body
|
154
|
+
|
155
|
+
def _table(self) -> tuple[dict, list]:
|
156
|
+
"""
|
157
|
+
Prepare generic table data.
|
158
|
+
"""
|
159
|
+
table_data = []
|
160
|
+
|
161
|
+
notebook_preview = ""
|
162
|
+
for cell in self.data["cells"]:
|
163
|
+
if "source" in cell:
|
164
|
+
notebook_preview += f"{cell['source']}\n"
|
165
|
+
if len(notebook_preview) > 1000:
|
166
|
+
notebook_preview = f"{notebook_preview[:1000]} [...]"
|
167
|
+
break
|
168
|
+
notebook_preview = notebook_preview.rstrip()
|
169
|
+
|
170
|
+
table_data.append(
|
171
|
+
{
|
172
|
+
"Attribute": "name",
|
173
|
+
"Value": repr(self.name),
|
174
|
+
}
|
175
|
+
)
|
176
|
+
table_data.append(
|
177
|
+
{
|
178
|
+
"Attribute": "notebook_preview",
|
179
|
+
"Value": notebook_preview,
|
180
|
+
}
|
181
|
+
)
|
182
|
+
|
183
|
+
column_names = ["Attribute", "Value"]
|
184
|
+
return table_data, column_names
|
185
|
+
|
186
|
+
def rich_print(self) -> "Table":
|
187
|
+
"""
|
188
|
+
Display a Notebook as a rich table.
|
189
|
+
"""
|
190
|
+
from rich.table import Table
|
191
|
+
|
192
|
+
table_data, column_names = self._table()
|
193
|
+
table = Table(title=f"{self.__class__.__name__} Attributes")
|
194
|
+
for column in column_names:
|
195
|
+
table.add_column(column, style="bold")
|
196
|
+
|
197
|
+
for row in table_data:
|
198
|
+
row_data = [row[column] for column in column_names]
|
199
|
+
table.add_row(*row_data)
|
200
|
+
|
201
|
+
return table
|
202
|
+
|
203
|
+
@classmethod
|
204
|
+
def example(cls, randomize: bool = False) -> Notebook:
|
205
|
+
"""
|
206
|
+
Returns an example Notebook instance.
|
207
|
+
|
208
|
+
:param randomize: If True, adds a random string one of the cells' output.
|
209
|
+
"""
|
210
|
+
addition = "" if not randomize else str(uuid4())
|
211
|
+
cells = [
|
212
|
+
{
|
213
|
+
"cell_type": "markdown",
|
214
|
+
"metadata": dict(),
|
215
|
+
"source": "# Test notebook",
|
216
|
+
},
|
217
|
+
{
|
218
|
+
"cell_type": "code",
|
219
|
+
"execution_count": 1,
|
220
|
+
"metadata": dict(),
|
221
|
+
"outputs": [
|
222
|
+
{
|
223
|
+
"name": "stdout",
|
224
|
+
"output_type": "stream",
|
225
|
+
"text": f"Hello world!\n{addition}",
|
226
|
+
}
|
227
|
+
],
|
228
|
+
"source": 'print("Hello world!")',
|
229
|
+
},
|
230
|
+
]
|
231
|
+
data = {
|
232
|
+
"metadata": dict(),
|
233
|
+
"nbformat": 4,
|
234
|
+
"nbformat_minor": 4,
|
235
|
+
"cells": cells,
|
236
|
+
}
|
237
|
+
return cls(data=data)
|
238
|
+
|
239
|
+
def code(self) -> List[str]:
|
240
|
+
"""
|
241
|
+
Return the code that could be used to create this Notebook.
|
242
|
+
"""
|
243
|
+
lines = []
|
244
|
+
lines.append("from edsl import Notebook")
|
245
|
+
lines.append(f'nb = Notebook(data={self.data}, name="""{self.name}""")')
|
246
|
+
return lines
|
247
|
+
|
248
|
+
def to_latex(self, filename: str):
|
249
|
+
"""
|
250
|
+
Convert notebook to LaTeX and create a folder with all necessary components.
|
251
|
+
|
252
|
+
:param filename: Name of the output folder and main tex file (without extension)
|
253
|
+
"""
|
254
|
+
from edsl.notebooks.NotebookToLaTeX import NotebookToLaTeX
|
255
|
+
|
256
|
+
NotebookToLaTeX(self).convert(filename)
|
257
|
+
|
258
|
+
|
259
|
+
if __name__ == "__main__":
|
260
|
+
from edsl import Notebook
|
261
|
+
|
262
|
+
notebook = Notebook.example()
|
263
|
+
assert notebook == notebook.from_dict(notebook.to_dict())
|
@@ -0,0 +1,142 @@
|
|
1
|
+
from typing import Optional, Dict
|
2
|
+
import os
|
3
|
+
import nbformat
|
4
|
+
from nbconvert.exporters import LatexExporter
|
5
|
+
from nbconvert.writers import FilesWriter
|
6
|
+
|
7
|
+
|
8
|
+
class NotebookToLaTeX:
|
9
|
+
"""
|
10
|
+
A class for converting Jupyter notebooks to LaTeX with proper directory structure.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def __init__(self, notebook):
|
14
|
+
"""
|
15
|
+
Initialize with a Notebook instance.
|
16
|
+
|
17
|
+
:param notebook: An instance of the Notebook class
|
18
|
+
"""
|
19
|
+
self.notebook = notebook
|
20
|
+
self.latex_exporter = LatexExporter()
|
21
|
+
self._configure_exporter()
|
22
|
+
|
23
|
+
def _configure_exporter(self):
|
24
|
+
"""Configure the LaTeX exporter with default settings."""
|
25
|
+
self.latex_exporter.exclude_input_prompt = True
|
26
|
+
self.latex_exporter.exclude_output_prompt = True
|
27
|
+
self.latex_exporter.template_name = "classic"
|
28
|
+
|
29
|
+
def _create_makefile(self, filename: str, output_dir: str):
|
30
|
+
"""Create a Makefile for the LaTeX project."""
|
31
|
+
makefile_content = f"""# Makefile for {filename}
|
32
|
+
all: pdf
|
33
|
+
|
34
|
+
pdf: {filename}.pdf
|
35
|
+
|
36
|
+
{filename}.pdf: {filename}.tex
|
37
|
+
\tpdflatex {filename}.tex
|
38
|
+
\tpdflatex {filename}.tex # Run twice for references
|
39
|
+
\tbibtex {filename} # Run bibtex if needed
|
40
|
+
\tpdflatex {filename}.tex # Run one more time for bibtex
|
41
|
+
|
42
|
+
clean:
|
43
|
+
\trm -f *.aux *.log *.out *.toc *.pdf *.bbl *.blg
|
44
|
+
"""
|
45
|
+
makefile_path = os.path.join(output_dir, "Makefile")
|
46
|
+
with open(makefile_path, "w") as f:
|
47
|
+
f.write(makefile_content)
|
48
|
+
|
49
|
+
def _create_readme(self, filename: str, output_dir: str):
|
50
|
+
"""Create a README file with usage instructions."""
|
51
|
+
readme_content = f"""# {filename}
|
52
|
+
|
53
|
+
This folder contains the LaTeX version of your Jupyter notebook.
|
54
|
+
|
55
|
+
Files:
|
56
|
+
- {filename}.tex: Main LaTeX file
|
57
|
+
- Makefile: Build automation
|
58
|
+
|
59
|
+
To compile the PDF:
|
60
|
+
1. Make sure you have a LaTeX distribution installed (e.g., TexLive)
|
61
|
+
2. Run `make` in this directory
|
62
|
+
3. The output will be {filename}.pdf
|
63
|
+
|
64
|
+
To clean up build files:
|
65
|
+
- Run `make clean`
|
66
|
+
"""
|
67
|
+
readme_path = os.path.join(output_dir, "README.md")
|
68
|
+
with open(readme_path, "w") as f:
|
69
|
+
f.write(readme_content)
|
70
|
+
|
71
|
+
def convert(self, filename: str, output_dir: Optional[str] = None):
|
72
|
+
"""
|
73
|
+
Convert the notebook to LaTeX and create a project directory.
|
74
|
+
|
75
|
+
:param filename: Name for the output files (without extension)
|
76
|
+
:param output_dir: Optional directory path. If None, uses filename as directory
|
77
|
+
"""
|
78
|
+
# Use filename as directory if no output_dir specified
|
79
|
+
output_dir = output_dir or filename
|
80
|
+
|
81
|
+
# Create output directory
|
82
|
+
os.makedirs(output_dir, exist_ok=True)
|
83
|
+
|
84
|
+
# Convert notebook to nbformat
|
85
|
+
notebook_node = nbformat.from_dict(self.notebook.data)
|
86
|
+
|
87
|
+
# Convert to LaTeX
|
88
|
+
body, resources = self.latex_exporter.from_notebook_node(notebook_node)
|
89
|
+
|
90
|
+
# Write the main tex file
|
91
|
+
output_file_path = os.path.join(output_dir, f"{filename}.tex")
|
92
|
+
with open(output_file_path, "w", encoding="utf-8") as f:
|
93
|
+
f.write(body)
|
94
|
+
|
95
|
+
# Write additional resources (images, etc.)
|
96
|
+
if resources.get("outputs"):
|
97
|
+
for fname, data in resources["outputs"].items():
|
98
|
+
resource_path = os.path.join(output_dir, fname)
|
99
|
+
with open(resource_path, "wb") as f:
|
100
|
+
f.write(data)
|
101
|
+
|
102
|
+
# Create supporting files
|
103
|
+
self._create_makefile(filename, output_dir)
|
104
|
+
self._create_readme(filename, output_dir)
|
105
|
+
|
106
|
+
def set_template(self, template_name: str):
|
107
|
+
"""
|
108
|
+
Set the LaTeX template to use.
|
109
|
+
|
110
|
+
:param template_name: Name of the template (e.g., 'classic', 'article')
|
111
|
+
"""
|
112
|
+
self.latex_exporter.template_name = template_name
|
113
|
+
|
114
|
+
def set_template_options(self, options: Dict):
|
115
|
+
"""
|
116
|
+
Set additional template options.
|
117
|
+
|
118
|
+
:param options: Dictionary of template options
|
119
|
+
"""
|
120
|
+
for key, value in options.items():
|
121
|
+
setattr(self.latex_exporter, key, value)
|
122
|
+
|
123
|
+
|
124
|
+
# Example usage:
|
125
|
+
if __name__ == "__main__":
|
126
|
+
from edsl import Notebook
|
127
|
+
|
128
|
+
# Create or load a notebook
|
129
|
+
notebook = Notebook.example()
|
130
|
+
|
131
|
+
# Create converter and convert
|
132
|
+
converter = NotebookToLaTeX(notebook)
|
133
|
+
converter.convert("example_output")
|
134
|
+
|
135
|
+
# Example with custom template options
|
136
|
+
converter.set_template_options(
|
137
|
+
{
|
138
|
+
"exclude_input": True, # Hide input cells
|
139
|
+
"exclude_output": False, # Show output cells
|
140
|
+
}
|
141
|
+
)
|
142
|
+
converter.convert("example_output_custom")
|
@@ -0,0 +1 @@
|
|
1
|
+
from edsl.notebooks.Notebook import Notebook
|