edsl 0.1.48__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.
Files changed (239) 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 +75 -0
  14. edsl/buckets/model_buckets.py +1 -2
  15. edsl/buckets/token_bucket.py +11 -6
  16. edsl/buckets/token_bucket_api.py +1 -2
  17. edsl/buckets/token_bucket_client.py +9 -7
  18. edsl/caching/cache.py +7 -2
  19. edsl/caching/cache_entry.py +10 -9
  20. edsl/caching/exceptions.py +113 -7
  21. edsl/caching/remote_cache_sync.py +1 -2
  22. edsl/caching/sql_dict.py +17 -12
  23. edsl/cli.py +43 -0
  24. edsl/config/config_class.py +30 -6
  25. edsl/conversation/Conversation.py +3 -2
  26. edsl/conversation/exceptions.py +58 -0
  27. edsl/conversation/mug_negotiation.py +0 -2
  28. edsl/coop/__init__.py +20 -1
  29. edsl/coop/coop.py +129 -38
  30. edsl/coop/exceptions.py +188 -9
  31. edsl/coop/price_fetcher.py +3 -6
  32. edsl/coop/utils.py +4 -6
  33. edsl/dataset/__init__.py +5 -4
  34. edsl/dataset/dataset.py +53 -43
  35. edsl/dataset/dataset_operations_mixin.py +86 -72
  36. edsl/dataset/dataset_tree.py +9 -5
  37. edsl/dataset/display/table_display.py +0 -2
  38. edsl/dataset/display/table_renderers.py +0 -1
  39. edsl/dataset/exceptions.py +125 -0
  40. edsl/dataset/file_exports.py +18 -11
  41. edsl/dataset/r/ggplot.py +13 -6
  42. edsl/display/__init__.py +27 -0
  43. edsl/display/core.py +147 -0
  44. edsl/display/plugin.py +189 -0
  45. edsl/display/utils.py +52 -0
  46. edsl/inference_services/__init__.py +9 -1
  47. edsl/inference_services/available_model_cache_handler.py +1 -1
  48. edsl/inference_services/available_model_fetcher.py +4 -5
  49. edsl/inference_services/data_structures.py +9 -6
  50. edsl/inference_services/exceptions.py +132 -1
  51. edsl/inference_services/inference_service_abc.py +2 -2
  52. edsl/inference_services/inference_services_collection.py +2 -6
  53. edsl/inference_services/registry.py +4 -3
  54. edsl/inference_services/service_availability.py +2 -1
  55. edsl/inference_services/services/anthropic_service.py +4 -1
  56. edsl/inference_services/services/aws_bedrock.py +13 -12
  57. edsl/inference_services/services/azure_ai.py +12 -10
  58. edsl/inference_services/services/deep_infra_service.py +1 -4
  59. edsl/inference_services/services/deep_seek_service.py +1 -5
  60. edsl/inference_services/services/google_service.py +6 -2
  61. edsl/inference_services/services/groq_service.py +1 -1
  62. edsl/inference_services/services/mistral_ai_service.py +4 -2
  63. edsl/inference_services/services/ollama_service.py +1 -1
  64. edsl/inference_services/services/open_ai_service.py +7 -5
  65. edsl/inference_services/services/perplexity_service.py +6 -2
  66. edsl/inference_services/services/test_service.py +8 -7
  67. edsl/inference_services/services/together_ai_service.py +2 -3
  68. edsl/inference_services/services/xai_service.py +1 -1
  69. edsl/instructions/__init__.py +1 -1
  70. edsl/instructions/change_instruction.py +3 -2
  71. edsl/instructions/exceptions.py +61 -0
  72. edsl/instructions/instruction.py +5 -2
  73. edsl/instructions/instruction_collection.py +2 -1
  74. edsl/instructions/instruction_handler.py +4 -9
  75. edsl/interviews/ReportErrors.py +0 -3
  76. edsl/interviews/__init__.py +9 -2
  77. edsl/interviews/answering_function.py +11 -13
  78. edsl/interviews/exception_tracking.py +14 -7
  79. edsl/interviews/exceptions.py +79 -0
  80. edsl/interviews/interview.py +32 -29
  81. edsl/interviews/interview_status_dictionary.py +4 -2
  82. edsl/interviews/interview_status_log.py +2 -1
  83. edsl/interviews/interview_task_manager.py +3 -3
  84. edsl/interviews/request_token_estimator.py +3 -1
  85. edsl/interviews/statistics.py +2 -3
  86. edsl/invigilators/__init__.py +7 -1
  87. edsl/invigilators/exceptions.py +79 -0
  88. edsl/invigilators/invigilator_base.py +0 -1
  89. edsl/invigilators/invigilators.py +8 -12
  90. edsl/invigilators/prompt_constructor.py +1 -5
  91. edsl/invigilators/prompt_helpers.py +8 -4
  92. edsl/invigilators/question_instructions_prompt_builder.py +1 -1
  93. edsl/invigilators/question_option_processor.py +9 -5
  94. edsl/invigilators/question_template_replacements_builder.py +3 -2
  95. edsl/jobs/__init__.py +3 -3
  96. edsl/jobs/async_interview_runner.py +24 -22
  97. edsl/jobs/check_survey_scenario_compatibility.py +7 -6
  98. edsl/jobs/data_structures.py +7 -4
  99. edsl/jobs/exceptions.py +177 -8
  100. edsl/jobs/fetch_invigilator.py +1 -1
  101. edsl/jobs/jobs.py +72 -67
  102. edsl/jobs/jobs_checks.py +2 -3
  103. edsl/jobs/jobs_component_constructor.py +2 -2
  104. edsl/jobs/jobs_pricing_estimation.py +3 -2
  105. edsl/jobs/jobs_remote_inference_logger.py +5 -4
  106. edsl/jobs/jobs_runner_asyncio.py +1 -2
  107. edsl/jobs/jobs_runner_status.py +8 -9
  108. edsl/jobs/remote_inference.py +26 -23
  109. edsl/jobs/results_exceptions_handler.py +8 -5
  110. edsl/key_management/__init__.py +3 -1
  111. edsl/key_management/exceptions.py +62 -0
  112. edsl/key_management/key_lookup.py +1 -1
  113. edsl/key_management/key_lookup_builder.py +37 -14
  114. edsl/key_management/key_lookup_collection.py +2 -0
  115. edsl/language_models/__init__.py +1 -1
  116. edsl/language_models/exceptions.py +302 -14
  117. edsl/language_models/language_model.py +4 -7
  118. edsl/language_models/model.py +4 -4
  119. edsl/language_models/model_list.py +1 -1
  120. edsl/language_models/price_manager.py +1 -1
  121. edsl/language_models/raw_response_handler.py +14 -9
  122. edsl/language_models/registry.py +17 -21
  123. edsl/language_models/repair.py +0 -6
  124. edsl/language_models/unused/fake_openai_service.py +0 -1
  125. edsl/load_plugins.py +69 -0
  126. edsl/logger.py +146 -0
  127. edsl/notebooks/notebook.py +1 -1
  128. edsl/notebooks/notebook_to_latex.py +0 -1
  129. edsl/plugins/__init__.py +63 -0
  130. edsl/plugins/built_in/export_example.py +50 -0
  131. edsl/plugins/built_in/pig_latin.py +67 -0
  132. edsl/plugins/cli.py +372 -0
  133. edsl/plugins/cli_typer.py +283 -0
  134. edsl/plugins/exceptions.py +31 -0
  135. edsl/plugins/hookspec.py +51 -0
  136. edsl/plugins/plugin_host.py +128 -0
  137. edsl/plugins/plugin_manager.py +633 -0
  138. edsl/plugins/plugins_registry.py +168 -0
  139. edsl/prompts/__init__.py +2 -0
  140. edsl/prompts/exceptions.py +107 -5
  141. edsl/prompts/prompt.py +14 -6
  142. edsl/questions/HTMLQuestion.py +5 -11
  143. edsl/questions/Quick.py +0 -1
  144. edsl/questions/__init__.py +2 -0
  145. edsl/questions/answer_validator_mixin.py +318 -318
  146. edsl/questions/compose_questions.py +2 -2
  147. edsl/questions/descriptors.py +10 -49
  148. edsl/questions/exceptions.py +278 -22
  149. edsl/questions/loop_processor.py +7 -5
  150. edsl/questions/prompt_templates/question_list.jinja +3 -0
  151. edsl/questions/question_base.py +14 -16
  152. edsl/questions/question_base_gen_mixin.py +2 -2
  153. edsl/questions/question_base_prompts_mixin.py +9 -3
  154. edsl/questions/question_budget.py +9 -5
  155. edsl/questions/question_check_box.py +3 -5
  156. edsl/questions/question_dict.py +171 -194
  157. edsl/questions/question_extract.py +1 -1
  158. edsl/questions/question_free_text.py +4 -6
  159. edsl/questions/question_functional.py +4 -3
  160. edsl/questions/question_list.py +36 -9
  161. edsl/questions/question_matrix.py +95 -61
  162. edsl/questions/question_multiple_choice.py +6 -4
  163. edsl/questions/question_numerical.py +2 -4
  164. edsl/questions/question_registry.py +4 -2
  165. edsl/questions/register_questions_meta.py +0 -1
  166. edsl/questions/response_validator_abc.py +7 -13
  167. edsl/questions/templates/dict/answering_instructions.jinja +1 -0
  168. edsl/questions/templates/rank/question_presentation.jinja +1 -1
  169. edsl/results/__init__.py +1 -1
  170. edsl/results/exceptions.py +141 -7
  171. edsl/results/report.py +0 -1
  172. edsl/results/result.py +4 -5
  173. edsl/results/results.py +10 -51
  174. edsl/results/results_selector.py +8 -4
  175. edsl/scenarios/PdfExtractor.py +2 -2
  176. edsl/scenarios/construct_download_link.py +69 -35
  177. edsl/scenarios/directory_scanner.py +33 -14
  178. edsl/scenarios/document_chunker.py +1 -1
  179. edsl/scenarios/exceptions.py +238 -14
  180. edsl/scenarios/file_methods.py +1 -1
  181. edsl/scenarios/file_store.py +7 -3
  182. edsl/scenarios/handlers/__init__.py +17 -0
  183. edsl/scenarios/handlers/docx_file_store.py +0 -5
  184. edsl/scenarios/handlers/pdf_file_store.py +0 -1
  185. edsl/scenarios/handlers/pptx_file_store.py +0 -5
  186. edsl/scenarios/handlers/py_file_store.py +0 -1
  187. edsl/scenarios/handlers/sql_file_store.py +1 -4
  188. edsl/scenarios/handlers/sqlite_file_store.py +0 -1
  189. edsl/scenarios/handlers/txt_file_store.py +1 -1
  190. edsl/scenarios/scenario.py +0 -1
  191. edsl/scenarios/scenario_list.py +152 -18
  192. edsl/scenarios/scenario_list_pdf_tools.py +1 -0
  193. edsl/scenarios/scenario_selector.py +0 -1
  194. edsl/surveys/__init__.py +3 -4
  195. edsl/surveys/dag/__init__.py +4 -2
  196. edsl/surveys/descriptors.py +1 -1
  197. edsl/surveys/edit_survey.py +1 -0
  198. edsl/surveys/exceptions.py +165 -9
  199. edsl/surveys/memory/__init__.py +5 -3
  200. edsl/surveys/memory/memory_management.py +1 -0
  201. edsl/surveys/memory/memory_plan.py +6 -15
  202. edsl/surveys/rules/__init__.py +5 -3
  203. edsl/surveys/rules/rule.py +1 -2
  204. edsl/surveys/rules/rule_collection.py +1 -1
  205. edsl/surveys/survey.py +12 -24
  206. edsl/surveys/survey_export.py +6 -3
  207. edsl/surveys/survey_flow_visualization.py +10 -1
  208. edsl/tasks/__init__.py +2 -0
  209. edsl/tasks/question_task_creator.py +3 -3
  210. edsl/tasks/task_creators.py +1 -3
  211. edsl/tasks/task_history.py +5 -7
  212. edsl/tasks/task_status_log.py +1 -2
  213. edsl/tokens/__init__.py +3 -1
  214. edsl/tokens/token_usage.py +1 -1
  215. edsl/utilities/__init__.py +21 -1
  216. edsl/utilities/decorators.py +1 -2
  217. edsl/utilities/markdown_to_docx.py +2 -2
  218. edsl/utilities/markdown_to_pdf.py +1 -1
  219. edsl/utilities/repair_functions.py +0 -1
  220. edsl/utilities/restricted_python.py +0 -1
  221. edsl/utilities/template_loader.py +2 -3
  222. edsl/utilities/utilities.py +8 -29
  223. {edsl-0.1.48.dist-info → edsl-0.1.50.dist-info}/METADATA +32 -2
  224. edsl-0.1.50.dist-info/RECORD +363 -0
  225. edsl-0.1.50.dist-info/entry_points.txt +3 -0
  226. edsl/dataset/smart_objects.py +0 -96
  227. edsl/exceptions/BaseException.py +0 -21
  228. edsl/exceptions/__init__.py +0 -54
  229. edsl/exceptions/configuration.py +0 -16
  230. edsl/exceptions/general.py +0 -34
  231. edsl/study/ObjectEntry.py +0 -173
  232. edsl/study/ProofOfWork.py +0 -113
  233. edsl/study/SnapShot.py +0 -80
  234. edsl/study/Study.py +0 -520
  235. edsl/study/__init__.py +0 -6
  236. edsl/utilities/interface.py +0 -135
  237. edsl-0.1.48.dist-info/RECORD +0 -347
  238. {edsl-0.1.48.dist-info → edsl-0.1.50.dist-info}/LICENSE +0 -0
  239. {edsl-0.1.48.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, 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,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
 
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, 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,
@@ -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, FileSystemLoader
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)
@@ -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,4 @@
1
1
  from .token_usage import TokenUsage
2
- from .interview_token_usage import InterviewTokenUsage
2
+ from .interview_token_usage import InterviewTokenUsage
3
+
4
+ __all__ = ["TokenUsage", "InterviewTokenUsage"]
@@ -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(f"Can't add token usages from different sources")
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,
@@ -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):
@@ -1,7 +1,6 @@
1
1
  from RestrictedPython import compile_restricted, safe_globals
2
2
  from RestrictedPython.Guards import (
3
3
  safe_builtins,
4
- full_write_guard,
5
4
  guarded_iter_unpack_sequence,
6
5
  )
7
6
 
@@ -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
- parts = [self.templates_dir] + template.split("/")
14
- template_path = os.path.join(*parts)
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)
@@ -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
- # Parse the JSON object to validate it
92
+ # Validate the JSON
94
93
  try:
95
- parsed_json = json.loads(json_object)
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
- if is_notebook():
219
- from IPython.display import HTML, display
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
- transform_func = lambda x: x
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.48
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