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/results/results_selector.py
CHANGED
@@ -11,8 +11,7 @@ from typing import Union, List, Dict, Any, Optional, Tuple, Callable
|
|
11
11
|
import sys
|
12
12
|
from collections import defaultdict
|
13
13
|
|
14
|
-
|
15
|
-
from ..utilities import is_notebook
|
14
|
+
# Import is_notebook but defer Dataset import to avoid potential circular imports
|
16
15
|
|
17
16
|
from .exceptions import ResultsColumnNotFoundError
|
18
17
|
|
@@ -67,7 +66,7 @@ class Selector:
|
|
67
66
|
self.columns = columns
|
68
67
|
self.items_in_order = [] # Tracks column order for consistent output
|
69
68
|
|
70
|
-
def select(self, *columns: Union[str, List[str]]) -> Optional[
|
69
|
+
def select(self, *columns: Union[str, List[str]]) -> Optional[Any]:
|
71
70
|
"""
|
72
71
|
Select specific columns from the data and return as a Dataset.
|
73
72
|
|
@@ -106,11 +105,16 @@ class Selector:
|
|
106
105
|
to_fetch = self._get_columns_to_fetch(columns)
|
107
106
|
new_data = self._fetch_data(to_fetch)
|
108
107
|
except ResultsColumnNotFoundError as e:
|
109
|
-
|
108
|
+
# Check is_notebook with explicit import to ensure mock works
|
109
|
+
from ..utilities import is_notebook as is_notebook_check
|
110
|
+
if is_notebook_check():
|
110
111
|
print("Error:", e, file=sys.stderr)
|
111
112
|
return None
|
112
113
|
else:
|
113
114
|
raise e
|
115
|
+
|
116
|
+
# Import Dataset here to avoid circular import issues
|
117
|
+
from ..dataset import Dataset
|
114
118
|
return Dataset(new_data)
|
115
119
|
|
116
120
|
def _normalize_columns(self, columns: Union[str, List[str]]) -> Tuple[str, ...]:
|
edsl/scenarios/PdfExtractor.py
CHANGED
@@ -1,46 +1,70 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
|
-
import
|
4
|
+
from typing import TYPE_CHECKING, Optional, List
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from ..display import HTML
|
8
|
+
from ..scenarios import FileStore
|
3
9
|
|
4
10
|
|
5
11
|
class ConstructDownloadLink:
|
6
|
-
"""
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
"""Create HTML download links for FileStore objects.
|
13
|
+
|
14
|
+
This class generates downloadable HTML links for FileStore objects that can be
|
15
|
+
displayed in Jupyter notebooks or other web interfaces. The links are styled
|
16
|
+
and allow for custom filenames and styling options.
|
17
|
+
|
18
|
+
Examples:
|
19
|
+
>>> from edsl import FileStore
|
20
|
+
>>> fs = FileStore.example("txt")
|
21
|
+
>>> link = ConstructDownloadLink(fs)
|
22
|
+
>>> new_link = link.create_link()
|
15
23
|
"""
|
16
24
|
|
17
|
-
def __init__(self, filestore):
|
18
|
-
"""
|
19
|
-
Initialize with a FileStore object.
|
25
|
+
def __init__(self, filestore: FileStore):
|
26
|
+
"""Initialize a new download link constructor.
|
20
27
|
|
21
28
|
Args:
|
22
|
-
filestore: A FileStore object containing the file to be made downloadable
|
29
|
+
filestore: A FileStore object containing the file to be made downloadable.
|
23
30
|
"""
|
24
31
|
self.filestore = filestore
|
25
32
|
|
26
|
-
def create_link(
|
27
|
-
|
33
|
+
def create_link(
|
34
|
+
self, custom_filename: Optional[str] = None, style: Optional[dict] = None
|
35
|
+
) -> HTML:
|
36
|
+
"""Create an HTML download link wrapped in an HTML display object.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
custom_filename: Optional custom name for the downloaded file.
|
40
|
+
If None, uses the original filename.
|
41
|
+
style: Optional dictionary of CSS styles for the download button.
|
42
|
+
If None, uses default styling.
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
HTML: A displayable HTML object containing the styled download link.
|
46
|
+
"""
|
47
|
+
from ..display import HTML
|
28
48
|
|
29
49
|
html = self.html_create_link(custom_filename, style)
|
30
50
|
return HTML(html)
|
31
51
|
|
32
|
-
def html_create_link(
|
33
|
-
|
34
|
-
|
52
|
+
def html_create_link(
|
53
|
+
self, custom_filename: Optional[str] = None, style: Optional[dict] = None
|
54
|
+
) -> str:
|
55
|
+
"""Generate an HTML download link string.
|
56
|
+
|
57
|
+
Creates a styled HTML anchor tag that triggers a file download when clicked.
|
58
|
+
The file data is embedded as a base64-encoded data URI.
|
35
59
|
|
36
60
|
Args:
|
37
|
-
custom_filename
|
38
|
-
|
39
|
-
style
|
40
|
-
|
61
|
+
custom_filename: Optional custom name for the downloaded file.
|
62
|
+
If None, uses the original filename.
|
63
|
+
style: Optional dictionary of CSS styles for the download button.
|
64
|
+
If None, uses default styling.
|
41
65
|
|
42
66
|
Returns:
|
43
|
-
|
67
|
+
str: HTML string containing the styled download link.
|
44
68
|
"""
|
45
69
|
|
46
70
|
# Get filename from path or use custom filename
|
@@ -78,19 +102,28 @@ class ConstructDownloadLink:
|
|
78
102
|
"""
|
79
103
|
return html
|
80
104
|
|
81
|
-
def create_multiple_links(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
105
|
+
def create_multiple_links(
|
106
|
+
self,
|
107
|
+
files: List["FileStore"],
|
108
|
+
custom_filenames: Optional[List[Optional[str]]] = None,
|
109
|
+
style: Optional[dict] = None,
|
110
|
+
) -> HTML:
|
111
|
+
"""Create multiple download links in a horizontal layout.
|
112
|
+
|
113
|
+
Generates a collection of download links arranged horizontally with consistent
|
114
|
+
styling. Useful for providing different versions of the same file or related
|
115
|
+
files together.
|
86
116
|
|
87
117
|
Args:
|
88
|
-
files
|
89
|
-
custom_filenames
|
90
|
-
|
118
|
+
files: List of FileStore objects to create download links for.
|
119
|
+
custom_filenames: Optional list of custom filenames for downloads.
|
120
|
+
If None, original filenames will be used for all files.
|
121
|
+
style: Optional dictionary of CSS styles applied to all download buttons.
|
122
|
+
If None, uses default styling.
|
91
123
|
|
92
124
|
Returns:
|
93
|
-
|
125
|
+
HTML: A displayable HTML object containing all download links arranged
|
126
|
+
horizontally.
|
94
127
|
"""
|
95
128
|
if custom_filenames is None:
|
96
129
|
custom_filenames = [None] * len(files)
|
@@ -104,7 +137,8 @@ class ConstructDownloadLink:
|
|
104
137
|
)._repr_html_()
|
105
138
|
)
|
106
139
|
|
107
|
-
from
|
140
|
+
from ..display import HTML
|
141
|
+
|
108
142
|
return HTML(
|
109
143
|
'<div style="display: flex; gap: 10px;">' + "".join(html_parts) + "</div>"
|
110
144
|
)
|
@@ -113,4 +147,4 @@ class ConstructDownloadLink:
|
|
113
147
|
if __name__ == "__main__":
|
114
148
|
import doctest
|
115
149
|
|
116
|
-
doctest.testmod()
|
150
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE)
|
@@ -8,9 +8,8 @@ the matching files.
|
|
8
8
|
"""
|
9
9
|
|
10
10
|
from dataclasses import dataclass
|
11
|
-
from typing import Optional, List, Iterator, TypeVar,
|
11
|
+
from typing import Optional, List, Iterator, TypeVar, Callable
|
12
12
|
import os
|
13
|
-
from pathlib import Path
|
14
13
|
|
15
14
|
# Generic type variable for the factory function's return type
|
16
15
|
T = TypeVar("T")
|
@@ -193,24 +192,44 @@ class DirectoryScanner:
|
|
193
192
|
Returns:
|
194
193
|
True if the file should be included, False otherwise.
|
195
194
|
"""
|
195
|
+
# Get filename and extension
|
196
|
+
basename = os.path.basename(filepath)
|
196
197
|
_, ext = os.path.splitext(filepath)
|
197
198
|
ext = ext[1:] if ext else "" # Remove leading dot from extension
|
198
|
-
|
199
|
-
#
|
200
|
-
if
|
201
|
-
return
|
202
|
-
|
203
|
-
#
|
199
|
+
|
200
|
+
# Skip system files like .DS_Store by default
|
201
|
+
if basename == '.DS_Store':
|
202
|
+
return False
|
203
|
+
|
204
|
+
# If there's a specific allow list and we have a wildcard filter
|
205
|
+
if suffix_allow_list:
|
206
|
+
# Only include files with the allowed extensions
|
207
|
+
return ext in suffix_allow_list
|
208
|
+
|
209
|
+
# Check exclusions (they take precedence)
|
204
210
|
if suffix_exclude_list and ext in suffix_exclude_list:
|
205
211
|
return False
|
206
212
|
|
207
213
|
# Check example suffix if specified
|
208
|
-
if example_suffix
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
+
if example_suffix:
|
215
|
+
# Handle wildcard patterns
|
216
|
+
if '*' in example_suffix:
|
217
|
+
import fnmatch
|
218
|
+
basename = os.path.basename(filepath)
|
219
|
+
# Try to match just the filename if the pattern doesn't contain path separators
|
220
|
+
if '/' not in example_suffix and '\\' not in example_suffix:
|
221
|
+
if not fnmatch.fnmatch(basename, example_suffix):
|
222
|
+
return False
|
223
|
+
else:
|
224
|
+
# Match the full path
|
225
|
+
if not fnmatch.fnmatch(filepath, example_suffix):
|
226
|
+
return False
|
227
|
+
elif not filepath.endswith(example_suffix):
|
228
|
+
return False
|
229
|
+
|
230
|
+
# Handle no extension case
|
231
|
+
if not ext:
|
232
|
+
return include_no_extension
|
214
233
|
|
215
234
|
return True
|
216
235
|
|
edsl/scenarios/exceptions.py
CHANGED
@@ -7,7 +7,6 @@ that can occur when working with Scenarios, ScenarioLists, and related component
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
import re
|
10
|
-
from typing import List
|
11
10
|
|
12
11
|
from ..base import BaseException
|
13
12
|
|
@@ -16,11 +15,13 @@ class AgentListError(BaseException):
|
|
16
15
|
"""
|
17
16
|
Exception raised for errors related to AgentList operations.
|
18
17
|
|
19
|
-
This exception
|
20
|
-
|
18
|
+
This exception appears to be a duplicate of the exception defined in
|
19
|
+
edsl.agents.exceptions. It exists here for legacy reasons but is not
|
20
|
+
actively used from this module.
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
Note: This exception is defined but not used from this module. The AgentListError
|
23
|
+
from edsl.agents.exceptions is used instead. This raises Exception("not used")
|
24
|
+
to indicate this state.
|
24
25
|
"""
|
25
26
|
|
26
27
|
def __init__(self, message: str):
|
@@ -37,9 +38,24 @@ class ScenarioError(BaseException):
|
|
37
38
|
"""
|
38
39
|
Exception raised for errors related to Scenario operations.
|
39
40
|
|
40
|
-
This exception is raised when
|
41
|
-
|
42
|
-
|
41
|
+
This exception is raised when:
|
42
|
+
- Invalid data is passed to initialize a Scenario (not convertible to dictionary)
|
43
|
+
- Required fields are missing in scenario data
|
44
|
+
- File operations fail when loading scenarios from files
|
45
|
+
- Scenario content cannot be properly parsed or processed
|
46
|
+
- Scenario lists encounter issues with data formats or operations
|
47
|
+
|
48
|
+
To fix this error:
|
49
|
+
1. Check that your scenario data is properly formatted (valid dictionary or convertible to one)
|
50
|
+
2. Ensure all required fields for a scenario are present
|
51
|
+
3. Verify file paths and permissions when loading from files
|
52
|
+
4. Check for syntax or format errors in scenario content
|
53
|
+
|
54
|
+
Examples:
|
55
|
+
```python
|
56
|
+
Scenario(123) # Raises ScenarioError (not convertible to dictionary)
|
57
|
+
Scenario({"invalid_format": True}) # May raise ScenarioError (missing required fields)
|
58
|
+
```
|
43
59
|
|
44
60
|
Args:
|
45
61
|
message: A description of the error that occurred.
|
@@ -84,9 +100,10 @@ class ScenarioError(BaseException):
|
|
84
100
|
The text with URLs converted to clickable links.
|
85
101
|
|
86
102
|
Example:
|
87
|
-
|
88
|
-
|
89
|
-
|
103
|
+
```python
|
104
|
+
error = ScenarioError("See docs at https://example.com")
|
105
|
+
s = str(error) # Returns the message with clickable link
|
106
|
+
```
|
90
107
|
"""
|
91
108
|
url_pattern = r"https?://[^\s]+"
|
92
109
|
urls = re.findall(url_pattern, text)
|
@@ -96,6 +113,213 @@ class ScenarioError(BaseException):
|
|
96
113
|
return text
|
97
114
|
|
98
115
|
|
99
|
-
|
100
|
-
|
101
|
-
|
116
|
+
class FileNotFoundScenarioError(ScenarioError):
|
117
|
+
"""
|
118
|
+
Exception raised when a file needed for a scenario cannot be found.
|
119
|
+
|
120
|
+
This exception occurs when:
|
121
|
+
- A file specified in a file path does not exist
|
122
|
+
- A referenced image, document, or other resource is missing
|
123
|
+
- A directory expected to contain scenario files is not found
|
124
|
+
|
125
|
+
To fix this error:
|
126
|
+
1. Check that the file path is correct and the file exists
|
127
|
+
2. Verify file system permissions allow access to the file
|
128
|
+
3. Ensure any referenced external resources are properly available
|
129
|
+
|
130
|
+
Examples:
|
131
|
+
```python
|
132
|
+
Scenario.from_file("/path/to/nonexistent/file.json") # Raises FileNotFoundScenarioError
|
133
|
+
```
|
134
|
+
"""
|
135
|
+
|
136
|
+
def __init__(self, message: str):
|
137
|
+
"""
|
138
|
+
Initialize the FileNotFoundScenarioError with a message.
|
139
|
+
|
140
|
+
Args:
|
141
|
+
message: A description of the error that occurred.
|
142
|
+
"""
|
143
|
+
super().__init__(message)
|
144
|
+
|
145
|
+
|
146
|
+
class ImportScenarioError(ScenarioError):
|
147
|
+
"""
|
148
|
+
Exception raised when importing a library needed for scenario operations fails.
|
149
|
+
|
150
|
+
This exception occurs when:
|
151
|
+
- A required library for handling specific file types is not installed
|
152
|
+
- A module needed for processing scenario data cannot be imported
|
153
|
+
- Optional dependencies for advanced features are missing
|
154
|
+
|
155
|
+
To fix this error:
|
156
|
+
1. Install the required dependencies mentioned in the error message
|
157
|
+
2. Check for version conflicts between dependencies
|
158
|
+
3. Ensure your environment has all necessary packages
|
159
|
+
|
160
|
+
Examples:
|
161
|
+
```python
|
162
|
+
# When attempting to load a PDF without the pdf dependencies
|
163
|
+
Scenario.from_pdf("document.pdf") # Raises ImportScenarioError
|
164
|
+
```
|
165
|
+
"""
|
166
|
+
|
167
|
+
def __init__(self, message: str):
|
168
|
+
"""
|
169
|
+
Initialize the ImportScenarioError with a message.
|
170
|
+
|
171
|
+
Args:
|
172
|
+
message: A description of the error that occurred.
|
173
|
+
"""
|
174
|
+
super().__init__(message)
|
175
|
+
|
176
|
+
|
177
|
+
class TypeScenarioError(ScenarioError):
|
178
|
+
"""
|
179
|
+
Exception raised when there's a type mismatch in scenario operations.
|
180
|
+
|
181
|
+
This exception occurs when:
|
182
|
+
- A parameter is of the wrong type for a scenario operation
|
183
|
+
- Incompatible types are used in scenario methods
|
184
|
+
- Type conversion fails during scenario processing
|
185
|
+
|
186
|
+
To fix this error:
|
187
|
+
1. Check the types of parameters passed to scenario methods
|
188
|
+
2. Ensure data structures match what scenario operations expect
|
189
|
+
3. Verify that operations between scenarios and other objects are compatible
|
190
|
+
|
191
|
+
Examples:
|
192
|
+
```python
|
193
|
+
scenario * "invalid_operand" # Raises TypeScenarioError
|
194
|
+
```
|
195
|
+
"""
|
196
|
+
|
197
|
+
def __init__(self, message: str):
|
198
|
+
"""
|
199
|
+
Initialize the TypeScenarioError with a message.
|
200
|
+
|
201
|
+
Args:
|
202
|
+
message: A description of the error that occurred.
|
203
|
+
"""
|
204
|
+
super().__init__(message)
|
205
|
+
|
206
|
+
|
207
|
+
class ValueScenarioError(ScenarioError):
|
208
|
+
"""
|
209
|
+
Exception raised when there's an invalid value in scenario operations.
|
210
|
+
|
211
|
+
This exception occurs when:
|
212
|
+
- A parameter value is out of its acceptable range
|
213
|
+
- Invalid formats are provided for scenario data
|
214
|
+
- Operation parameters are invalid for the requested action
|
215
|
+
|
216
|
+
To fix this error:
|
217
|
+
1. Check parameter values against allowed ranges or formats
|
218
|
+
2. Verify inputs meet the requirements for specific operations
|
219
|
+
3. Ensure data formats match what's expected by scenario methods
|
220
|
+
|
221
|
+
Examples:
|
222
|
+
```python
|
223
|
+
scenario_list.to_table(output_type="invalid_format") # Raises ValueScenarioError
|
224
|
+
```
|
225
|
+
"""
|
226
|
+
|
227
|
+
def __init__(self, message: str):
|
228
|
+
"""
|
229
|
+
Initialize the ValueScenarioError with a message.
|
230
|
+
|
231
|
+
Args:
|
232
|
+
message: A description of the error that occurred.
|
233
|
+
"""
|
234
|
+
super().__init__(message)
|
235
|
+
|
236
|
+
|
237
|
+
class AttributeScenarioError(ScenarioError):
|
238
|
+
"""
|
239
|
+
Exception raised when accessing a non-existent attribute in a scenario.
|
240
|
+
|
241
|
+
This exception occurs when:
|
242
|
+
- Attempting to access a field not present in a scenario
|
243
|
+
- Using an attribute accessor on a scenario for a missing property
|
244
|
+
- CSV or dataframe column access issues
|
245
|
+
|
246
|
+
To fix this error:
|
247
|
+
1. Check that the attribute name is correct
|
248
|
+
2. Verify the scenario contains the expected fields
|
249
|
+
3. Use hasattr() to check for attribute existence before access
|
250
|
+
|
251
|
+
Examples:
|
252
|
+
```python
|
253
|
+
scenario.nonexistent_attribute # Raises AttributeScenarioError
|
254
|
+
```
|
255
|
+
"""
|
256
|
+
|
257
|
+
def __init__(self, message: str):
|
258
|
+
"""
|
259
|
+
Initialize the AttributeScenarioError with a message.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
message: A description of the error that occurred.
|
263
|
+
"""
|
264
|
+
super().__init__(message)
|
265
|
+
|
266
|
+
|
267
|
+
class IndexScenarioError(ScenarioError):
|
268
|
+
"""
|
269
|
+
Exception raised when an index is out of range in scenario operations.
|
270
|
+
|
271
|
+
This exception occurs when:
|
272
|
+
- Accessing a scenario index outside the valid range
|
273
|
+
- Using an invalid index in a scenario list operation
|
274
|
+
- Sequence operations with invalid indices
|
275
|
+
|
276
|
+
To fix this error:
|
277
|
+
1. Check array boundaries before accessing elements
|
278
|
+
2. Verify indices are within valid ranges for the collection
|
279
|
+
3. Use len() to determine the valid index range
|
280
|
+
|
281
|
+
Examples:
|
282
|
+
```python
|
283
|
+
scenario_list[999] # Raises IndexScenarioError if fewer items exist
|
284
|
+
```
|
285
|
+
"""
|
286
|
+
|
287
|
+
def __init__(self, message: str):
|
288
|
+
"""
|
289
|
+
Initialize the IndexScenarioError with a message.
|
290
|
+
|
291
|
+
Args:
|
292
|
+
message: A description of the error that occurred.
|
293
|
+
"""
|
294
|
+
super().__init__(message)
|
295
|
+
|
296
|
+
|
297
|
+
class KeyScenarioError(ScenarioError):
|
298
|
+
"""
|
299
|
+
Exception raised when a key is missing in scenario operations.
|
300
|
+
|
301
|
+
This exception occurs when:
|
302
|
+
- Accessing a non-existent key in a scenario
|
303
|
+
- Using key-based access for missing fields
|
304
|
+
- Dictionary operations with invalid keys
|
305
|
+
|
306
|
+
To fix this error:
|
307
|
+
1. Check if the key exists before attempting access
|
308
|
+
2. Use dictionary get() method with default values for safer access
|
309
|
+
3. Verify the scenario contains the expected keys
|
310
|
+
|
311
|
+
Examples:
|
312
|
+
```python
|
313
|
+
scenario["missing_key"] # Raises KeyScenarioError
|
314
|
+
```
|
315
|
+
"""
|
316
|
+
|
317
|
+
def __init__(self, message: str):
|
318
|
+
"""
|
319
|
+
Initialize the KeyScenarioError with a message.
|
320
|
+
|
321
|
+
Args:
|
322
|
+
message: A description of the error that occurred.
|
323
|
+
"""
|
324
|
+
super().__init__(message)
|
325
|
+
|
edsl/scenarios/file_methods.py
CHANGED
edsl/scenarios/file_store.py
CHANGED
@@ -4,16 +4,19 @@ import tempfile
|
|
4
4
|
import mimetypes
|
5
5
|
import asyncio
|
6
6
|
import os
|
7
|
-
from typing import Dict,
|
7
|
+
from typing import Dict, IO, Optional
|
8
8
|
from typing import Union
|
9
9
|
from uuid import UUID
|
10
10
|
import time
|
11
|
-
from typing import
|
11
|
+
from typing import List, Literal, TYPE_CHECKING
|
12
12
|
|
13
13
|
from .scenario import Scenario
|
14
14
|
from ..utilities import remove_edsl_version
|
15
15
|
from .file_methods import FileMethods
|
16
16
|
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
from .scenario_list import ScenarioList
|
19
|
+
|
17
20
|
class FileStore(Scenario):
|
18
21
|
"""
|
19
22
|
A specialized Scenario subclass for managing file content and metadata.
|
@@ -246,6 +249,7 @@ class FileStore(Scenario):
|
|
246
249
|
Returns:
|
247
250
|
ScenarioList containing FileStore objects with their corresponding URLs
|
248
251
|
"""
|
252
|
+
# Import here to avoid circular imports
|
249
253
|
from .scenario_list import ScenarioList
|
250
254
|
|
251
255
|
try:
|
@@ -282,7 +286,7 @@ class FileStore(Scenario):
|
|
282
286
|
|
283
287
|
@property
|
284
288
|
def size(self) -> int:
|
285
|
-
if self.base64_string
|
289
|
+
if self.base64_string is not None:
|
286
290
|
return (len(self.base64_string) / 4.0) * 3 # from base64 to char size
|
287
291
|
return os.path.getsize(self.path)
|
288
292
|
|
@@ -1,3 +1,20 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"PdfMethods",
|
3
|
+
"DocxMethods",
|
4
|
+
"PngMethods",
|
5
|
+
"TxtMethods",
|
6
|
+
"HtmlMethods",
|
7
|
+
"MarkdownMethods",
|
8
|
+
"CsvMethods",
|
9
|
+
"JsonMethods",
|
10
|
+
"SqlMethods",
|
11
|
+
"PptxMethods",
|
12
|
+
"LaTeXMethods",
|
13
|
+
"PyMethods",
|
14
|
+
"SQLiteMethods",
|
15
|
+
"JpegMethods"
|
16
|
+
]
|
17
|
+
|
1
18
|
from .pdf_file_store import PdfMethods
|
2
19
|
from .docx_file_store import DocxMethods
|
3
20
|
from .png_file_store import PngMethods
|
@@ -2,9 +2,6 @@ import os
|
|
2
2
|
import tempfile
|
3
3
|
|
4
4
|
from ..file_methods import FileMethods
|
5
|
-
from ..scenario import Scenario
|
6
|
-
from ..scenario_list import ScenarioList
|
7
|
-
from ..file_store import FileStore
|
8
5
|
|
9
6
|
class DocxMethods(FileMethods):
|
10
7
|
suffix = "docx"
|
@@ -59,8 +56,6 @@ class DocxMethods(FileMethods):
|
|
59
56
|
|
60
57
|
def example(self):
|
61
58
|
from docx import Document
|
62
|
-
from ..scenario import Scenario
|
63
|
-
from ..scenario_list import ScenarioList
|
64
59
|
|
65
60
|
os.makedirs("test_dir", exist_ok=True)
|
66
61
|
doc1 = Document()
|
@@ -2,9 +2,6 @@ from ..file_methods import FileMethods
|
|
2
2
|
import os
|
3
3
|
import tempfile
|
4
4
|
|
5
|
-
from ..scenario import Scenario
|
6
|
-
from ..scenario_list import ScenarioList
|
7
|
-
from ..file_store import FileStore
|
8
5
|
|
9
6
|
class PptxMethods(FileMethods):
|
10
7
|
suffix = "pptx"
|
@@ -76,8 +73,6 @@ class PptxMethods(FileMethods):
|
|
76
73
|
|
77
74
|
def example(self):
|
78
75
|
from pptx import Presentation
|
79
|
-
from ..scenario import Scenario
|
80
|
-
from ..scenario_list import ScenarioList
|
81
76
|
|
82
77
|
os.makedirs("test_dir", exist_ok=True)
|
83
78
|
|