edsl 0.1.49__py3-none-any.whl → 0.1.51__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/__init__.py +124 -53
- edsl/__version__.py +1 -1
- edsl/agents/agent.py +21 -21
- edsl/agents/agent_list.py +2 -5
- edsl/agents/exceptions.py +119 -5
- edsl/base/__init__.py +10 -35
- edsl/base/base_class.py +71 -36
- edsl/base/base_exception.py +204 -0
- edsl/base/data_transfer_models.py +1 -1
- edsl/base/exceptions.py +94 -0
- edsl/buckets/__init__.py +15 -1
- edsl/buckets/bucket_collection.py +3 -4
- edsl/buckets/exceptions.py +107 -0
- edsl/buckets/model_buckets.py +1 -2
- edsl/buckets/token_bucket.py +11 -6
- edsl/buckets/token_bucket_api.py +27 -12
- edsl/buckets/token_bucket_client.py +9 -7
- edsl/caching/cache.py +12 -4
- edsl/caching/cache_entry.py +10 -9
- edsl/caching/exceptions.py +113 -7
- edsl/caching/remote_cache_sync.py +6 -7
- edsl/caching/sql_dict.py +20 -14
- edsl/cli.py +43 -0
- edsl/config/__init__.py +1 -1
- edsl/config/config_class.py +32 -6
- edsl/conversation/Conversation.py +8 -4
- edsl/conversation/car_buying.py +1 -3
- edsl/conversation/exceptions.py +58 -0
- edsl/conversation/mug_negotiation.py +2 -8
- edsl/coop/__init__.py +28 -6
- edsl/coop/coop.py +120 -29
- edsl/coop/coop_functions.py +1 -1
- edsl/coop/ep_key_handling.py +1 -1
- edsl/coop/exceptions.py +188 -9
- edsl/coop/price_fetcher.py +5 -8
- edsl/coop/utils.py +4 -6
- edsl/dataset/__init__.py +5 -4
- edsl/dataset/dataset.py +177 -86
- edsl/dataset/dataset_operations_mixin.py +98 -76
- edsl/dataset/dataset_tree.py +11 -7
- edsl/dataset/display/table_display.py +0 -2
- edsl/dataset/display/table_renderers.py +6 -4
- edsl/dataset/exceptions.py +125 -0
- edsl/dataset/file_exports.py +18 -11
- edsl/dataset/r/ggplot.py +13 -6
- edsl/display/__init__.py +27 -0
- edsl/display/core.py +147 -0
- edsl/display/plugin.py +189 -0
- edsl/display/utils.py +52 -0
- edsl/inference_services/__init__.py +9 -1
- edsl/inference_services/available_model_cache_handler.py +1 -1
- edsl/inference_services/available_model_fetcher.py +5 -6
- edsl/inference_services/data_structures.py +10 -7
- edsl/inference_services/exceptions.py +132 -1
- edsl/inference_services/inference_service_abc.py +2 -2
- edsl/inference_services/inference_services_collection.py +2 -6
- edsl/inference_services/registry.py +4 -3
- edsl/inference_services/service_availability.py +4 -3
- edsl/inference_services/services/anthropic_service.py +4 -1
- edsl/inference_services/services/aws_bedrock.py +13 -12
- edsl/inference_services/services/azure_ai.py +12 -10
- edsl/inference_services/services/deep_infra_service.py +1 -4
- edsl/inference_services/services/deep_seek_service.py +1 -5
- edsl/inference_services/services/google_service.py +7 -3
- edsl/inference_services/services/groq_service.py +1 -1
- edsl/inference_services/services/mistral_ai_service.py +4 -2
- edsl/inference_services/services/ollama_service.py +1 -1
- edsl/inference_services/services/open_ai_service.py +7 -5
- edsl/inference_services/services/perplexity_service.py +6 -2
- edsl/inference_services/services/test_service.py +8 -7
- edsl/inference_services/services/together_ai_service.py +2 -3
- edsl/inference_services/services/xai_service.py +1 -1
- edsl/instructions/__init__.py +1 -1
- edsl/instructions/change_instruction.py +7 -5
- edsl/instructions/exceptions.py +61 -0
- edsl/instructions/instruction.py +6 -2
- edsl/instructions/instruction_collection.py +6 -4
- edsl/instructions/instruction_handler.py +12 -15
- edsl/interviews/ReportErrors.py +0 -3
- edsl/interviews/__init__.py +9 -2
- edsl/interviews/answering_function.py +11 -13
- edsl/interviews/exception_tracking.py +15 -8
- edsl/interviews/exceptions.py +79 -0
- edsl/interviews/interview.py +33 -30
- edsl/interviews/interview_status_dictionary.py +4 -2
- edsl/interviews/interview_status_log.py +2 -1
- edsl/interviews/interview_task_manager.py +5 -5
- edsl/interviews/request_token_estimator.py +5 -2
- edsl/interviews/statistics.py +3 -4
- edsl/invigilators/__init__.py +7 -1
- edsl/invigilators/exceptions.py +79 -0
- edsl/invigilators/invigilator_base.py +0 -1
- edsl/invigilators/invigilators.py +9 -13
- edsl/invigilators/prompt_constructor.py +1 -5
- edsl/invigilators/prompt_helpers.py +8 -4
- edsl/invigilators/question_instructions_prompt_builder.py +1 -1
- edsl/invigilators/question_option_processor.py +9 -5
- edsl/invigilators/question_template_replacements_builder.py +3 -2
- edsl/jobs/__init__.py +42 -5
- edsl/jobs/async_interview_runner.py +25 -23
- edsl/jobs/check_survey_scenario_compatibility.py +11 -10
- edsl/jobs/data_structures.py +8 -5
- edsl/jobs/exceptions.py +177 -8
- edsl/jobs/fetch_invigilator.py +1 -1
- edsl/jobs/jobs.py +74 -69
- edsl/jobs/jobs_checks.py +6 -7
- edsl/jobs/jobs_component_constructor.py +4 -4
- edsl/jobs/jobs_pricing_estimation.py +4 -3
- edsl/jobs/jobs_remote_inference_logger.py +5 -4
- edsl/jobs/jobs_runner_asyncio.py +3 -4
- edsl/jobs/jobs_runner_status.py +8 -9
- edsl/jobs/remote_inference.py +27 -24
- edsl/jobs/results_exceptions_handler.py +10 -7
- edsl/key_management/__init__.py +3 -1
- edsl/key_management/exceptions.py +62 -0
- edsl/key_management/key_lookup.py +1 -1
- edsl/key_management/key_lookup_builder.py +37 -14
- edsl/key_management/key_lookup_collection.py +2 -0
- edsl/language_models/__init__.py +1 -1
- edsl/language_models/exceptions.py +302 -14
- edsl/language_models/language_model.py +9 -8
- edsl/language_models/model.py +4 -4
- edsl/language_models/model_list.py +1 -1
- edsl/language_models/price_manager.py +1 -1
- edsl/language_models/raw_response_handler.py +14 -9
- edsl/language_models/registry.py +17 -21
- edsl/language_models/repair.py +0 -6
- edsl/language_models/unused/fake_openai_service.py +0 -1
- edsl/load_plugins.py +69 -0
- edsl/logger.py +146 -0
- edsl/notebooks/__init__.py +24 -1
- edsl/notebooks/exceptions.py +82 -0
- edsl/notebooks/notebook.py +7 -3
- edsl/notebooks/notebook_to_latex.py +1 -2
- edsl/plugins/__init__.py +63 -0
- edsl/plugins/built_in/export_example.py +50 -0
- edsl/plugins/built_in/pig_latin.py +67 -0
- edsl/plugins/cli.py +372 -0
- edsl/plugins/cli_typer.py +283 -0
- edsl/plugins/exceptions.py +31 -0
- edsl/plugins/hookspec.py +51 -0
- edsl/plugins/plugin_host.py +128 -0
- edsl/plugins/plugin_manager.py +633 -0
- edsl/plugins/plugins_registry.py +168 -0
- edsl/prompts/__init__.py +24 -1
- edsl/prompts/exceptions.py +107 -5
- edsl/prompts/prompt.py +15 -7
- edsl/questions/HTMLQuestion.py +5 -11
- edsl/questions/Quick.py +0 -1
- edsl/questions/__init__.py +6 -4
- edsl/questions/answer_validator_mixin.py +318 -323
- edsl/questions/compose_questions.py +3 -3
- edsl/questions/descriptors.py +11 -50
- edsl/questions/exceptions.py +278 -22
- edsl/questions/loop_processor.py +7 -5
- edsl/questions/prompt_templates/question_list.jinja +3 -0
- edsl/questions/question_base.py +46 -19
- edsl/questions/question_base_gen_mixin.py +2 -2
- edsl/questions/question_base_prompts_mixin.py +13 -7
- edsl/questions/question_budget.py +503 -98
- edsl/questions/question_check_box.py +660 -160
- edsl/questions/question_dict.py +345 -194
- edsl/questions/question_extract.py +401 -61
- edsl/questions/question_free_text.py +80 -14
- edsl/questions/question_functional.py +119 -9
- edsl/questions/{derived/question_likert_five.py → question_likert_five.py} +2 -2
- edsl/questions/{derived/question_linear_scale.py → question_linear_scale.py} +3 -4
- edsl/questions/question_list.py +275 -28
- edsl/questions/question_matrix.py +643 -96
- edsl/questions/question_multiple_choice.py +219 -51
- edsl/questions/question_numerical.py +361 -32
- edsl/questions/question_rank.py +401 -124
- edsl/questions/question_registry.py +7 -5
- edsl/questions/{derived/question_top_k.py → question_top_k.py} +3 -3
- edsl/questions/{derived/question_yes_no.py → question_yes_no.py} +3 -4
- edsl/questions/register_questions_meta.py +2 -2
- edsl/questions/response_validator_abc.py +13 -15
- edsl/questions/response_validator_factory.py +10 -12
- edsl/questions/templates/dict/answering_instructions.jinja +1 -0
- edsl/questions/templates/rank/question_presentation.jinja +1 -1
- edsl/results/__init__.py +1 -1
- edsl/results/exceptions.py +141 -7
- edsl/results/report.py +1 -2
- edsl/results/result.py +11 -9
- edsl/results/results.py +480 -321
- edsl/results/results_selector.py +8 -4
- edsl/scenarios/PdfExtractor.py +2 -2
- edsl/scenarios/construct_download_link.py +69 -35
- edsl/scenarios/directory_scanner.py +33 -14
- edsl/scenarios/document_chunker.py +1 -1
- edsl/scenarios/exceptions.py +238 -14
- edsl/scenarios/file_methods.py +1 -1
- edsl/scenarios/file_store.py +7 -3
- edsl/scenarios/handlers/__init__.py +17 -0
- edsl/scenarios/handlers/docx_file_store.py +0 -5
- edsl/scenarios/handlers/pdf_file_store.py +0 -1
- edsl/scenarios/handlers/pptx_file_store.py +0 -5
- edsl/scenarios/handlers/py_file_store.py +0 -1
- edsl/scenarios/handlers/sql_file_store.py +1 -4
- edsl/scenarios/handlers/sqlite_file_store.py +0 -1
- edsl/scenarios/handlers/txt_file_store.py +1 -1
- edsl/scenarios/scenario.py +1 -3
- edsl/scenarios/scenario_list.py +179 -27
- edsl/scenarios/scenario_list_pdf_tools.py +1 -0
- edsl/scenarios/scenario_selector.py +0 -1
- edsl/surveys/__init__.py +3 -4
- edsl/surveys/dag/__init__.py +4 -2
- edsl/surveys/descriptors.py +1 -1
- edsl/surveys/edit_survey.py +1 -0
- edsl/surveys/exceptions.py +165 -9
- edsl/surveys/memory/__init__.py +5 -3
- edsl/surveys/memory/memory_management.py +1 -0
- edsl/surveys/memory/memory_plan.py +6 -15
- edsl/surveys/rules/__init__.py +5 -3
- edsl/surveys/rules/rule.py +1 -2
- edsl/surveys/rules/rule_collection.py +1 -1
- edsl/surveys/survey.py +12 -24
- edsl/surveys/survey_css.py +3 -3
- edsl/surveys/survey_export.py +6 -3
- edsl/surveys/survey_flow_visualization.py +10 -1
- edsl/surveys/survey_simulator.py +2 -1
- edsl/tasks/__init__.py +23 -1
- edsl/tasks/exceptions.py +72 -0
- edsl/tasks/question_task_creator.py +3 -3
- edsl/tasks/task_creators.py +1 -3
- edsl/tasks/task_history.py +8 -10
- edsl/tasks/task_status_log.py +1 -2
- edsl/tokens/__init__.py +29 -1
- edsl/tokens/exceptions.py +37 -0
- edsl/tokens/interview_token_usage.py +3 -2
- edsl/tokens/token_usage.py +4 -3
- edsl/utilities/__init__.py +21 -1
- edsl/utilities/decorators.py +1 -2
- edsl/utilities/markdown_to_docx.py +2 -2
- edsl/utilities/markdown_to_pdf.py +1 -1
- edsl/utilities/repair_functions.py +0 -1
- edsl/utilities/restricted_python.py +0 -1
- edsl/utilities/template_loader.py +2 -3
- edsl/utilities/utilities.py +8 -29
- {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/METADATA +32 -2
- edsl-0.1.51.dist-info/RECORD +365 -0
- edsl-0.1.51.dist-info/entry_points.txt +3 -0
- edsl/dataset/smart_objects.py +0 -96
- edsl/exceptions/BaseException.py +0 -21
- edsl/exceptions/__init__.py +0 -54
- edsl/exceptions/configuration.py +0 -16
- edsl/exceptions/general.py +0 -34
- edsl/questions/derived/__init__.py +0 -0
- edsl/study/ObjectEntry.py +0 -173
- edsl/study/ProofOfWork.py +0 -113
- edsl/study/SnapShot.py +0 -80
- edsl/study/Study.py +0 -520
- edsl/study/__init__.py +0 -6
- edsl/utilities/interface.py +0 -135
- edsl-0.1.49.dist-info/RECORD +0 -347
- {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/LICENSE +0 -0
- {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/WHEEL +0 -0
edsl/load_plugins.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
def load_plugins():
|
4
|
+
"""
|
5
|
+
Load plugins for EDSL.
|
6
|
+
|
7
|
+
This function handles the discovery and loading of plugins via the pluggy library.
|
8
|
+
It searches for entry points registered under the "edsl" namespace.
|
9
|
+
"""
|
10
|
+
logger = logging.getLogger("edsl")
|
11
|
+
|
12
|
+
try:
|
13
|
+
logger.info("Loading plugins")
|
14
|
+
import pluggy
|
15
|
+
import pkg_resources
|
16
|
+
|
17
|
+
logger.info("Available edsl entrypoints: %s", [ep for ep in pkg_resources.iter_entry_points("edsl")])
|
18
|
+
|
19
|
+
# Import hook specs from the plugin system
|
20
|
+
from edsl.plugins.hookspec import EDSLPluginSpec
|
21
|
+
|
22
|
+
# Create plugin manager and register specs
|
23
|
+
pm = pluggy.PluginManager("edsl")
|
24
|
+
pm.add_hookspecs(EDSLPluginSpec)
|
25
|
+
|
26
|
+
# Load all plugins
|
27
|
+
logger.info("Loading setuptools entrypoints...")
|
28
|
+
pm.load_setuptools_entrypoints("edsl")
|
29
|
+
|
30
|
+
# Get registered plugins
|
31
|
+
registered_plugins = [
|
32
|
+
plugin_name
|
33
|
+
for plugin_name, _ in pm.list_name_plugin()
|
34
|
+
if plugin_name != "EDSLHookSpecs"
|
35
|
+
]
|
36
|
+
logger.info("Registered plugins: %s", registered_plugins)
|
37
|
+
|
38
|
+
# Get plugins and add to __all__
|
39
|
+
logger.info("Calling edsl_plugin hook...")
|
40
|
+
try:
|
41
|
+
results = pm.hook.edsl_plugin()
|
42
|
+
logger.info("Results: %s", results)
|
43
|
+
plugins = {}
|
44
|
+
|
45
|
+
if results:
|
46
|
+
for plugin in results:
|
47
|
+
if hasattr(plugin, "__name__"):
|
48
|
+
plugin_name = plugin.__name__
|
49
|
+
elif hasattr(plugin, "__class__"):
|
50
|
+
plugin_name = plugin.__class__.__name__
|
51
|
+
else:
|
52
|
+
plugin_name = f"Plugin_{len(plugins)}"
|
53
|
+
|
54
|
+
logger.info(f"Loaded plugin: {plugin_name}")
|
55
|
+
plugins[plugin_name] = plugin
|
56
|
+
|
57
|
+
return plugins
|
58
|
+
except Exception as e:
|
59
|
+
logger.error("Error calling edsl_plugin hook: %s", e)
|
60
|
+
except ImportError as e:
|
61
|
+
# pluggy not available
|
62
|
+
logger.info("pluggy not available, skipping plugin loading: %s", e)
|
63
|
+
logger.debug("pluggy not available, skipping plugin loading: %s", e)
|
64
|
+
except Exception as e:
|
65
|
+
# Error loading plugins
|
66
|
+
logger.error("Error loading plugins: %s", e)
|
67
|
+
logger.debug("Error loading plugins: %s", e)
|
68
|
+
|
69
|
+
return {}
|
edsl/logger.py
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
"""
|
2
|
+
Logger module for EDSL.
|
3
|
+
|
4
|
+
This module provides a centralized logging configuration for the EDSL package.
|
5
|
+
It configures console and file logging with appropriate formatting.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import logging
|
9
|
+
import os
|
10
|
+
import sys
|
11
|
+
from logging.handlers import RotatingFileHandler
|
12
|
+
from pathlib import Path
|
13
|
+
|
14
|
+
# Create the logger
|
15
|
+
logger = logging.getLogger("edsl")
|
16
|
+
logger.setLevel(logging.ERROR) # Default level
|
17
|
+
|
18
|
+
# Avoid adding handlers multiple times when imported in different modules
|
19
|
+
if not logger.handlers:
|
20
|
+
# Console handler removed - logs only go to file now
|
21
|
+
|
22
|
+
# File handler - create logs directory if it doesn't exist
|
23
|
+
try:
|
24
|
+
log_dir = Path.home() / ".edsl" / "logs"
|
25
|
+
os.makedirs(log_dir, exist_ok=True)
|
26
|
+
|
27
|
+
file_handler = RotatingFileHandler(
|
28
|
+
log_dir / "edsl.log", maxBytes=5 * 1024 * 1024, backupCount=3 # 5 MB
|
29
|
+
)
|
30
|
+
file_handler.setLevel(logging.ERROR)
|
31
|
+
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
32
|
+
file_handler.setFormatter(file_formatter)
|
33
|
+
logger.addHandler(file_handler)
|
34
|
+
except Exception as e:
|
35
|
+
# Don't fail if file logging can't be set up
|
36
|
+
# No console handler to adjust
|
37
|
+
print(f"WARNING: Could not set up file logging: {e}")
|
38
|
+
|
39
|
+
|
40
|
+
def get_logger(name):
|
41
|
+
"""
|
42
|
+
Get a logger for a specific module.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
name: Usually __name__ of the module
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
A Logger instance configured with the EDSL settings
|
49
|
+
"""
|
50
|
+
return logging.getLogger(f"edsl.{name}")
|
51
|
+
|
52
|
+
|
53
|
+
def set_level(level):
|
54
|
+
"""
|
55
|
+
Set the logging level for the EDSL logger.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
level: A logging level (e.g., logging.DEBUG, logging.INFO, etc.)
|
59
|
+
"""
|
60
|
+
logger.setLevel(level)
|
61
|
+
for handler in logger.handlers:
|
62
|
+
handler.setLevel(level)
|
63
|
+
|
64
|
+
# Update child loggers
|
65
|
+
for logger_name in logging.root.manager.loggerDict:
|
66
|
+
if logger_name.startswith("edsl."):
|
67
|
+
logging.getLogger(logger_name).setLevel(level)
|
68
|
+
|
69
|
+
|
70
|
+
# Convenience function to avoid importing logging in every file
|
71
|
+
def debug(msg, *args, **kwargs):
|
72
|
+
logger.debug(msg, *args, **kwargs)
|
73
|
+
|
74
|
+
|
75
|
+
def info(msg, *args, **kwargs):
|
76
|
+
logger.info(msg, *args, **kwargs)
|
77
|
+
|
78
|
+
|
79
|
+
def warning(msg, *args, **kwargs):
|
80
|
+
logger.warning(msg, *args, **kwargs)
|
81
|
+
|
82
|
+
|
83
|
+
def error(msg, *args, **kwargs):
|
84
|
+
logger.error(msg, *args, **kwargs)
|
85
|
+
|
86
|
+
|
87
|
+
def critical(msg, *args, **kwargs):
|
88
|
+
logger.critical(msg, *args, **kwargs)
|
89
|
+
|
90
|
+
|
91
|
+
def exception(msg, *args, **kwargs):
|
92
|
+
"""Log an exception with traceback at the ERROR level"""
|
93
|
+
logger.exception(msg, *args, **kwargs)
|
94
|
+
|
95
|
+
|
96
|
+
def configure_from_config():
|
97
|
+
"""
|
98
|
+
Configure logging based on EDSL_LOG_LEVEL environment variable or config.
|
99
|
+
|
100
|
+
This function looks for the EDSL_LOG_LEVEL setting in the config and sets
|
101
|
+
the logging level accordingly. Valid values are:
|
102
|
+
- DEBUG
|
103
|
+
- INFO
|
104
|
+
- WARNING
|
105
|
+
- ERROR
|
106
|
+
- CRITICAL
|
107
|
+
If no configuration is found, the default level (ERROR) is maintained.
|
108
|
+
|
109
|
+
"""
|
110
|
+
try:
|
111
|
+
import os
|
112
|
+
|
113
|
+
# First check environment variable
|
114
|
+
log_level = os.environ.get("EDSL_LOG_LEVEL")
|
115
|
+
|
116
|
+
# If not in environment, try to get from config
|
117
|
+
if not log_level:
|
118
|
+
try:
|
119
|
+
from edsl.config import CONFIG
|
120
|
+
|
121
|
+
log_level = CONFIG.EDSL_LOG_LEVEL
|
122
|
+
except (ImportError, AttributeError):
|
123
|
+
# Config might not be available or doesn't have EDSL_LOG_LEVEL
|
124
|
+
pass
|
125
|
+
|
126
|
+
if log_level:
|
127
|
+
# Convert to uppercase to match logging constants
|
128
|
+
log_level = log_level.upper()
|
129
|
+
|
130
|
+
# Map string to logging level
|
131
|
+
level_map = {
|
132
|
+
"DEBUG": logging.DEBUG,
|
133
|
+
"INFO": logging.INFO,
|
134
|
+
"WARNING": logging.WARNING,
|
135
|
+
"ERROR": logging.ERROR,
|
136
|
+
"CRITICAL": logging.CRITICAL,
|
137
|
+
}
|
138
|
+
|
139
|
+
if log_level in level_map:
|
140
|
+
set_level(level_map[log_level])
|
141
|
+
info(f"Log level set to {log_level} from configuration")
|
142
|
+
else:
|
143
|
+
warning(f"Invalid log level in configuration: {log_level}")
|
144
|
+
except Exception as e:
|
145
|
+
# Catch any exceptions to ensure logging configuration doesn't break the application
|
146
|
+
warning(f"Error configuring logging from config: {e}")
|
edsl/notebooks/__init__.py
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
"""
|
2
|
+
The notebooks module provides tools for working with Jupyter notebooks.
|
3
|
+
|
4
|
+
It includes classes for notebook creation, manipulation, and conversion
|
5
|
+
to other formats such as LaTeX.
|
6
|
+
"""
|
7
|
+
|
1
8
|
from .notebook import Notebook
|
9
|
+
from .notebook_to_latex import NotebookToLaTeX
|
10
|
+
from .exceptions import (
|
11
|
+
NotebookError,
|
12
|
+
NotebookValueError,
|
13
|
+
NotebookFormatError,
|
14
|
+
NotebookConversionError,
|
15
|
+
NotebookEnvironmentError,
|
16
|
+
)
|
2
17
|
|
3
|
-
__all__ = [
|
18
|
+
__all__ = [
|
19
|
+
"Notebook",
|
20
|
+
"NotebookToLaTeX",
|
21
|
+
"NotebookError",
|
22
|
+
"NotebookValueError",
|
23
|
+
"NotebookFormatError",
|
24
|
+
"NotebookConversionError",
|
25
|
+
"NotebookEnvironmentError",
|
26
|
+
]
|
@@ -0,0 +1,82 @@
|
|
1
|
+
"""
|
2
|
+
Custom exceptions for the notebooks module.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from ..base import BaseException
|
6
|
+
|
7
|
+
|
8
|
+
class NotebookError(BaseException):
|
9
|
+
"""
|
10
|
+
Base exception class for all notebook-related errors.
|
11
|
+
|
12
|
+
This is the parent class for all exceptions related to notebook
|
13
|
+
operations, including creation, validation, and conversion.
|
14
|
+
"""
|
15
|
+
relevant_doc = "https://docs.expectedparrot.com/"
|
16
|
+
|
17
|
+
|
18
|
+
class NotebookValueError(NotebookError):
|
19
|
+
"""
|
20
|
+
Exception raised when an invalid value is provided to a notebook method.
|
21
|
+
|
22
|
+
This exception occurs when attempting to create or modify a notebook
|
23
|
+
with invalid values, such as:
|
24
|
+
- Invalid data format
|
25
|
+
- Incompatible notebook contents
|
26
|
+
|
27
|
+
Examples:
|
28
|
+
```python
|
29
|
+
# Attempting to create a notebook with invalid data
|
30
|
+
notebook = Notebook(data=invalid_data) # Raises NotebookValueError
|
31
|
+
```
|
32
|
+
"""
|
33
|
+
relevant_doc = "https://docs.expectedparrot.com/"
|
34
|
+
|
35
|
+
|
36
|
+
class NotebookFormatError(NotebookError):
|
37
|
+
"""
|
38
|
+
Exception raised when a notebook's format is invalid.
|
39
|
+
|
40
|
+
This exception occurs when the notebook structure does not conform
|
41
|
+
to the expected Jupyter Notebook format.
|
42
|
+
|
43
|
+
Examples:
|
44
|
+
```python
|
45
|
+
# Attempting to load a notebook with invalid format
|
46
|
+
notebook = Notebook.from_dict(invalid_dict) # Raises NotebookFormatError
|
47
|
+
```
|
48
|
+
"""
|
49
|
+
relevant_doc = "https://docs.expectedparrot.com/"
|
50
|
+
|
51
|
+
|
52
|
+
class NotebookConversionError(NotebookError):
|
53
|
+
"""
|
54
|
+
Exception raised when a notebook conversion fails.
|
55
|
+
|
56
|
+
This exception occurs when attempting to convert a notebook to another
|
57
|
+
format (like LaTeX) and the conversion process fails.
|
58
|
+
|
59
|
+
Examples:
|
60
|
+
```python
|
61
|
+
# Attempting to convert a notebook to LaTeX with invalid options
|
62
|
+
notebook.to_latex(invalid_options) # Raises NotebookConversionError
|
63
|
+
```
|
64
|
+
"""
|
65
|
+
relevant_doc = "https://docs.expectedparrot.com/"
|
66
|
+
|
67
|
+
|
68
|
+
class NotebookEnvironmentError(NotebookError):
|
69
|
+
"""
|
70
|
+
Exception raised when the notebook environment is not supportable.
|
71
|
+
|
72
|
+
This exception occurs when attempting to create a notebook in an
|
73
|
+
environment that doesn't provide required context, such as when
|
74
|
+
trying to create a notebook from within itself outside of VS Code.
|
75
|
+
|
76
|
+
Examples:
|
77
|
+
```python
|
78
|
+
# Attempting to create a notebook from within itself in an unsupported IDE
|
79
|
+
notebook = Notebook() # Raises NotebookEnvironmentError
|
80
|
+
```
|
81
|
+
"""
|
82
|
+
relevant_doc = "https://docs.expectedparrot.com/"
|
edsl/notebooks/notebook.py
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
import json
|
5
|
-
from typing import Dict, List, Optional,
|
5
|
+
from typing import Dict, List, Optional, TYPE_CHECKING
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
from rich.table import Table
|
6
9
|
from uuid import uuid4
|
7
10
|
|
8
11
|
from ..base import Base
|
@@ -47,7 +50,8 @@ class Notebook(Base):
|
|
47
50
|
self.data = json.loads(json.dumps(data))
|
48
51
|
else:
|
49
52
|
# TODO: Support for IDEs other than VSCode
|
50
|
-
|
53
|
+
from .exceptions import NotebookEnvironmentError
|
54
|
+
raise NotebookEnvironmentError(
|
51
55
|
"Cannot create a notebook from within itself in this development environment"
|
52
56
|
)
|
53
57
|
|
@@ -251,7 +255,7 @@ class Notebook(Base):
|
|
251
255
|
|
252
256
|
:param filename: Name of the output folder and main tex file (without extension)
|
253
257
|
"""
|
254
|
-
from .
|
258
|
+
from .notebook_to_latex import NotebookToLaTeX
|
255
259
|
|
256
260
|
NotebookToLaTeX(self).convert(filename)
|
257
261
|
|
@@ -2,7 +2,6 @@ from typing import Optional, Dict
|
|
2
2
|
import os
|
3
3
|
import nbformat
|
4
4
|
from nbconvert.exporters import LatexExporter
|
5
|
-
from nbconvert.writers import FilesWriter
|
6
5
|
|
7
6
|
|
8
7
|
class NotebookToLaTeX:
|
@@ -123,7 +122,7 @@ To clean up build files:
|
|
123
122
|
|
124
123
|
# Example usage:
|
125
124
|
if __name__ == "__main__":
|
126
|
-
from
|
125
|
+
from .. import Notebook
|
127
126
|
|
128
127
|
# Create or load a notebook
|
129
128
|
notebook = Notebook.example()
|
edsl/plugins/__init__.py
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
"""EDSL Plugins module for extending functionality with custom plugins."""
|
2
|
+
|
3
|
+
# Import for public API
|
4
|
+
from .plugin_host import PluginHost, get_plugin_manager
|
5
|
+
from .exceptions import (
|
6
|
+
PluginException,
|
7
|
+
PluginNotFoundError,
|
8
|
+
PluginInstallationError,
|
9
|
+
GitHubRepoError,
|
10
|
+
InvalidPluginError,
|
11
|
+
PluginMethodError,
|
12
|
+
PluginDependencyError
|
13
|
+
)
|
14
|
+
from .cli import PluginCLI
|
15
|
+
# Import the Typer CLI
|
16
|
+
from .cli_typer import app as typer_app
|
17
|
+
|
18
|
+
# Public API functions
|
19
|
+
def install_from_github(github_url, branch=None):
|
20
|
+
"""Install a plugin from a GitHub repository."""
|
21
|
+
return PluginHost.install_from_github(github_url, branch)
|
22
|
+
|
23
|
+
def uninstall_plugin(plugin_name):
|
24
|
+
"""Uninstall a plugin by name."""
|
25
|
+
return PluginHost.uninstall_plugin(plugin_name)
|
26
|
+
|
27
|
+
def list_plugins():
|
28
|
+
"""List all installed plugins."""
|
29
|
+
return PluginHost.list_plugins()
|
30
|
+
|
31
|
+
def get_exports():
|
32
|
+
"""Get objects exported to the global namespace by plugins."""
|
33
|
+
return PluginHost.get_exports()
|
34
|
+
|
35
|
+
def cli():
|
36
|
+
"""Run the plugin CLI (legacy version)."""
|
37
|
+
from .cli import main
|
38
|
+
main()
|
39
|
+
|
40
|
+
def cli_typer():
|
41
|
+
"""Run the Typer-based plugin CLI."""
|
42
|
+
from .cli_typer import run
|
43
|
+
run()
|
44
|
+
|
45
|
+
__all__ = [
|
46
|
+
'PluginHost',
|
47
|
+
'get_plugin_manager',
|
48
|
+
'install_from_github',
|
49
|
+
'uninstall_plugin',
|
50
|
+
'list_plugins',
|
51
|
+
'get_exports',
|
52
|
+
'cli',
|
53
|
+
'cli_typer',
|
54
|
+
'PluginCLI',
|
55
|
+
'typer_app',
|
56
|
+
'PluginException',
|
57
|
+
'PluginNotFoundError',
|
58
|
+
'PluginInstallationError',
|
59
|
+
'GitHubRepoError',
|
60
|
+
'InvalidPluginError',
|
61
|
+
'PluginMethodError',
|
62
|
+
'PluginDependencyError'
|
63
|
+
]
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Example plugin that demonstrates exporting objects to the global namespace
|
2
|
+
import pluggy
|
3
|
+
from typing import Dict, Any, Optional
|
4
|
+
|
5
|
+
# Define a hook implementation marker
|
6
|
+
hookimpl = pluggy.HookimplMarker("edsl")
|
7
|
+
|
8
|
+
# Create a class that will be exported to the global namespace
|
9
|
+
class ExportedClass:
|
10
|
+
"""An example class exported from a plugin to the global namespace."""
|
11
|
+
|
12
|
+
def __init__(self, name="Example"):
|
13
|
+
self.name = name
|
14
|
+
|
15
|
+
def greet(self):
|
16
|
+
"""Return a greeting message."""
|
17
|
+
return f"Hello from {self.name}!"
|
18
|
+
|
19
|
+
# A function to be exported to the global namespace
|
20
|
+
def exported_function(text):
|
21
|
+
"""An example function exported from a plugin to the global namespace."""
|
22
|
+
return f"Processed: {text}"
|
23
|
+
|
24
|
+
class ExportExample:
|
25
|
+
"""Example plugin that exports objects to the global namespace."""
|
26
|
+
|
27
|
+
@hookimpl
|
28
|
+
def plugin_name(self):
|
29
|
+
return "ExportExample"
|
30
|
+
|
31
|
+
@hookimpl
|
32
|
+
def plugin_description(self):
|
33
|
+
return "Demonstrates how to export objects to the global namespace."
|
34
|
+
|
35
|
+
@hookimpl
|
36
|
+
def edsl_plugin(self, plugin_name=None):
|
37
|
+
if plugin_name is None or plugin_name == "ExportExample":
|
38
|
+
return self
|
39
|
+
|
40
|
+
@hookimpl
|
41
|
+
def get_plugin_methods(self):
|
42
|
+
return {}
|
43
|
+
|
44
|
+
@hookimpl
|
45
|
+
def exports_to_namespace(self) -> Dict[str, Any]:
|
46
|
+
"""Export objects to the global namespace."""
|
47
|
+
return {
|
48
|
+
"ExportedClass": ExportedClass,
|
49
|
+
"exported_function": exported_function
|
50
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# edsl/plugins/text_plugins.py
|
2
|
+
import pluggy
|
3
|
+
from typing import Dict, Any, Optional
|
4
|
+
|
5
|
+
# Define a hook implementation marker
|
6
|
+
hookimpl = pluggy.HookimplMarker("edsl")
|
7
|
+
|
8
|
+
# Create an exportable class for demonstration
|
9
|
+
class PigLatinTranslator:
|
10
|
+
"""A class that translates text to Pig Latin."""
|
11
|
+
|
12
|
+
@staticmethod
|
13
|
+
def translate(text):
|
14
|
+
"""Translate text to Pig Latin."""
|
15
|
+
words = text.split()
|
16
|
+
result = []
|
17
|
+
for word in words:
|
18
|
+
# Simple Pig Latin rule: move first letter to end and add "ay"
|
19
|
+
if len(word) > 1:
|
20
|
+
pig_latin = word[1:] + word[0] + "ay"
|
21
|
+
result.append(pig_latin)
|
22
|
+
else:
|
23
|
+
result.append(word + "ay")
|
24
|
+
return " ".join(result)
|
25
|
+
|
26
|
+
class PigLatin:
|
27
|
+
"""Text processing plugin."""
|
28
|
+
|
29
|
+
@hookimpl
|
30
|
+
def plugin_name(self):
|
31
|
+
return "PigLatin"
|
32
|
+
|
33
|
+
@hookimpl
|
34
|
+
def plugin_description(self):
|
35
|
+
return "This plugin translates text to Pig Latin."
|
36
|
+
|
37
|
+
@hookimpl
|
38
|
+
def edsl_plugin(self, plugin_name=None):
|
39
|
+
if plugin_name is None or plugin_name == "PigLatin":
|
40
|
+
return self
|
41
|
+
|
42
|
+
@hookimpl
|
43
|
+
def get_plugin_methods(self):
|
44
|
+
return {
|
45
|
+
"pig_latin": self.pig_latin
|
46
|
+
}
|
47
|
+
|
48
|
+
@hookimpl
|
49
|
+
def exports_to_namespace(self) -> Dict[str, Any]:
|
50
|
+
"""Export objects to the global namespace."""
|
51
|
+
return {
|
52
|
+
"PigLatinTranslator": PigLatinTranslator
|
53
|
+
}
|
54
|
+
|
55
|
+
def pig_latin(self, survey, *args, **kwargs):
|
56
|
+
"""Get pig latin translation of survey questions."""
|
57
|
+
# A simple Pig Latin translator without using the model
|
58
|
+
# This avoids needing API keys for testing
|
59
|
+
|
60
|
+
#print(f"Processing survey: {survey}")
|
61
|
+
|
62
|
+
# Translate each question text
|
63
|
+
translations = []
|
64
|
+
for question in survey.questions:
|
65
|
+
translations.append(PigLatinTranslator.translate(question.question_text))
|
66
|
+
|
67
|
+
return translations
|