edsl 0.1.49__py3-none-any.whl → 0.1.50__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 +75 -0
- edsl/buckets/model_buckets.py +1 -2
- edsl/buckets/token_bucket.py +11 -6
- edsl/buckets/token_bucket_api.py +1 -2
- edsl/buckets/token_bucket_client.py +9 -7
- edsl/caching/cache.py +7 -2
- edsl/caching/cache_entry.py +10 -9
- edsl/caching/exceptions.py +113 -7
- edsl/caching/remote_cache_sync.py +1 -2
- edsl/caching/sql_dict.py +17 -12
- edsl/cli.py +43 -0
- edsl/config/config_class.py +30 -6
- edsl/conversation/Conversation.py +3 -2
- edsl/conversation/exceptions.py +58 -0
- edsl/conversation/mug_negotiation.py +0 -2
- edsl/coop/__init__.py +20 -1
- edsl/coop/coop.py +120 -29
- edsl/coop/exceptions.py +188 -9
- edsl/coop/price_fetcher.py +3 -6
- edsl/coop/utils.py +4 -6
- edsl/dataset/__init__.py +5 -4
- edsl/dataset/dataset.py +53 -43
- edsl/dataset/dataset_operations_mixin.py +86 -72
- edsl/dataset/dataset_tree.py +9 -5
- edsl/dataset/display/table_display.py +0 -2
- edsl/dataset/display/table_renderers.py +0 -1
- 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 +4 -5
- edsl/inference_services/data_structures.py +9 -6
- 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 +2 -1
- 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 +6 -2
- 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 +3 -2
- edsl/instructions/exceptions.py +61 -0
- edsl/instructions/instruction.py +5 -2
- edsl/instructions/instruction_collection.py +2 -1
- edsl/instructions/instruction_handler.py +4 -9
- edsl/interviews/ReportErrors.py +0 -3
- edsl/interviews/__init__.py +9 -2
- edsl/interviews/answering_function.py +11 -13
- edsl/interviews/exception_tracking.py +14 -7
- edsl/interviews/exceptions.py +79 -0
- edsl/interviews/interview.py +32 -29
- edsl/interviews/interview_status_dictionary.py +4 -2
- edsl/interviews/interview_status_log.py +2 -1
- edsl/interviews/interview_task_manager.py +3 -3
- edsl/interviews/request_token_estimator.py +3 -1
- edsl/interviews/statistics.py +2 -3
- edsl/invigilators/__init__.py +7 -1
- edsl/invigilators/exceptions.py +79 -0
- edsl/invigilators/invigilator_base.py +0 -1
- edsl/invigilators/invigilators.py +8 -12
- 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 +3 -3
- edsl/jobs/async_interview_runner.py +24 -22
- edsl/jobs/check_survey_scenario_compatibility.py +7 -6
- edsl/jobs/data_structures.py +7 -4
- edsl/jobs/exceptions.py +177 -8
- edsl/jobs/fetch_invigilator.py +1 -1
- edsl/jobs/jobs.py +72 -67
- edsl/jobs/jobs_checks.py +2 -3
- edsl/jobs/jobs_component_constructor.py +2 -2
- edsl/jobs/jobs_pricing_estimation.py +3 -2
- edsl/jobs/jobs_remote_inference_logger.py +5 -4
- edsl/jobs/jobs_runner_asyncio.py +1 -2
- edsl/jobs/jobs_runner_status.py +8 -9
- edsl/jobs/remote_inference.py +26 -23
- edsl/jobs/results_exceptions_handler.py +8 -5
- 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 +4 -7
- 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/notebook.py +1 -1
- edsl/notebooks/notebook_to_latex.py +0 -1
- 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 +2 -0
- edsl/prompts/exceptions.py +107 -5
- edsl/prompts/prompt.py +14 -6
- edsl/questions/HTMLQuestion.py +5 -11
- edsl/questions/Quick.py +0 -1
- edsl/questions/__init__.py +2 -0
- edsl/questions/answer_validator_mixin.py +318 -318
- edsl/questions/compose_questions.py +2 -2
- edsl/questions/descriptors.py +10 -49
- 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 +14 -16
- edsl/questions/question_base_gen_mixin.py +2 -2
- edsl/questions/question_base_prompts_mixin.py +9 -3
- edsl/questions/question_budget.py +9 -5
- edsl/questions/question_check_box.py +3 -5
- edsl/questions/question_dict.py +171 -194
- edsl/questions/question_extract.py +1 -1
- edsl/questions/question_free_text.py +4 -6
- edsl/questions/question_functional.py +4 -3
- edsl/questions/question_list.py +36 -9
- edsl/questions/question_matrix.py +95 -61
- edsl/questions/question_multiple_choice.py +6 -4
- edsl/questions/question_numerical.py +2 -4
- edsl/questions/question_registry.py +4 -2
- edsl/questions/register_questions_meta.py +0 -1
- edsl/questions/response_validator_abc.py +7 -13
- 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 +0 -1
- edsl/results/result.py +4 -5
- edsl/results/results.py +10 -51
- 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 +0 -1
- edsl/scenarios/scenario_list.py +152 -18
- 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_export.py +6 -3
- edsl/surveys/survey_flow_visualization.py +10 -1
- edsl/tasks/__init__.py +2 -0
- edsl/tasks/question_task_creator.py +3 -3
- edsl/tasks/task_creators.py +1 -3
- edsl/tasks/task_history.py +5 -7
- edsl/tasks/task_status_log.py +1 -2
- edsl/tokens/__init__.py +3 -1
- edsl/tokens/token_usage.py +1 -1
- 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.50.dist-info}/METADATA +32 -2
- edsl-0.1.50.dist-info/RECORD +363 -0
- edsl-0.1.50.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/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.50.dist-info}/LICENSE +0 -0
- {edsl-0.1.49.dist-info → edsl-0.1.50.dist-info}/WHEEL +0 -0
edsl/results/exceptions.py
CHANGED
@@ -2,28 +2,162 @@
|
|
2
2
|
from ..base import BaseException
|
3
3
|
|
4
4
|
class ResultsError(BaseException):
|
5
|
-
|
5
|
+
"""
|
6
|
+
Base exception class for all results-related errors.
|
7
|
+
|
8
|
+
This is the parent class for all exceptions related to Results objects
|
9
|
+
operations, including data manipulation, selection, and filtering.
|
10
|
+
|
11
|
+
This exception is raised in the following cases:
|
12
|
+
- When trying to add two Results objects with different surveys or created columns
|
13
|
+
- When trying to sample more items than available
|
14
|
+
- When Survey is not defined when accessing answer_keys
|
15
|
+
- When fetching remote Results fails
|
16
|
+
- When inappropriate model types are used with Results methods
|
17
|
+
"""
|
18
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html"
|
6
19
|
|
7
20
|
|
8
21
|
class ResultsDeserializationError(ResultsError):
|
9
|
-
|
22
|
+
"""
|
23
|
+
Exception raised when Results object deserialization fails.
|
24
|
+
|
25
|
+
This exception occurs when a Results object cannot be properly reconstructed
|
26
|
+
from its serialized representation, typically during from_dict() operations.
|
27
|
+
|
28
|
+
Reasons this might occur:
|
29
|
+
- Missing required fields in the serialized data
|
30
|
+
- Corrupted serialized data
|
31
|
+
- Version incompatibility between serialized data and current code
|
32
|
+
|
33
|
+
To fix this error:
|
34
|
+
1. Check that the serialized data is complete and uncorrupted
|
35
|
+
2. Ensure you're using a compatible version of EDSL to deserialize the data
|
36
|
+
3. If the issue persists, you may need to recreate the results from raw data
|
37
|
+
|
38
|
+
Examples:
|
39
|
+
```python
|
40
|
+
Results.from_dict(incomplete_or_corrupted_data) # Raises ResultsDeserializationError
|
41
|
+
```
|
42
|
+
"""
|
43
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#saving-and-loading-results"
|
10
44
|
|
11
45
|
|
12
46
|
class ResultsBadMutationstringError(ResultsError):
|
13
|
-
|
47
|
+
"""
|
48
|
+
Exception raised when an invalid mutation string is provided.
|
49
|
+
|
50
|
+
This exception occurs when the mutation string doesn't follow the required format,
|
51
|
+
which should be 'column_name = expression' where expression is a valid Python
|
52
|
+
expression that can reference other columns.
|
53
|
+
|
54
|
+
To fix this error:
|
55
|
+
1. Ensure your mutation string contains an equals sign
|
56
|
+
2. Check that the left side is a valid column name
|
57
|
+
3. Verify the right side is a valid Python expression
|
58
|
+
|
59
|
+
Examples:
|
60
|
+
```python
|
61
|
+
results.mutate("invalid_mutation_no_equals") # Raises ResultsBadMutationstringError
|
62
|
+
results.mutate("column_name == value") # Raises ResultsBadMutationstringError (should use single =)
|
63
|
+
```
|
64
|
+
"""
|
65
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#creating-new-columns"
|
14
66
|
|
15
67
|
|
16
68
|
class ResultsColumnNotFoundError(ResultsError):
|
17
|
-
|
69
|
+
"""
|
70
|
+
Exception raised when attempting to access a non-existent column.
|
71
|
+
|
72
|
+
This exception occurs when trying to access, filter, or perform operations
|
73
|
+
on a column that doesn't exist in the Results object.
|
74
|
+
|
75
|
+
To fix this error:
|
76
|
+
1. Check for typos in the column name
|
77
|
+
2. Verify the column exists using results.columns() or results.df.columns
|
78
|
+
3. If the column is dynamic, ensure it has been created with mutate() first
|
79
|
+
|
80
|
+
The error message typically includes suggestions for similar column names
|
81
|
+
that do exist, which can help identify typos.
|
82
|
+
|
83
|
+
Examples:
|
84
|
+
```python
|
85
|
+
results.table(keys=["non_existent_column"]) # Raises ResultsColumnNotFoundError
|
86
|
+
results.select("typo_in_column_name") # Raises ResultsColumnNotFoundError
|
87
|
+
```
|
88
|
+
"""
|
89
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#selecting-columns"
|
18
90
|
|
19
91
|
|
20
92
|
class ResultsInvalidNameError(ResultsError):
|
21
|
-
|
93
|
+
"""
|
94
|
+
Exception raised when an invalid column name is provided.
|
95
|
+
|
96
|
+
This exception occurs when:
|
97
|
+
- The provided name is not a valid Python identifier
|
98
|
+
- The name conflicts with reserved names or methods
|
99
|
+
- The name contains invalid characters or starts with a number
|
100
|
+
|
101
|
+
To fix this error:
|
102
|
+
1. Use names that follow Python variable naming rules
|
103
|
+
2. Avoid using reserved words or existing method names
|
104
|
+
3. Use only letters, numbers, and underscores (not starting with a number)
|
105
|
+
|
106
|
+
Examples:
|
107
|
+
```python
|
108
|
+
results.mutate("123invalid = 1") # Raises ResultsInvalidNameError (starts with number)
|
109
|
+
results.mutate("invalid-name = 1") # Raises ResultsInvalidNameError (contains hyphen)
|
110
|
+
results.mutate("filter = 1") # Raises ResultsInvalidNameError (reserved method name)
|
111
|
+
```
|
112
|
+
"""
|
113
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#creating-new-columns"
|
22
114
|
|
23
115
|
|
24
116
|
class ResultsMutateError(ResultsError):
|
25
|
-
|
117
|
+
"""
|
118
|
+
Exception raised when a mutation operation fails.
|
119
|
+
|
120
|
+
This exception occurs when an error happens during the execution of a mutation
|
121
|
+
expression, such as:
|
122
|
+
- Syntax errors in the expression
|
123
|
+
- Reference to non-existent columns
|
124
|
+
- Type errors in operations (e.g., adding a string to a number)
|
125
|
+
|
126
|
+
To fix this error:
|
127
|
+
1. Check the expression syntax
|
128
|
+
2. Verify all columns referenced in the expression exist
|
129
|
+
3. Ensure type compatibility in operations
|
130
|
+
4. Test the expression with simple cases first
|
131
|
+
|
132
|
+
Examples:
|
133
|
+
```python
|
134
|
+
results.mutate("new_col = old_col + 'text'") # Raises ResultsMutateError if old_col contains numbers
|
135
|
+
results.mutate("new_col = undefined_col + 1") # Raises ResultsMutateError if undefined_col doesn't exist
|
136
|
+
```
|
137
|
+
"""
|
138
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#creating-new-columns"
|
26
139
|
|
27
140
|
|
28
141
|
class ResultsFilterError(ResultsError):
|
29
|
-
|
142
|
+
"""
|
143
|
+
Exception raised when a filter operation fails.
|
144
|
+
|
145
|
+
This exception occurs when there's an error in the filter expression, such as:
|
146
|
+
- Using single equals (=) instead of double equals (==) for comparison
|
147
|
+
- Syntax errors in the filter expression
|
148
|
+
- Reference to non-existent columns
|
149
|
+
- Type errors in comparisons
|
150
|
+
|
151
|
+
To fix this error:
|
152
|
+
1. Use == (double equals) for equality comparisons, not = (single equals)
|
153
|
+
2. Check the filter expression syntax
|
154
|
+
3. Verify all columns referenced in the expression exist
|
155
|
+
4. Ensure type compatibility in comparisons
|
156
|
+
|
157
|
+
Examples:
|
158
|
+
```python
|
159
|
+
results.filter("column = value") # Raises ResultsFilterError (use == instead)
|
160
|
+
results.filter("column == undefined_var") # Raises ResultsFilterError if undefined_var isn't defined
|
161
|
+
```
|
162
|
+
"""
|
163
|
+
relevant_doc = "https://docs.expectedparrot.com/en/latest/results.html#filtering-results"
|
edsl/results/report.py
CHANGED
edsl/results/result.py
CHANGED
@@ -23,7 +23,7 @@ maintaining a rich object model.
|
|
23
23
|
from __future__ import annotations
|
24
24
|
import inspect
|
25
25
|
from collections import UserDict
|
26
|
-
from typing import Any,
|
26
|
+
from typing import Any, Callable, Optional, TYPE_CHECKING, Union
|
27
27
|
|
28
28
|
from ..base import Base
|
29
29
|
from ..utilities import remove_edsl_version
|
@@ -35,7 +35,6 @@ if TYPE_CHECKING:
|
|
35
35
|
from ..agents import Agent
|
36
36
|
from ..scenarios import Scenario
|
37
37
|
from ..language_models import LanguageModel
|
38
|
-
from ..prompts import Prompt
|
39
38
|
from ..surveys import Survey
|
40
39
|
|
41
40
|
QuestionName = str
|
@@ -259,7 +258,7 @@ class Result(Base, UserDict):
|
|
259
258
|
|
260
259
|
def check_expression(self, expression: str) -> None:
|
261
260
|
for key in self.problem_keys:
|
262
|
-
if key in expression and
|
261
|
+
if key in expression and key + "." not in expression:
|
263
262
|
raise ValueError(
|
264
263
|
f"Key by iself {key} is problematic. Use the full key {key + '.' + key} name instead."
|
265
264
|
)
|
@@ -307,7 +306,7 @@ class Result(Base, UserDict):
|
|
307
306
|
return self._combined_dict
|
308
307
|
|
309
308
|
@property
|
310
|
-
def
|
309
|
+
def get_problem_keys(self) -> list[str]:
|
311
310
|
"""Return a list of keys that are problematic."""
|
312
311
|
if self._combined_dict is None or self._problem_keys is None:
|
313
312
|
self._compute_combined_dict_and_problem_keys()
|
@@ -579,7 +578,7 @@ class Result(Base, UserDict):
|
|
579
578
|
|
580
579
|
def get_question_results(
|
581
580
|
model_response_objects,
|
582
|
-
) -> dict[str,
|
581
|
+
) -> dict[str, Any]:
|
583
582
|
"""Maps the question name to the EDSLResultObjectInput."""
|
584
583
|
question_results = {}
|
585
584
|
for result in model_response_objects:
|
edsl/results/results.py
CHANGED
@@ -41,7 +41,7 @@ import json
|
|
41
41
|
import random
|
42
42
|
import warnings
|
43
43
|
from collections import UserList, defaultdict
|
44
|
-
from typing import Optional, Callable, Any,
|
44
|
+
from typing import Optional, Callable, Any, Union, List, TYPE_CHECKING
|
45
45
|
from bisect import bisect_left
|
46
46
|
|
47
47
|
from ..base import Base
|
@@ -50,7 +50,6 @@ if TYPE_CHECKING:
|
|
50
50
|
from ..surveys import Survey
|
51
51
|
from ..data import Cache
|
52
52
|
from ..agents import AgentList
|
53
|
-
from ..language_models import Model
|
54
53
|
from ..scenarios import ScenarioList
|
55
54
|
from ..results import Result
|
56
55
|
from ..tasks import TaskHistory
|
@@ -113,13 +112,13 @@ def ensure_ready(method):
|
|
113
112
|
|
114
113
|
class NotReadyObject:
|
115
114
|
"""A placeholder object that prints a message when any attribute is accessed."""
|
116
|
-
def __init__(self, name: str, job_info: '
|
115
|
+
def __init__(self, name: str, job_info: 'Any'):
|
117
116
|
self.name = name
|
118
117
|
self.job_info = job_info
|
119
118
|
#print(f"Not ready to call {name}")
|
120
119
|
|
121
120
|
def __repr__(self):
|
122
|
-
message =
|
121
|
+
message = """Results not ready - job still running on server."""
|
123
122
|
for key, value in self.job_info.creation_data.items():
|
124
123
|
message += f"\n{key}: {value}"
|
125
124
|
return message
|
@@ -231,26 +230,6 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
231
230
|
if hasattr(self, "_add_output_functions"):
|
232
231
|
self._add_output_functions()
|
233
232
|
|
234
|
-
def long(self):
|
235
|
-
return self.table().long()
|
236
|
-
|
237
|
-
def print_long(self, max_rows: int = None) -> None:
|
238
|
-
"""Print the results in long format.
|
239
|
-
|
240
|
-
>>> from edsl.results import Results
|
241
|
-
>>> r = Results.example()
|
242
|
-
>>> r.select('how_feeling').print_long(max_rows = 2)
|
243
|
-
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┓
|
244
|
-
┃ Result index ┃ Key ┃ Value ┃
|
245
|
-
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━┩
|
246
|
-
│ 0 │ how_feeling │ OK │
|
247
|
-
│ 1 │ how_feeling │ Great │
|
248
|
-
└──────────────┴─────────────┴───────┘
|
249
|
-
"""
|
250
|
-
from edsl.utilities.interface import print_results_long
|
251
|
-
|
252
|
-
print_results_long(self, max_rows=max_rows)
|
253
|
-
|
254
233
|
|
255
234
|
def _fetch_list(self, data_type: str, key: str) -> list:
|
256
235
|
"""
|
@@ -467,7 +446,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
467
446
|
self.fetch_remote(self.job_info)
|
468
447
|
|
469
448
|
if not self.completed:
|
470
|
-
return
|
449
|
+
return "Results not ready to call"
|
471
450
|
|
472
451
|
return super()._repr_html_()
|
473
452
|
|
@@ -482,7 +461,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
482
461
|
def table(
|
483
462
|
self,
|
484
463
|
*fields,
|
485
|
-
tablefmt: Optional[str] =
|
464
|
+
tablefmt: Optional[str] = "rich",
|
486
465
|
pretty_labels: Optional[dict] = None,
|
487
466
|
print_parameters: Optional[dict] = None,
|
488
467
|
):
|
@@ -599,7 +578,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
599
578
|
def hashes(self) -> set:
|
600
579
|
return set(hash(result) for result in self.data)
|
601
580
|
|
602
|
-
def
|
581
|
+
def _sample_legacy(self, n: int) -> Results:
|
603
582
|
"""Return a random sample of the results.
|
604
583
|
|
605
584
|
:param n: The number of samples to return.
|
@@ -643,7 +622,6 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
643
622
|
from ..caching import Cache
|
644
623
|
from ..results import Result
|
645
624
|
from ..tasks import TaskHistory
|
646
|
-
from ..agents import Agent
|
647
625
|
|
648
626
|
survey = Survey.from_dict(data["survey"])
|
649
627
|
results_data = [Result.from_dict(r) for r in data["data"]]
|
@@ -1076,26 +1054,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
1076
1054
|
created_columns=self.created_columns + [var_name],
|
1077
1055
|
)
|
1078
1056
|
|
1079
|
-
|
1080
|
-
def add_column(self, column_name: str, values: list) -> Results:
|
1081
|
-
"""Adds columns to Results
|
1082
|
-
|
1083
|
-
>>> r = Results.example()
|
1084
|
-
>>> r.add_column('a', [1,2,3, 4]).select('a')
|
1085
|
-
Dataset([{'answer.a': [1, 2, 3, 4]}])
|
1086
|
-
"""
|
1087
|
-
|
1088
|
-
assert len(values) == len(
|
1089
|
-
self.data
|
1090
|
-
), "The number of values must match the number of results."
|
1091
|
-
new_results = self.data.copy()
|
1092
|
-
for i, result in enumerate(new_results):
|
1093
|
-
result["answer"][column_name] = values[i]
|
1094
|
-
return Results(
|
1095
|
-
survey=self.survey,
|
1096
|
-
data=new_results,
|
1097
|
-
created_columns=self.created_columns + [column_name],
|
1098
|
-
)
|
1057
|
+
# Method removed due to duplication (F811)
|
1099
1058
|
|
1100
1059
|
@ensure_ready
|
1101
1060
|
def rename(self, old_name: str, new_name: str) -> Results:
|
@@ -1275,7 +1234,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
1275
1234
|
def to_numeric_if_possible(v):
|
1276
1235
|
try:
|
1277
1236
|
return float(v)
|
1278
|
-
except:
|
1237
|
+
except (ValueError, TypeError):
|
1279
1238
|
return v
|
1280
1239
|
|
1281
1240
|
def sort_key(item):
|
@@ -1444,7 +1403,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
1444
1403
|
return [r.score_with_answer_key(answer_key) for r in self.data]
|
1445
1404
|
|
1446
1405
|
|
1447
|
-
def fetch_remote(self, job_info:
|
1406
|
+
def fetch_remote(self, job_info: Any) -> None:
|
1448
1407
|
"""
|
1449
1408
|
Fetches the remote Results object using the provided RemoteJobInfo and updates this instance with the remote data.
|
1450
1409
|
|
@@ -1532,7 +1491,7 @@ class Results(UserList, ResultsOperationsMixin, Base):
|
|
1532
1491
|
from ..questions import QuestionFreeText, QuestionDict
|
1533
1492
|
from ..surveys import Survey
|
1534
1493
|
from ..scenarios import Scenario, ScenarioList
|
1535
|
-
from ..language_models import
|
1494
|
+
from ..language_models import ModelList
|
1536
1495
|
import pandas as pd
|
1537
1496
|
|
1538
1497
|
df = self.select("agent.*", "scenario.*", "answer.*", "raw_model_response.*", "prompt.*").to_pandas()
|
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 edsl.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 edsl.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
|
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[str | None]] = 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
|
|