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/surveys/survey.py
CHANGED
@@ -25,10 +25,8 @@ from typing import (
|
|
25
25
|
TYPE_CHECKING,
|
26
26
|
Dict,
|
27
27
|
Tuple,
|
28
|
-
Set,
|
29
|
-
Type,
|
30
28
|
)
|
31
|
-
from typing_extensions import Literal
|
29
|
+
from typing_extensions import Literal
|
32
30
|
from ..base import Base
|
33
31
|
from ..agents import Agent
|
34
32
|
from ..scenarios import Scenario
|
@@ -45,7 +43,6 @@ if TYPE_CHECKING:
|
|
45
43
|
from ..scenarios import ScenarioList
|
46
44
|
from ..buckets.bucket_collection import BucketCollection
|
47
45
|
from ..key_management.key_lookup import KeyLookup
|
48
|
-
from .memory import Memory
|
49
46
|
|
50
47
|
# Define types for documentation purpose only
|
51
48
|
VisibilityType = Literal["unlisted", "public", "private"]
|
@@ -243,6 +240,14 @@ class Survey(Base):
|
|
243
240
|
|
244
241
|
self._exporter = SurveyExport(self)
|
245
242
|
|
243
|
+
|
244
|
+
# In survey.py
|
245
|
+
@property
|
246
|
+
def ep(self):
|
247
|
+
"""Return plugin host for this survey."""
|
248
|
+
from ..plugins.plugin_host import PluginHost
|
249
|
+
return PluginHost(self)
|
250
|
+
|
246
251
|
def question_names_valid(self) -> bool:
|
247
252
|
"""Check if the question names are valid."""
|
248
253
|
return all(q.is_valid_question_name() for q in self.questions)
|
@@ -350,11 +355,7 @@ class Survey(Base):
|
|
350
355
|
|
351
356
|
This doesnt' work with questions that don't exist:
|
352
357
|
|
353
|
-
|
354
|
-
Traceback (most recent call last):
|
355
|
-
...
|
356
|
-
edsl.surveys.exceptions.SurveyError: Question name poop not found in survey. The current question names are {'q0': 0, 'q1': 1, 'q2': 2}.
|
357
|
-
...
|
358
|
+
# Example with a non-existent question name would raise SurveyError
|
358
359
|
"""
|
359
360
|
if q is EndOfSurvey:
|
360
361
|
return EndOfSurvey
|
@@ -609,11 +610,6 @@ class Survey(Base):
|
|
609
610
|
>>> s1 = Survey.example()
|
610
611
|
>>> from edsl import QuestionFreeText
|
611
612
|
>>> s2 = Survey([QuestionFreeText(question_text="What is your name?", question_name="yo")])
|
612
|
-
>>> s3 = s1 + s2
|
613
|
-
Traceback (most recent call last):
|
614
|
-
...
|
615
|
-
edsl.surveys.exceptions.SurveyCreationError: ...
|
616
|
-
...
|
617
613
|
>>> s3 = s1.clear_non_default_rules() + s2
|
618
614
|
>>> len(s3.questions)
|
619
615
|
4
|
@@ -676,11 +672,7 @@ class Survey(Base):
|
|
676
672
|
>>> q = QuestionMultipleChoice(question_text = "Do you like school?", question_options=["yes", "no"], question_name="q0")
|
677
673
|
>>> s = Survey().add_question(q)
|
678
674
|
|
679
|
-
|
680
|
-
Traceback (most recent call last):
|
681
|
-
...
|
682
|
-
edsl.surveys.exceptions.SurveyCreationError: Question name 'q0' already exists in survey. Existing names are ['q0'].
|
683
|
-
...
|
675
|
+
# Adding a question with a duplicate name would raise SurveyCreationError
|
684
676
|
"""
|
685
677
|
return EditSurvey(self).add_question(question, index)
|
686
678
|
|
@@ -972,11 +964,7 @@ class Survey(Base):
|
|
972
964
|
>>> s.next_question("q0", {"q0.answer": "no"}).question_name
|
973
965
|
'q1'
|
974
966
|
|
975
|
-
|
976
|
-
Traceback (most recent call last):
|
977
|
-
...
|
978
|
-
edsl.surveys.exceptions.SurveyCreationError: The expression contains '<>', which is not allowed. You probably mean '!='.
|
979
|
-
...
|
967
|
+
# Using invalid operators like '<>' would raise SurveyCreationError
|
980
968
|
"""
|
981
969
|
return RuleManager(self).add_stop_rule(question, expression)
|
982
970
|
|
edsl/surveys/survey_export.py
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
"""A class for exporting surveys to different formats."""
|
2
2
|
|
3
|
-
from typing import Union, Optional
|
3
|
+
from typing import Union, Optional, TYPE_CHECKING
|
4
4
|
|
5
5
|
import subprocess
|
6
6
|
import platform
|
7
7
|
import os
|
8
8
|
import tempfile
|
9
9
|
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from docx import Document
|
12
|
+
from ..scenarios import ScenarioList
|
13
|
+
|
10
14
|
|
11
15
|
def open_docx(file_path):
|
12
16
|
"""
|
@@ -61,7 +65,7 @@ class SurveyExport:
|
|
61
65
|
|
62
66
|
doc = Document()
|
63
67
|
doc.add_heading("EDSL Survey")
|
64
|
-
doc.add_paragraph(
|
68
|
+
doc.add_paragraph("\n")
|
65
69
|
for index, question in enumerate(self.survey._questions):
|
66
70
|
h = doc.add_paragraph() # Add question as a paragraph
|
67
71
|
h.add_run(f"Question {index + 1} ({question.question_name})").bold = True
|
@@ -176,7 +180,6 @@ class SurveyExport:
|
|
176
180
|
include_question_name=False,
|
177
181
|
):
|
178
182
|
from IPython.display import display, HTML
|
179
|
-
import tempfile
|
180
183
|
import os
|
181
184
|
from edsl.utilities.utilities import is_notebook
|
182
185
|
|
@@ -1,10 +1,19 @@
|
|
1
1
|
"""A mixin for visualizing the flow of a survey with parameter nodes."""
|
2
2
|
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional
|
4
4
|
from edsl.surveys.base import RulePriority, EndOfSurvey
|
5
5
|
import tempfile
|
6
6
|
|
7
7
|
|
8
|
+
# Import types for annotations
|
9
|
+
from typing import TYPE_CHECKING
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from ..surveys.survey import Survey
|
13
|
+
from ..scenarios import Scenario
|
14
|
+
from ..agents import Agent
|
15
|
+
|
16
|
+
|
8
17
|
class SurveyFlowVisualization:
|
9
18
|
"""A mixin for visualizing the flow of a survey with parameter visualization."""
|
10
19
|
|
edsl/tasks/__init__.py
CHANGED
@@ -26,6 +26,8 @@ For most users, this module works behind the scenes, but understanding it can
|
|
26
26
|
be helpful when debugging or optimizing complex EDSL workflows.
|
27
27
|
"""
|
28
28
|
|
29
|
+
__all__ = ['TaskHistory', 'QuestionTaskCreator', 'TaskCreators', 'TaskStatus', 'TaskStatusDescriptor']
|
30
|
+
|
29
31
|
from .task_history import TaskHistory
|
30
32
|
from .question_task_creator import QuestionTaskCreator
|
31
33
|
from .task_creators import TaskCreators
|
@@ -8,7 +8,7 @@ execution unit in EDSL's task system.
|
|
8
8
|
"""
|
9
9
|
|
10
10
|
import asyncio
|
11
|
-
from typing import Callable,
|
11
|
+
from typing import Callable, Optional, TYPE_CHECKING
|
12
12
|
from collections import UserList, UserDict
|
13
13
|
|
14
14
|
from ..jobs.exceptions import InterviewErrorPriorTaskCanceled
|
@@ -170,12 +170,12 @@ class QuestionTaskCreator(UserList):
|
|
170
170
|
"""
|
171
171
|
|
172
172
|
requested_tokens = self.estimated_tokens()
|
173
|
-
if (
|
173
|
+
if (self.tokens_bucket.wait_time(requested_tokens)) > 0:
|
174
174
|
self.task_status = TaskStatus.WAITING_FOR_TOKEN_CAPACITY
|
175
175
|
|
176
176
|
await self.tokens_bucket.get_tokens(requested_tokens)
|
177
177
|
|
178
|
-
if
|
178
|
+
if self.model_buckets.requests_bucket.wait_time(1) > 0:
|
179
179
|
self.waiting = True # do we need this?
|
180
180
|
self.task_status = TaskStatus.WAITING_FOR_REQUEST_CAPACITY
|
181
181
|
|
edsl/tasks/task_creators.py
CHANGED
@@ -6,15 +6,13 @@ for executing a single question within an interview. It aggregates status and to
|
|
6
6
|
information across all tasks, providing a complete view of interview execution.
|
7
7
|
"""
|
8
8
|
|
9
|
-
from typing import
|
9
|
+
from typing import List, TYPE_CHECKING
|
10
10
|
from collections import UserDict
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
|
-
from ..tokens import TokenUsage
|
14
13
|
from ..tokens import InterviewTokenUsage
|
15
14
|
from ..interviews import InterviewStatusDictionary
|
16
15
|
from .task_status_log import TaskStatusLog
|
17
|
-
from .question_task_creator import QuestionTaskCreator
|
18
16
|
|
19
17
|
class TaskCreators(UserDict):
|
20
18
|
"""
|
edsl/tasks/task_history.py
CHANGED
@@ -7,7 +7,10 @@ visualization and reporting to help users understand task execution patterns and
|
|
7
7
|
issues.
|
8
8
|
"""
|
9
9
|
|
10
|
-
from typing import List, Optional,
|
10
|
+
from typing import List, Optional, TYPE_CHECKING
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from ..interviews import Interview
|
11
14
|
from io import BytesIO
|
12
15
|
import base64
|
13
16
|
import os
|
@@ -89,12 +92,10 @@ class TaskHistory(RepresentationMixin):
|
|
89
92
|
@classmethod
|
90
93
|
def example(cls):
|
91
94
|
""" """
|
92
|
-
from ..interviews import Interview
|
93
95
|
from ..jobs import Jobs
|
94
96
|
|
95
97
|
j = Jobs.example(throw_exception_probability=1, test_model=True)
|
96
98
|
|
97
|
-
from edsl.config import CONFIG
|
98
99
|
|
99
100
|
results = j.run(
|
100
101
|
print_exceptions=False,
|
@@ -404,7 +405,7 @@ class TaskHistory(RepresentationMixin):
|
|
404
405
|
|
405
406
|
models_used = set([i.model.model for index, i in self._interviews.items()])
|
406
407
|
|
407
|
-
from jinja2 import Environment
|
408
|
+
from jinja2 import Environment
|
408
409
|
from edsl.utilities import TemplateLoader
|
409
410
|
|
410
411
|
env = Environment(loader=TemplateLoader("edsl", "templates/error_reporting"))
|
@@ -463,7 +464,6 @@ class TaskHistory(RepresentationMixin):
|
|
463
464
|
- Exception details, status transitions, and timing are all included
|
464
465
|
"""
|
465
466
|
from IPython.display import display, HTML
|
466
|
-
import tempfile
|
467
467
|
import os
|
468
468
|
from edsl.utilities.utilities import is_notebook
|
469
469
|
|
@@ -509,8 +509,6 @@ class TaskHistory(RepresentationMixin):
|
|
509
509
|
"""Create a notebook with the HTML content embedded in the first cell, then delete the cell content while keeping the output."""
|
510
510
|
from nbformat import v4 as nbf
|
511
511
|
from nbconvert.preprocessors import ExecutePreprocessor
|
512
|
-
import nbformat
|
513
|
-
import os
|
514
512
|
|
515
513
|
# Use the existing html method to generate the HTML content
|
516
514
|
output_html = self.generate_html_report(css=None)
|
edsl/tasks/task_status_log.py
CHANGED
@@ -7,9 +7,8 @@ execution, including timing, state transitions, and status at any point in time.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from collections import UserList
|
10
|
-
from typing import List, Optional, Union
|
11
10
|
|
12
|
-
from .task_status_enum import TaskStatus
|
11
|
+
from .task_status_enum import TaskStatus
|
13
12
|
|
14
13
|
|
15
14
|
class TaskStatusLog(UserList):
|
edsl/tokens/__init__.py
CHANGED
edsl/tokens/token_usage.py
CHANGED
@@ -17,7 +17,7 @@ class TokenUsage:
|
|
17
17
|
if not isinstance(other, TokenUsage):
|
18
18
|
raise ValueError(f"Can't add {type(other)} to InterviewTokenUsage")
|
19
19
|
if self.from_cache != other.from_cache:
|
20
|
-
raise ValueError(
|
20
|
+
raise ValueError("Can't add token usages from different sources")
|
21
21
|
return TokenUsage(
|
22
22
|
from_cache=self.from_cache,
|
23
23
|
prompt_tokens=self.prompt_tokens + other.prompt_tokens,
|
edsl/utilities/__init__.py
CHANGED
@@ -26,5 +26,25 @@ from .is_valid_variable_name import is_valid_variable_name
|
|
26
26
|
from .naming_utilities import sanitize_string
|
27
27
|
|
28
28
|
# Interface module - note: print_results_long is imported directly in results.py
|
29
|
-
|
29
|
+
|
30
|
+
__all__ = [
|
31
|
+
"TemplateLoader",
|
32
|
+
"PrettyList",
|
33
|
+
"create_restricted_function",
|
34
|
+
"remove_edsl_version",
|
35
|
+
"extract_variable_names",
|
36
|
+
"clean_json",
|
37
|
+
"dict_hash",
|
38
|
+
"hash_value",
|
39
|
+
"repair_json",
|
40
|
+
"create_valid_var_name",
|
41
|
+
"random_string",
|
42
|
+
"shorten_string",
|
43
|
+
"is_gzipped",
|
44
|
+
"sync_wrapper",
|
45
|
+
"jupyter_nb_handler",
|
46
|
+
"is_notebook",
|
47
|
+
"is_valid_variable_name",
|
48
|
+
"sanitize_string"
|
49
|
+
]
|
30
50
|
|
edsl/utilities/decorators.py
CHANGED
@@ -69,7 +69,7 @@ class MarkdownToDocx:
|
|
69
69
|
|
70
70
|
try:
|
71
71
|
# Run pandoc command
|
72
|
-
|
72
|
+
subprocess.run(
|
73
73
|
cmd,
|
74
74
|
input=self.markdown_content,
|
75
75
|
text=True,
|
@@ -115,7 +115,7 @@ class MarkdownToDocx:
|
|
115
115
|
cmd = ["pandoc", "--print-default-data-file", "reference.docx"]
|
116
116
|
|
117
117
|
with open(output_path, "wb") as f:
|
118
|
-
|
118
|
+
subprocess.run(cmd, stdout=f, check=True)
|
119
119
|
return True
|
120
120
|
except subprocess.CalledProcessError as e:
|
121
121
|
print(f"Error creating template: {e.stderr}")
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from importlib import resources
|
2
2
|
from jinja2 import BaseLoader, TemplateNotFound
|
3
|
-
import os
|
4
3
|
|
5
4
|
|
6
5
|
class TemplateLoader(BaseLoader):
|
@@ -10,8 +9,8 @@ class TemplateLoader(BaseLoader):
|
|
10
9
|
|
11
10
|
def get_source(self, environment, template):
|
12
11
|
try:
|
13
|
-
|
14
|
-
template_path
|
12
|
+
# Split template path into components
|
13
|
+
# (template_path from os.path.join is no longer needed with importlib.resources)
|
15
14
|
|
16
15
|
# Use resources.files() to get a Traversable object
|
17
16
|
templates = resources.files(self.package_name).joinpath(self.templates_dir)
|
edsl/utilities/utilities.py
CHANGED
@@ -14,7 +14,6 @@ import string
|
|
14
14
|
import tempfile
|
15
15
|
import gzip
|
16
16
|
import webbrowser
|
17
|
-
import json
|
18
17
|
|
19
18
|
from html import escape
|
20
19
|
from typing import Callable, Union
|
@@ -90,9 +89,9 @@ def fix_partial_correct_response(text: str) -> dict:
|
|
90
89
|
start_pos = text.find(json_object)
|
91
90
|
stop_pos = start_pos + len(json_object)
|
92
91
|
|
93
|
-
#
|
92
|
+
# Validate the JSON
|
94
93
|
try:
|
95
|
-
|
94
|
+
json.loads(json_object) # Just validate, don't need to keep the parsed result
|
96
95
|
except json.JSONDecodeError:
|
97
96
|
return {"error": "Failed to parse JSON object"}
|
98
97
|
|
@@ -215,17 +214,8 @@ def is_notebook() -> bool:
|
|
215
214
|
|
216
215
|
def file_notice(file_name):
|
217
216
|
"""Print a notice about the file being created."""
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
link_text = "Download file"
|
222
|
-
display(
|
223
|
-
HTML(
|
224
|
-
f'<p>File created: {file_name}</p>.<a href="{file_name}" download>{link_text}</a>'
|
225
|
-
)
|
226
|
-
)
|
227
|
-
else:
|
228
|
-
print(f"File created: {file_name}")
|
217
|
+
from ..display import file_notice as display_file_notice
|
218
|
+
display_file_notice(file_name, link_text="Download file")
|
229
219
|
|
230
220
|
|
231
221
|
class HTMLSnippet(str):
|
@@ -316,20 +306,7 @@ def merge_dicts(dict_list):
|
|
316
306
|
result[key] = [d.get(key, None) for d in dict_list]
|
317
307
|
return result
|
318
308
|
|
319
|
-
|
320
|
-
def extract_json_from_string(s):
|
321
|
-
"""Extract a JSON string from a string."""
|
322
|
-
# Find the first occurrence of '{'
|
323
|
-
start_idx = s.find("{")
|
324
|
-
# Find the last occurrence of '}'
|
325
|
-
end_idx = s.rfind("}")
|
326
|
-
# If both '{' and '}' are found in the string
|
327
|
-
if start_idx != -1 and end_idx != -1 and start_idx < end_idx:
|
328
|
-
# Extract the substring from start_idx to end_idx (inclusive)
|
329
|
-
json_str = s[start_idx : end_idx + 1]
|
330
|
-
return json_str
|
331
|
-
else:
|
332
|
-
raise ValueError("No JSON object found in string")
|
309
|
+
# Note: extract_json_from_string is already defined above (line 58)
|
333
310
|
|
334
311
|
|
335
312
|
def valid_json(json_string):
|
@@ -354,7 +331,9 @@ def is_valid_variable_name(name, allow_name=True):
|
|
354
331
|
def create_valid_var_name(s, transform_func: Callable = lambda x: x.lower()) -> str:
|
355
332
|
"""Create a valid variable name from a string."""
|
356
333
|
if transform_func is None:
|
357
|
-
|
334
|
+
def identity(x):
|
335
|
+
return x
|
336
|
+
transform_func = identity
|
358
337
|
|
359
338
|
# Ensure the string is not empty
|
360
339
|
if not s:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: edsl
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.50
|
4
4
|
Summary: Create and analyze LLM-based surveys
|
5
5
|
Home-page: https://www.expectedparrot.com/
|
6
6
|
License: MIT
|
@@ -36,6 +36,7 @@ Requires-Dist: openai (>=1.4.0,<2.0.0)
|
|
36
36
|
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
37
37
|
Requires-Dist: pandas (>=2.1.4,<3.0.0)
|
38
38
|
Requires-Dist: platformdirs (>=4.3.6,<5.0.0)
|
39
|
+
Requires-Dist: pluggy (>=1.3.0,<2.0.0)
|
39
40
|
Requires-Dist: pydot (>=2.0.0,<3.0.0)
|
40
41
|
Requires-Dist: pygments (>=2.17.2,<3.0.0)
|
41
42
|
Requires-Dist: pypdf2 (>=3.0.1,<4.0.0)
|
@@ -50,6 +51,7 @@ Requires-Dist: simpleeval (>=0.9.13,<0.10.0)
|
|
50
51
|
Requires-Dist: sqlalchemy (>=2.0.23,<3.0.0)
|
51
52
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
52
53
|
Requires-Dist: tenacity (>=8.2.3,<9.0.0)
|
54
|
+
Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
|
53
55
|
Requires-Dist: urllib3 (>=1.25.4,<1.27)
|
54
56
|
Project-URL: Documentation, https://docs.expectedparrot.com
|
55
57
|
Description-Content-Type: text/markdown
|
@@ -198,6 +200,27 @@ results.select("color", "flower")
|
|
198
200
|
**Caching**:
|
199
201
|
API calls to LLMs are cached automatically, allowing you to retrieve responses to questions that have already been run and reproduce experiments at no cost. Learn more about how the <a href="https://docs.expectedparrot.com/en/latest/remote_caching.html" target="_blank" rel="noopener noreferrer">universal remote cache</a> works.
|
200
202
|
|
203
|
+
**Logging**:
|
204
|
+
EDSL includes a comprehensive logging system to help with debugging and monitoring. Control log levels and see important information about operations:
|
205
|
+
|
206
|
+
```python
|
207
|
+
from edsl import logger
|
208
|
+
import logging
|
209
|
+
|
210
|
+
# Set the logging level
|
211
|
+
logger.set_level(logging.DEBUG) # Show all log messages
|
212
|
+
|
213
|
+
# Get a module-specific logger
|
214
|
+
my_logger = logger.get_logger(__name__)
|
215
|
+
my_logger.info("This is a module-specific log message")
|
216
|
+
|
217
|
+
# Log messages at different levels
|
218
|
+
logger.debug("Detailed debugging information")
|
219
|
+
logger.info("General information about operation")
|
220
|
+
logger.warning("Something unexpected but not critical")
|
221
|
+
logger.error("Something went wrong")
|
222
|
+
```
|
223
|
+
|
201
224
|
**Flexibility**:
|
202
225
|
Choose whether to run surveys on your own computer or at the Expected Parrot server.
|
203
226
|
|
@@ -231,6 +254,13 @@ Analyze results as specified datasets from your account or workspace. Easily imp
|
|
231
254
|
- API keys for language models. You can use your own keys or an Expected Parrot key that provides access to all available models.
|
232
255
|
See instructions on <a href="https://docs.expectedparrot.com/en/latest/api_keys.html" target="_blank" rel="noopener noreferrer">managing keys</a> and <a href="https://www.expectedparrot.com/getting-started/coop-pricing" target="_blank" rel="noopener noreferrer">model pricing and performance</a> information.
|
233
256
|
|
257
|
+
## Developer Notes
|
258
|
+
|
259
|
+
### Running Tests
|
260
|
+
- Unit tests: `python -m pytest tests/`
|
261
|
+
- Integration tests: `python -m pytest integration/`
|
262
|
+
- Doctests: `python run_doctests.py` (use `-v` flag for verbose output)
|
263
|
+
|
234
264
|
## Coop
|
235
265
|
An integrated platform for running experiments, sharing workflows and launching hybrid human/AI surveys.
|
236
266
|
- <a href="https://www.expectedparrot.com/login" target="_blank" rel="noopener noreferrer">Login / Signup</a>
|
@@ -243,5 +273,5 @@ An integrated platform for running experiments, sharing workflows and launching
|
|
243
273
|
- <a href="https://blog.expectedparrot.com" target="_blank" rel="noopener noreferrer">Blog</a>.
|
244
274
|
|
245
275
|
## Contact
|
246
|
-
- <a href="mailto:info@expectedparrot.com" target="_blank" rel="noopener noreferrer">Email</a
|
276
|
+
- <a href="mailto:info@expectedparrot.com" target="_blank" rel="noopener noreferrer">Email</a>.
|
247
277
|
|