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.
Files changed (257) hide show
  1. edsl/__init__.py +124 -53
  2. edsl/__version__.py +1 -1
  3. edsl/agents/agent.py +21 -21
  4. edsl/agents/agent_list.py +2 -5
  5. edsl/agents/exceptions.py +119 -5
  6. edsl/base/__init__.py +10 -35
  7. edsl/base/base_class.py +71 -36
  8. edsl/base/base_exception.py +204 -0
  9. edsl/base/data_transfer_models.py +1 -1
  10. edsl/base/exceptions.py +94 -0
  11. edsl/buckets/__init__.py +15 -1
  12. edsl/buckets/bucket_collection.py +3 -4
  13. edsl/buckets/exceptions.py +107 -0
  14. edsl/buckets/model_buckets.py +1 -2
  15. edsl/buckets/token_bucket.py +11 -6
  16. edsl/buckets/token_bucket_api.py +27 -12
  17. edsl/buckets/token_bucket_client.py +9 -7
  18. edsl/caching/cache.py +12 -4
  19. edsl/caching/cache_entry.py +10 -9
  20. edsl/caching/exceptions.py +113 -7
  21. edsl/caching/remote_cache_sync.py +6 -7
  22. edsl/caching/sql_dict.py +20 -14
  23. edsl/cli.py +43 -0
  24. edsl/config/__init__.py +1 -1
  25. edsl/config/config_class.py +32 -6
  26. edsl/conversation/Conversation.py +8 -4
  27. edsl/conversation/car_buying.py +1 -3
  28. edsl/conversation/exceptions.py +58 -0
  29. edsl/conversation/mug_negotiation.py +2 -8
  30. edsl/coop/__init__.py +28 -6
  31. edsl/coop/coop.py +120 -29
  32. edsl/coop/coop_functions.py +1 -1
  33. edsl/coop/ep_key_handling.py +1 -1
  34. edsl/coop/exceptions.py +188 -9
  35. edsl/coop/price_fetcher.py +5 -8
  36. edsl/coop/utils.py +4 -6
  37. edsl/dataset/__init__.py +5 -4
  38. edsl/dataset/dataset.py +177 -86
  39. edsl/dataset/dataset_operations_mixin.py +98 -76
  40. edsl/dataset/dataset_tree.py +11 -7
  41. edsl/dataset/display/table_display.py +0 -2
  42. edsl/dataset/display/table_renderers.py +6 -4
  43. edsl/dataset/exceptions.py +125 -0
  44. edsl/dataset/file_exports.py +18 -11
  45. edsl/dataset/r/ggplot.py +13 -6
  46. edsl/display/__init__.py +27 -0
  47. edsl/display/core.py +147 -0
  48. edsl/display/plugin.py +189 -0
  49. edsl/display/utils.py +52 -0
  50. edsl/inference_services/__init__.py +9 -1
  51. edsl/inference_services/available_model_cache_handler.py +1 -1
  52. edsl/inference_services/available_model_fetcher.py +5 -6
  53. edsl/inference_services/data_structures.py +10 -7
  54. edsl/inference_services/exceptions.py +132 -1
  55. edsl/inference_services/inference_service_abc.py +2 -2
  56. edsl/inference_services/inference_services_collection.py +2 -6
  57. edsl/inference_services/registry.py +4 -3
  58. edsl/inference_services/service_availability.py +4 -3
  59. edsl/inference_services/services/anthropic_service.py +4 -1
  60. edsl/inference_services/services/aws_bedrock.py +13 -12
  61. edsl/inference_services/services/azure_ai.py +12 -10
  62. edsl/inference_services/services/deep_infra_service.py +1 -4
  63. edsl/inference_services/services/deep_seek_service.py +1 -5
  64. edsl/inference_services/services/google_service.py +7 -3
  65. edsl/inference_services/services/groq_service.py +1 -1
  66. edsl/inference_services/services/mistral_ai_service.py +4 -2
  67. edsl/inference_services/services/ollama_service.py +1 -1
  68. edsl/inference_services/services/open_ai_service.py +7 -5
  69. edsl/inference_services/services/perplexity_service.py +6 -2
  70. edsl/inference_services/services/test_service.py +8 -7
  71. edsl/inference_services/services/together_ai_service.py +2 -3
  72. edsl/inference_services/services/xai_service.py +1 -1
  73. edsl/instructions/__init__.py +1 -1
  74. edsl/instructions/change_instruction.py +7 -5
  75. edsl/instructions/exceptions.py +61 -0
  76. edsl/instructions/instruction.py +6 -2
  77. edsl/instructions/instruction_collection.py +6 -4
  78. edsl/instructions/instruction_handler.py +12 -15
  79. edsl/interviews/ReportErrors.py +0 -3
  80. edsl/interviews/__init__.py +9 -2
  81. edsl/interviews/answering_function.py +11 -13
  82. edsl/interviews/exception_tracking.py +15 -8
  83. edsl/interviews/exceptions.py +79 -0
  84. edsl/interviews/interview.py +33 -30
  85. edsl/interviews/interview_status_dictionary.py +4 -2
  86. edsl/interviews/interview_status_log.py +2 -1
  87. edsl/interviews/interview_task_manager.py +5 -5
  88. edsl/interviews/request_token_estimator.py +5 -2
  89. edsl/interviews/statistics.py +3 -4
  90. edsl/invigilators/__init__.py +7 -1
  91. edsl/invigilators/exceptions.py +79 -0
  92. edsl/invigilators/invigilator_base.py +0 -1
  93. edsl/invigilators/invigilators.py +9 -13
  94. edsl/invigilators/prompt_constructor.py +1 -5
  95. edsl/invigilators/prompt_helpers.py +8 -4
  96. edsl/invigilators/question_instructions_prompt_builder.py +1 -1
  97. edsl/invigilators/question_option_processor.py +9 -5
  98. edsl/invigilators/question_template_replacements_builder.py +3 -2
  99. edsl/jobs/__init__.py +42 -5
  100. edsl/jobs/async_interview_runner.py +25 -23
  101. edsl/jobs/check_survey_scenario_compatibility.py +11 -10
  102. edsl/jobs/data_structures.py +8 -5
  103. edsl/jobs/exceptions.py +177 -8
  104. edsl/jobs/fetch_invigilator.py +1 -1
  105. edsl/jobs/jobs.py +74 -69
  106. edsl/jobs/jobs_checks.py +6 -7
  107. edsl/jobs/jobs_component_constructor.py +4 -4
  108. edsl/jobs/jobs_pricing_estimation.py +4 -3
  109. edsl/jobs/jobs_remote_inference_logger.py +5 -4
  110. edsl/jobs/jobs_runner_asyncio.py +3 -4
  111. edsl/jobs/jobs_runner_status.py +8 -9
  112. edsl/jobs/remote_inference.py +27 -24
  113. edsl/jobs/results_exceptions_handler.py +10 -7
  114. edsl/key_management/__init__.py +3 -1
  115. edsl/key_management/exceptions.py +62 -0
  116. edsl/key_management/key_lookup.py +1 -1
  117. edsl/key_management/key_lookup_builder.py +37 -14
  118. edsl/key_management/key_lookup_collection.py +2 -0
  119. edsl/language_models/__init__.py +1 -1
  120. edsl/language_models/exceptions.py +302 -14
  121. edsl/language_models/language_model.py +9 -8
  122. edsl/language_models/model.py +4 -4
  123. edsl/language_models/model_list.py +1 -1
  124. edsl/language_models/price_manager.py +1 -1
  125. edsl/language_models/raw_response_handler.py +14 -9
  126. edsl/language_models/registry.py +17 -21
  127. edsl/language_models/repair.py +0 -6
  128. edsl/language_models/unused/fake_openai_service.py +0 -1
  129. edsl/load_plugins.py +69 -0
  130. edsl/logger.py +146 -0
  131. edsl/notebooks/__init__.py +24 -1
  132. edsl/notebooks/exceptions.py +82 -0
  133. edsl/notebooks/notebook.py +7 -3
  134. edsl/notebooks/notebook_to_latex.py +1 -2
  135. edsl/plugins/__init__.py +63 -0
  136. edsl/plugins/built_in/export_example.py +50 -0
  137. edsl/plugins/built_in/pig_latin.py +67 -0
  138. edsl/plugins/cli.py +372 -0
  139. edsl/plugins/cli_typer.py +283 -0
  140. edsl/plugins/exceptions.py +31 -0
  141. edsl/plugins/hookspec.py +51 -0
  142. edsl/plugins/plugin_host.py +128 -0
  143. edsl/plugins/plugin_manager.py +633 -0
  144. edsl/plugins/plugins_registry.py +168 -0
  145. edsl/prompts/__init__.py +24 -1
  146. edsl/prompts/exceptions.py +107 -5
  147. edsl/prompts/prompt.py +15 -7
  148. edsl/questions/HTMLQuestion.py +5 -11
  149. edsl/questions/Quick.py +0 -1
  150. edsl/questions/__init__.py +6 -4
  151. edsl/questions/answer_validator_mixin.py +318 -323
  152. edsl/questions/compose_questions.py +3 -3
  153. edsl/questions/descriptors.py +11 -50
  154. edsl/questions/exceptions.py +278 -22
  155. edsl/questions/loop_processor.py +7 -5
  156. edsl/questions/prompt_templates/question_list.jinja +3 -0
  157. edsl/questions/question_base.py +46 -19
  158. edsl/questions/question_base_gen_mixin.py +2 -2
  159. edsl/questions/question_base_prompts_mixin.py +13 -7
  160. edsl/questions/question_budget.py +503 -98
  161. edsl/questions/question_check_box.py +660 -160
  162. edsl/questions/question_dict.py +345 -194
  163. edsl/questions/question_extract.py +401 -61
  164. edsl/questions/question_free_text.py +80 -14
  165. edsl/questions/question_functional.py +119 -9
  166. edsl/questions/{derived/question_likert_five.py → question_likert_five.py} +2 -2
  167. edsl/questions/{derived/question_linear_scale.py → question_linear_scale.py} +3 -4
  168. edsl/questions/question_list.py +275 -28
  169. edsl/questions/question_matrix.py +643 -96
  170. edsl/questions/question_multiple_choice.py +219 -51
  171. edsl/questions/question_numerical.py +361 -32
  172. edsl/questions/question_rank.py +401 -124
  173. edsl/questions/question_registry.py +7 -5
  174. edsl/questions/{derived/question_top_k.py → question_top_k.py} +3 -3
  175. edsl/questions/{derived/question_yes_no.py → question_yes_no.py} +3 -4
  176. edsl/questions/register_questions_meta.py +2 -2
  177. edsl/questions/response_validator_abc.py +13 -15
  178. edsl/questions/response_validator_factory.py +10 -12
  179. edsl/questions/templates/dict/answering_instructions.jinja +1 -0
  180. edsl/questions/templates/rank/question_presentation.jinja +1 -1
  181. edsl/results/__init__.py +1 -1
  182. edsl/results/exceptions.py +141 -7
  183. edsl/results/report.py +1 -2
  184. edsl/results/result.py +11 -9
  185. edsl/results/results.py +480 -321
  186. edsl/results/results_selector.py +8 -4
  187. edsl/scenarios/PdfExtractor.py +2 -2
  188. edsl/scenarios/construct_download_link.py +69 -35
  189. edsl/scenarios/directory_scanner.py +33 -14
  190. edsl/scenarios/document_chunker.py +1 -1
  191. edsl/scenarios/exceptions.py +238 -14
  192. edsl/scenarios/file_methods.py +1 -1
  193. edsl/scenarios/file_store.py +7 -3
  194. edsl/scenarios/handlers/__init__.py +17 -0
  195. edsl/scenarios/handlers/docx_file_store.py +0 -5
  196. edsl/scenarios/handlers/pdf_file_store.py +0 -1
  197. edsl/scenarios/handlers/pptx_file_store.py +0 -5
  198. edsl/scenarios/handlers/py_file_store.py +0 -1
  199. edsl/scenarios/handlers/sql_file_store.py +1 -4
  200. edsl/scenarios/handlers/sqlite_file_store.py +0 -1
  201. edsl/scenarios/handlers/txt_file_store.py +1 -1
  202. edsl/scenarios/scenario.py +1 -3
  203. edsl/scenarios/scenario_list.py +179 -27
  204. edsl/scenarios/scenario_list_pdf_tools.py +1 -0
  205. edsl/scenarios/scenario_selector.py +0 -1
  206. edsl/surveys/__init__.py +3 -4
  207. edsl/surveys/dag/__init__.py +4 -2
  208. edsl/surveys/descriptors.py +1 -1
  209. edsl/surveys/edit_survey.py +1 -0
  210. edsl/surveys/exceptions.py +165 -9
  211. edsl/surveys/memory/__init__.py +5 -3
  212. edsl/surveys/memory/memory_management.py +1 -0
  213. edsl/surveys/memory/memory_plan.py +6 -15
  214. edsl/surveys/rules/__init__.py +5 -3
  215. edsl/surveys/rules/rule.py +1 -2
  216. edsl/surveys/rules/rule_collection.py +1 -1
  217. edsl/surveys/survey.py +12 -24
  218. edsl/surveys/survey_css.py +3 -3
  219. edsl/surveys/survey_export.py +6 -3
  220. edsl/surveys/survey_flow_visualization.py +10 -1
  221. edsl/surveys/survey_simulator.py +2 -1
  222. edsl/tasks/__init__.py +23 -1
  223. edsl/tasks/exceptions.py +72 -0
  224. edsl/tasks/question_task_creator.py +3 -3
  225. edsl/tasks/task_creators.py +1 -3
  226. edsl/tasks/task_history.py +8 -10
  227. edsl/tasks/task_status_log.py +1 -2
  228. edsl/tokens/__init__.py +29 -1
  229. edsl/tokens/exceptions.py +37 -0
  230. edsl/tokens/interview_token_usage.py +3 -2
  231. edsl/tokens/token_usage.py +4 -3
  232. edsl/utilities/__init__.py +21 -1
  233. edsl/utilities/decorators.py +1 -2
  234. edsl/utilities/markdown_to_docx.py +2 -2
  235. edsl/utilities/markdown_to_pdf.py +1 -1
  236. edsl/utilities/repair_functions.py +0 -1
  237. edsl/utilities/restricted_python.py +0 -1
  238. edsl/utilities/template_loader.py +2 -3
  239. edsl/utilities/utilities.py +8 -29
  240. {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/METADATA +32 -2
  241. edsl-0.1.51.dist-info/RECORD +365 -0
  242. edsl-0.1.51.dist-info/entry_points.txt +3 -0
  243. edsl/dataset/smart_objects.py +0 -96
  244. edsl/exceptions/BaseException.py +0 -21
  245. edsl/exceptions/__init__.py +0 -54
  246. edsl/exceptions/configuration.py +0 -16
  247. edsl/exceptions/general.py +0 -34
  248. edsl/questions/derived/__init__.py +0 -0
  249. edsl/study/ObjectEntry.py +0 -173
  250. edsl/study/ProofOfWork.py +0 -113
  251. edsl/study/SnapShot.py +0 -80
  252. edsl/study/Study.py +0 -520
  253. edsl/study/__init__.py +0 -6
  254. edsl/utilities/interface.py +0 -135
  255. edsl-0.1.49.dist-info/RECORD +0 -347
  256. {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/LICENSE +0 -0
  257. {edsl-0.1.49.dist-info → edsl-0.1.51.dist-info}/WHEEL +0 -0
@@ -3,6 +3,7 @@ from typing import Callable, Union, List, TYPE_CHECKING
3
3
 
4
4
  if TYPE_CHECKING:
5
5
  from edsl.questions.QuestionBase import QuestionBase
6
+ from ...surveys.survey import Survey
6
7
 
7
8
 
8
9
  class MemoryManagement:
@@ -8,6 +8,7 @@ if TYPE_CHECKING:
8
8
  from ...surveys import Survey
9
9
  from ...prompts import Prompt
10
10
  from ..dag import DAG
11
+ from ...questions.question_base import QuestionBase
11
12
 
12
13
  class MemoryPlan(UserDict):
13
14
  """A survey has a memory plan that specifies what the agent should remember when answering a question.
@@ -103,23 +104,13 @@ class MemoryPlan(UserDict):
103
104
  :param focal_question: The current question being answered.
104
105
  :param prior_question: The question that was answered before the focal question that should be remembered.
105
106
 
106
- >>> mp = MemoryPlan.example()
107
- >>> mp.add_single_memory("q0", "q1")
108
- Traceback (most recent call last):
109
- ...
110
- ValueError: q1 must come before q0.
107
+ # Prior question must come before focal question
108
+ # Example: adding "q0", "q1" would raise ValueError as q1 comes after q0
111
109
 
112
- >>> mp = MemoryPlan.example()
113
- >>> mp.add_single_memory("q0", "crap")
114
- Traceback (most recent call last):
115
- ...
116
- ValueError: crap is not in the survey. Current names are ['q0', 'q1', 'q2']
110
+ # Question names must exist in the survey
111
+ # Example: using a non-existent question name "crap" would raise ValueError
117
112
 
118
- >>> mp = MemoryPlan.example()
119
- >>> mp.add_single_memory("crap", "q0")
120
- Traceback (most recent call last):
121
- ...
122
- ValueError: crap is not in the survey. Current names are ['q0', 'q1', 'q2']
113
+ # Similarly, focal question must also exist in the survey
123
114
  """
124
115
  self._check_valid_question_name(focal_question)
125
116
  self._check_valid_question_name(prior_question)
@@ -1,3 +1,5 @@
1
- from .rule import Rule
2
- from .rule_manager import RuleManager
3
- from .rule_collection import RuleCollection
1
+ from .rule import Rule # noqa: F401
2
+ from .rule_manager import RuleManager # noqa: F401
3
+ from .rule_collection import RuleCollection # noqa: F401
4
+
5
+ __all__ = []
@@ -19,7 +19,7 @@ with a low (-1) priority.
19
19
 
20
20
  import ast
21
21
  import random
22
- from typing import Any, Union, List
22
+ from typing import Any, Union
23
23
  from collections import defaultdict
24
24
 
25
25
 
@@ -27,7 +27,6 @@ from collections import defaultdict
27
27
  from simpleeval import EvalWithCompoundTypes
28
28
 
29
29
  from ..exceptions import SurveyError
30
-
31
30
  from ..exceptions import (
32
31
  SurveyRuleCannotEvaluateError,
33
32
  SurveyRuleRefersToFutureStateError,
@@ -1,6 +1,6 @@
1
1
  """A collection of rules for a survey."""
2
2
 
3
- from typing import List, Union, Any, Optional
3
+ from typing import List, Any, Optional
4
4
  from collections import defaultdict, UserList, namedtuple
5
5
 
6
6
  from ..exceptions import (
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, TypeAlias
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
- >>> s._get_question_index("poop")
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
- >>> s = Survey().add_question(q).add_question(q)
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
- >>> s.add_stop_rule("q0", "{{ q1.answer }} <> 'yes'")
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
 
@@ -1,5 +1,5 @@
1
1
  from typing import Optional
2
- from edsl.utilities.remove_edsl_version import remove_edsl_version
2
+ from ..utilities.remove_edsl_version import remove_edsl_version
3
3
 
4
4
 
5
5
  class CSSRuleMeta(type):
@@ -73,7 +73,7 @@ class CSSRule(metaclass=CSSRuleMeta):
73
73
  d = {"selector": self.selector, "properties": self.properties}
74
74
 
75
75
  if add_esl_version:
76
- from edsl import __version__
76
+ from .. import __version__
77
77
 
78
78
  d["edsl_version"] = __version__
79
79
  d["edsl_class_name"] = self.__class__.__name__
@@ -233,7 +233,7 @@ class SurveyCSS:
233
233
  """
234
234
  d = {"rules": [rule.to_dict() for rule in self.rules.values()]}
235
235
  if add_edsl_version:
236
- from edsl import __version__
236
+ from .. import __version__
237
237
 
238
238
  d["edsl_version"] = __version__
239
239
  d["edsl_class_name"] = self.__class__.__name__
@@ -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(f"\n")
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, TYPE_CHECKING
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
 
@@ -58,7 +58,8 @@ class Simulator:
58
58
 
59
59
  if num_passes > 100:
60
60
  print("Too many passes.")
61
- raise Exception("Too many passes.")
61
+ from .exceptions import SurveyError
62
+ raise SurveyError("Too many passes.")
62
63
  return self.survey.answers
63
64
 
64
65
  def create_agent(self) -> "Agent":
edsl/tasks/__init__.py CHANGED
@@ -26,7 +26,29 @@ 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__ = [
30
+ 'TaskHistory',
31
+ 'QuestionTaskCreator',
32
+ 'TaskCreators',
33
+ 'TaskStatus',
34
+ 'TaskStatusDescriptor',
35
+ 'TaskError',
36
+ 'TaskStatusError',
37
+ 'TaskExecutionError',
38
+ 'TaskDependencyError',
39
+ 'TaskResourceError',
40
+ 'TaskHistoryError'
41
+ ]
42
+
29
43
  from .task_history import TaskHistory
30
44
  from .question_task_creator import QuestionTaskCreator
31
45
  from .task_creators import TaskCreators
32
- from .task_status_enum import TaskStatus, TaskStatusDescriptor
46
+ from .task_status_enum import TaskStatus, TaskStatusDescriptor
47
+ from .exceptions import (
48
+ TaskError,
49
+ TaskStatusError,
50
+ TaskExecutionError,
51
+ TaskDependencyError,
52
+ TaskResourceError,
53
+ TaskHistoryError
54
+ )
@@ -0,0 +1,72 @@
1
+ """
2
+ This module defines the exception hierarchy for the tasks module.
3
+
4
+ All exceptions related to task creation, execution, and management are defined here.
5
+ These exceptions provide detailed error information for debugging and error reporting.
6
+ """
7
+
8
+ from ..base import BaseException
9
+
10
+
11
+ class TaskError(BaseException):
12
+ """
13
+ Base exception for all tasks-related errors.
14
+
15
+ This is the parent class for all exceptions raised within the tasks module.
16
+ It inherits from BaseException to ensure proper error tracking and reporting.
17
+ """
18
+ pass
19
+
20
+
21
+ class TaskStatusError(TaskError):
22
+ """
23
+ Raised when a task encounters an invalid status transition.
24
+
25
+ This exception is raised when a task attempts to transition to an invalid state
26
+ based on its current state, such as trying to set a completed task to running.
27
+
28
+ Attributes:
29
+ current_status: The current status of the task
30
+ attempted_status: The status that could not be set
31
+ """
32
+ pass
33
+
34
+
35
+ class TaskExecutionError(TaskError):
36
+ """
37
+ Raised when a task encounters an error during execution.
38
+
39
+ This is a general exception for errors that occur while a task is running,
40
+ not specific to dependency resolution or resource allocation.
41
+ """
42
+ pass
43
+
44
+
45
+ class TaskDependencyError(TaskError):
46
+ """
47
+ Raised when there is an issue with task dependencies.
48
+
49
+ This exception is raised for dependency-related issues, such as circular
50
+ dependencies or errors in dependent tasks.
51
+ """
52
+ pass
53
+
54
+
55
+ class TaskResourceError(TaskError):
56
+ """
57
+ Raised when a task cannot acquire necessary resources.
58
+
59
+ This exception is used when a task cannot obtain required resources
60
+ such as tokens or request capacity, beyond normal waiting situations.
61
+ """
62
+ pass
63
+
64
+
65
+ class TaskHistoryError(TaskError):
66
+ """
67
+ Raised for errors related to task history operations.
68
+
69
+ This exception covers issues with recording, accessing, or analyzing
70
+ task execution history and logs.
71
+ """
72
+ pass
@@ -8,7 +8,7 @@ execution unit in EDSL's task system.
8
8
  """
9
9
 
10
10
  import asyncio
11
- from typing import Callable, Union, List, Dict, Any, Optional, TYPE_CHECKING
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 (estimated_wait_time := self.tokens_bucket.wait_time(requested_tokens)) > 0:
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 (estimated_wait_time := self.model_buckets.requests_bucket.wait_time(1)) > 0:
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
 
@@ -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 Callable, Union, List, Dict, TYPE_CHECKING
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
  """
@@ -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, Dict, Any, Union
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,
@@ -145,7 +146,7 @@ class TaskHistory(RepresentationMixin):
145
146
  "include_traceback": self.include_traceback,
146
147
  }
147
148
  if add_edsl_version:
148
- from edsl import __version__
149
+ from .. import __version__
149
150
 
150
151
  d["edsl_version"] = __version__
151
152
  d["edsl_class_name"] = "TaskHistory"
@@ -404,8 +405,8 @@ 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, FileSystemLoader
408
- from edsl.utilities import TemplateLoader
408
+ from jinja2 import Environment
409
+ from ..utilities import TemplateLoader
409
410
 
410
411
  env = Environment(loader=TemplateLoader("edsl", "templates/error_reporting"))
411
412
 
@@ -463,9 +464,8 @@ 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
- from edsl.utilities.utilities import is_notebook
468
+ from ..utilities.utilities import is_notebook
469
469
 
470
470
  output = self.generate_html_report(css)
471
471
 
@@ -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)
@@ -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, TaskStatusLogEntry
11
+ from .task_status_enum import TaskStatus
13
12
 
14
13
 
15
14
  class TaskStatusLog(UserList):
edsl/tokens/__init__.py CHANGED
@@ -1,2 +1,30 @@
1
+ """
2
+ The tokens module provides functionality for tracking and analyzing token usage in EDSL.
3
+
4
+ This module implements classes for tracking and reporting token usage across various
5
+ components of EDSL, particularly for language model calls. It supports aggregation,
6
+ cost calculation, and reporting of token usage metrics.
7
+
8
+ Key components:
9
+ 1. TokenUsage - Tracks prompt and completion tokens for a single operation
10
+ 2. InterviewTokenUsage - Aggregates token usage across an entire interview
11
+ 3. Exception classes for handling token-related errors
12
+
13
+ The token tracking system helps with:
14
+ - Cost estimation and billing
15
+ - Resource utilization analysis
16
+ - Cache effectiveness measurement
17
+ - API quota management
18
+ """
19
+
1
20
  from .token_usage import TokenUsage
2
- from .interview_token_usage import InterviewTokenUsage
21
+ from .interview_token_usage import InterviewTokenUsage
22
+ from .exceptions import TokenError, TokenUsageError, TokenCostError
23
+
24
+ __all__ = [
25
+ "TokenUsage",
26
+ "InterviewTokenUsage",
27
+ "TokenError",
28
+ "TokenUsageError",
29
+ "TokenCostError"
30
+ ]
@@ -0,0 +1,37 @@
1
+ """
2
+ This module defines the exception hierarchy for the tokens module.
3
+
4
+ All exceptions related to token usage tracking and cost calculations are defined here.
5
+ """
6
+
7
+ from ..base import BaseException
8
+
9
+
10
+ class TokenError(BaseException):
11
+ """
12
+ Base exception for all token-related errors.
13
+
14
+ This is the parent class for all exceptions raised within the tokens module.
15
+ It inherits from BaseException to ensure proper error tracking and reporting.
16
+ """
17
+ pass
18
+
19
+
20
+ class TokenUsageError(TokenError):
21
+ """
22
+ Raised when there is an error in token usage operations.
23
+
24
+ This exception is raised for issues related to token usage tracking,
25
+ such as invalid token counts or incompatible token usage types.
26
+ """
27
+ pass
28
+
29
+
30
+ class TokenCostError(TokenError):
31
+ """
32
+ Raised when there is an error in token cost calculations.
33
+
34
+ This exception is used for issues with cost calculations, such as
35
+ missing or invalid pricing information.
36
+ """
37
+ pass
@@ -1,7 +1,8 @@
1
1
  from typing import Optional
2
2
 
3
3
  from .token_usage import TokenUsage
4
- from edsl.enums import TokenPricing
4
+ from ..enums import TokenPricing
5
+ from .exceptions import TokenUsageError
5
6
 
6
7
  class InterviewTokenUsage:
7
8
  """A class to represent the token usage of an interview."""
@@ -24,7 +25,7 @@ class InterviewTokenUsage:
24
25
  >>> usage3 = usage1 + usage2
25
26
  """
26
27
  if not isinstance(other, InterviewTokenUsage):
27
- raise ValueError(f"Can't add {type(other)} to InterviewTokenSummary")
28
+ raise TokenUsageError(f"Can't add {type(other)} to InterviewTokenSummary")
28
29
  return InterviewTokenUsage(
29
30
  new_token_usage=self.new_token_usage + other.new_token_usage,
30
31
  cached_token_usage=self.cached_token_usage + other.cached_token_usage,
@@ -1,4 +1,5 @@
1
- from edsl.enums import TokenPricing
1
+ from ..enums import TokenPricing
2
+ from .exceptions import TokenUsageError, TokenCostError
2
3
 
3
4
 
4
5
  class TokenUsage:
@@ -15,9 +16,9 @@ class TokenUsage:
15
16
 
16
17
  def __add__(self, other):
17
18
  if not isinstance(other, TokenUsage):
18
- raise ValueError(f"Can't add {type(other)} to InterviewTokenUsage")
19
+ raise TokenUsageError(f"Can't add {type(other)} to InterviewTokenUsage")
19
20
  if self.from_cache != other.from_cache:
20
- raise ValueError(f"Can't add token usages from different sources")
21
+ raise TokenUsageError("Can't add token usages from different sources")
21
22
  return TokenUsage(
22
23
  from_cache=self.from_cache,
23
24
  prompt_tokens=self.prompt_tokens + other.prompt_tokens,
@@ -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
- from .interface import print_results_long
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
 
@@ -1,11 +1,10 @@
1
1
  import functools
2
2
  import asyncio
3
3
  import nest_asyncio
4
+ from edsl import __version__ as edsl_version
4
5
 
5
6
  nest_asyncio.apply()
6
7
 
7
- from edsl import __version__ as edsl_version
8
-
9
8
 
10
9
  def add_edsl_version(func):
11
10
  """
@@ -69,7 +69,7 @@ class MarkdownToDocx:
69
69
 
70
70
  try:
71
71
  # Run pandoc command
72
- result = subprocess.run(
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
- result = subprocess.run(cmd, stdout=f, check=True)
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}")
@@ -86,7 +86,7 @@ class MarkdownToPDF:
86
86
 
87
87
  try:
88
88
  # Run pandoc command
89
- result = subprocess.run(
89
+ subprocess.run(
90
90
  cmd,
91
91
  input=self.markdown_content,
92
92
  text=True,
@@ -1,5 +1,4 @@
1
1
  import json
2
- from .utilities import valid_json
3
2
 
4
3
 
5
4
  def extract_json_from_string(s):