edsl 0.1.50__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 (109) hide show
  1. edsl/__version__.py +1 -1
  2. edsl/base/base_exception.py +2 -2
  3. edsl/buckets/bucket_collection.py +1 -1
  4. edsl/buckets/exceptions.py +32 -0
  5. edsl/buckets/token_bucket_api.py +26 -10
  6. edsl/caching/cache.py +5 -2
  7. edsl/caching/remote_cache_sync.py +5 -5
  8. edsl/caching/sql_dict.py +12 -11
  9. edsl/config/__init__.py +1 -1
  10. edsl/config/config_class.py +4 -2
  11. edsl/conversation/Conversation.py +7 -4
  12. edsl/conversation/car_buying.py +1 -3
  13. edsl/conversation/mug_negotiation.py +2 -6
  14. edsl/coop/__init__.py +11 -8
  15. edsl/coop/coop.py +13 -13
  16. edsl/coop/coop_functions.py +1 -1
  17. edsl/coop/ep_key_handling.py +1 -1
  18. edsl/coop/price_fetcher.py +2 -2
  19. edsl/coop/utils.py +2 -2
  20. edsl/dataset/dataset.py +144 -63
  21. edsl/dataset/dataset_operations_mixin.py +14 -6
  22. edsl/dataset/dataset_tree.py +3 -3
  23. edsl/dataset/display/table_renderers.py +6 -3
  24. edsl/dataset/file_exports.py +4 -4
  25. edsl/dataset/r/ggplot.py +3 -3
  26. edsl/inference_services/available_model_fetcher.py +2 -2
  27. edsl/inference_services/data_structures.py +5 -5
  28. edsl/inference_services/inference_service_abc.py +1 -1
  29. edsl/inference_services/inference_services_collection.py +1 -1
  30. edsl/inference_services/service_availability.py +3 -3
  31. edsl/inference_services/services/azure_ai.py +3 -3
  32. edsl/inference_services/services/google_service.py +1 -1
  33. edsl/inference_services/services/test_service.py +1 -1
  34. edsl/instructions/change_instruction.py +5 -4
  35. edsl/instructions/instruction.py +1 -0
  36. edsl/instructions/instruction_collection.py +5 -4
  37. edsl/instructions/instruction_handler.py +10 -8
  38. edsl/interviews/exception_tracking.py +1 -1
  39. edsl/interviews/interview.py +1 -1
  40. edsl/interviews/interview_status_dictionary.py +1 -1
  41. edsl/interviews/interview_task_manager.py +2 -2
  42. edsl/interviews/request_token_estimator.py +3 -2
  43. edsl/interviews/statistics.py +2 -2
  44. edsl/invigilators/invigilators.py +2 -2
  45. edsl/jobs/__init__.py +39 -2
  46. edsl/jobs/async_interview_runner.py +1 -1
  47. edsl/jobs/check_survey_scenario_compatibility.py +5 -5
  48. edsl/jobs/data_structures.py +2 -2
  49. edsl/jobs/jobs.py +2 -2
  50. edsl/jobs/jobs_checks.py +5 -5
  51. edsl/jobs/jobs_component_constructor.py +2 -2
  52. edsl/jobs/jobs_pricing_estimation.py +1 -1
  53. edsl/jobs/jobs_runner_asyncio.py +2 -2
  54. edsl/jobs/remote_inference.py +1 -1
  55. edsl/jobs/results_exceptions_handler.py +2 -2
  56. edsl/language_models/language_model.py +5 -1
  57. edsl/notebooks/__init__.py +24 -1
  58. edsl/notebooks/exceptions.py +82 -0
  59. edsl/notebooks/notebook.py +7 -3
  60. edsl/notebooks/notebook_to_latex.py +1 -1
  61. edsl/prompts/__init__.py +23 -2
  62. edsl/prompts/prompt.py +1 -1
  63. edsl/questions/__init__.py +4 -4
  64. edsl/questions/answer_validator_mixin.py +0 -5
  65. edsl/questions/compose_questions.py +2 -2
  66. edsl/questions/descriptors.py +1 -1
  67. edsl/questions/question_base.py +32 -3
  68. edsl/questions/question_base_prompts_mixin.py +4 -4
  69. edsl/questions/question_budget.py +503 -102
  70. edsl/questions/question_check_box.py +658 -156
  71. edsl/questions/question_dict.py +176 -2
  72. edsl/questions/question_extract.py +401 -61
  73. edsl/questions/question_free_text.py +77 -9
  74. edsl/questions/question_functional.py +118 -9
  75. edsl/questions/{derived/question_likert_five.py → question_likert_five.py} +2 -2
  76. edsl/questions/{derived/question_linear_scale.py → question_linear_scale.py} +3 -4
  77. edsl/questions/question_list.py +246 -26
  78. edsl/questions/question_matrix.py +586 -73
  79. edsl/questions/question_multiple_choice.py +213 -47
  80. edsl/questions/question_numerical.py +360 -29
  81. edsl/questions/question_rank.py +401 -124
  82. edsl/questions/question_registry.py +3 -3
  83. edsl/questions/{derived/question_top_k.py → question_top_k.py} +3 -3
  84. edsl/questions/{derived/question_yes_no.py → question_yes_no.py} +3 -4
  85. edsl/questions/register_questions_meta.py +2 -1
  86. edsl/questions/response_validator_abc.py +6 -2
  87. edsl/questions/response_validator_factory.py +10 -12
  88. edsl/results/report.py +1 -1
  89. edsl/results/result.py +7 -4
  90. edsl/results/results.py +471 -271
  91. edsl/results/results_selector.py +2 -2
  92. edsl/scenarios/construct_download_link.py +3 -3
  93. edsl/scenarios/scenario.py +1 -2
  94. edsl/scenarios/scenario_list.py +41 -23
  95. edsl/surveys/survey_css.py +3 -3
  96. edsl/surveys/survey_simulator.py +2 -1
  97. edsl/tasks/__init__.py +22 -2
  98. edsl/tasks/exceptions.py +72 -0
  99. edsl/tasks/task_history.py +3 -3
  100. edsl/tokens/__init__.py +27 -1
  101. edsl/tokens/exceptions.py +37 -0
  102. edsl/tokens/interview_token_usage.py +3 -2
  103. edsl/tokens/token_usage.py +4 -3
  104. {edsl-0.1.50.dist-info → edsl-0.1.51.dist-info}/METADATA +1 -1
  105. {edsl-0.1.50.dist-info → edsl-0.1.51.dist-info}/RECORD +108 -106
  106. edsl/questions/derived/__init__.py +0 -0
  107. {edsl-0.1.50.dist-info → edsl-0.1.51.dist-info}/LICENSE +0 -0
  108. {edsl-0.1.50.dist-info → edsl-0.1.51.dist-info}/WHEEL +0 -0
  109. {edsl-0.1.50.dist-info → edsl-0.1.51.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  from typing import List, 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 ChangeInstruction:
@@ -9,11 +9,12 @@ class ChangeInstruction:
9
9
  drop: Optional[List[str]] = None,
10
10
  ):
11
11
  if keep is None and drop is None:
12
- from edsl.instructions.exceptions import InstructionValueError
12
+ from .exceptions import InstructionValueError
13
13
  raise InstructionValueError("Keep and drop cannot both be None")
14
14
 
15
15
  self.keep = keep or []
16
16
  self.drop = drop or []
17
+ self.pseudo_index = 0.0
17
18
 
18
19
  def include_instruction(self, instruction_name) -> bool:
19
20
  return (instruction_name in self.keep) or (instruction_name not in self.drop)
@@ -30,7 +31,7 @@ class ChangeInstruction:
30
31
  "drop": self.drop,
31
32
  }
32
33
  if add_edsl_version:
33
- from edsl import __version__
34
+ from .. import __version__
34
35
 
35
36
  d["edsl_version"] = __version__
36
37
  d["edsl_class_name"] = "ChangeInstruction"
@@ -39,7 +40,7 @@ class ChangeInstruction:
39
40
 
40
41
  def __hash__(self) -> int:
41
42
  """Return a hash of the question."""
42
- from edsl.utilities.utilities import dict_hash
43
+ from ..utilities.utilities import dict_hash
43
44
 
44
45
  return dict_hash(self.to_dict(add_edsl_version=False))
45
46
 
@@ -14,6 +14,7 @@ class Instruction(RepresentationMixin):
14
14
  self.name = name
15
15
  self.text = text
16
16
  self.preamble = preamble
17
+ self.pseudo_index = 0.0
17
18
 
18
19
  def __str__(self):
19
20
  return self.text
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Dict, List, Generator, Union
1
+ from typing import TYPE_CHECKING, Dict, List, Generator, Union, Tuple
2
2
  from collections import UserDict
3
3
 
4
4
  from .instruction import Instruction
@@ -40,13 +40,14 @@ class InstructionCollection(UserDict):
40
40
 
41
41
  def _entries_before(
42
42
  self, question_name
43
- ) -> tuple[List[Instruction], List[ChangeInstruction]]:
43
+ ) -> Tuple[List[Instruction], List[ChangeInstruction]]:
44
44
  if question_name not in self.question_names:
45
- from edsl.instructions.exceptions import InstructionCollectionError
45
+ from .exceptions import InstructionCollectionError
46
46
  raise InstructionCollectionError(
47
47
  f"Question name not found in the list of questions: got '{question_name}'; list is {self.question_names}"
48
48
  )
49
- instructions, changes = [], []
49
+ instructions: List[Instruction] = []
50
+ changes: List[ChangeInstruction] = []
50
51
 
51
52
  index = self.question_index(question_name)
52
53
  for instruction in self.instruction_names_to_instruction.values():
@@ -1,11 +1,13 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
 
4
+ from typing import Dict, List, Any
5
+
4
6
  @dataclass
5
7
  class SeparatedComponents:
6
- true_questions: list
7
- instruction_names_to_instructions: dict
8
- pseudo_indices: dict
8
+ true_questions: List[Any]
9
+ instruction_names_to_instructions: Dict[str, Any]
10
+ pseudo_indices: Dict[str, float]
9
11
 
10
12
 
11
13
  class InstructionHandler:
@@ -13,7 +15,7 @@ class InstructionHandler:
13
15
  self.survey = survey
14
16
 
15
17
  @staticmethod
16
- def separate_questions_and_instructions(questions_and_instructions: list) -> tuple:
18
+ def separate_questions_and_instructions(questions_and_instructions: list) -> SeparatedComponents:
17
19
  """
18
20
  The 'pseudo_indices' attribute is a dictionary that maps question names to pseudo-indices
19
21
  that are used to order questions and instructions in the survey.
@@ -48,9 +50,9 @@ class InstructionHandler:
48
50
  """
49
51
  from .instruction import Instruction
50
52
  from .change_instruction import ChangeInstruction
51
- from edsl.questions import QuestionBase
53
+ from ..questions import QuestionBase
52
54
 
53
- true_questions = []
55
+ true_questions: List[QuestionBase] = []
54
56
  instruction_names_to_instructions = {}
55
57
 
56
58
  num_change_instructions = 0
@@ -63,7 +65,7 @@ class InstructionHandler:
63
65
  num_change_instructions += 1
64
66
  for prior_instruction in entry.keep + entry.drop:
65
67
  if prior_instruction not in instruction_names_to_instructions:
66
- from edsl.instructions.exceptions import InstructionValueError
68
+ from .exceptions import InstructionValueError
67
69
  raise InstructionValueError(
68
70
  f"ChangeInstruction {entry.name} references instruction {prior_instruction} which does not exist."
69
71
  )
@@ -77,7 +79,7 @@ class InstructionHandler:
77
79
  instructions_run_length = 0
78
80
  true_questions.append(entry)
79
81
  else:
80
- from edsl.instructions.exceptions import InstructionValueError
82
+ from .exceptions import InstructionValueError
81
83
  raise InstructionValueError(
82
84
  f"Entry {repr(entry)} is not a QuestionBase or an Instruction."
83
85
  )
@@ -92,7 +92,7 @@ class InterviewExceptionEntry:
92
92
  def code(self, run=True):
93
93
  """Return the code to reproduce the exception."""
94
94
  lines = []
95
- lines.append("from edsl import Question, Model, Scenario, Agent")
95
+ lines.append("from .. import Question, Model, Scenario, Agent")
96
96
 
97
97
  lines.append(f"q = {repr(self.invigilator.question)}")
98
98
  lines.append(f"scenario = {repr(self.invigilator.scenario)}")
@@ -365,7 +365,7 @@ class Interview:
365
365
  bool: True if the interviews are equivalent, False otherwise
366
366
 
367
367
  Examples:
368
- >>> from edsl.interviews import Interview
368
+ >>> from . import Interview
369
369
  >>> i = Interview.example()
370
370
  >>> d = i.to_dict()
371
371
  >>> i2 = Interview.from_dict(d)
@@ -27,7 +27,7 @@ class InterviewStatusDictionary(UserDict):
27
27
  ) -> "InterviewStatusDictionary":
28
28
  """Adds two InterviewStatusDictionaries together."""
29
29
  if not isinstance(other, InterviewStatusDictionary):
30
- from edsl.interviews.exceptions import InterviewStatusError
30
+ from .exceptions import InterviewStatusError
31
31
  raise InterviewStatusError(f"Can't add {type(other)} to InterviewStatusDictionary")
32
32
  new_dict = {}
33
33
  for key in self.keys():
@@ -29,7 +29,7 @@ class InterviewTaskManager:
29
29
  self, answer_func, token_estimator, model_buckets
30
30
  ) -> list[asyncio.Task]:
31
31
  """Create tasks for all questions with proper dependencies."""
32
- tasks = []
32
+ tasks: list[asyncio.Task] = []
33
33
  for question in self.survey.questions:
34
34
  dependencies = self._get_task_dependencies(tasks, question)
35
35
  task = self._create_single_task(
@@ -40,7 +40,7 @@ class InterviewTaskManager:
40
40
  model_buckets=model_buckets,
41
41
  )
42
42
  tasks.append(task)
43
- return tuple(tasks)
43
+ return tasks
44
44
 
45
45
  def _get_task_dependencies(
46
46
  self, existing_tasks: list[asyncio.Task], question: "QuestionBase"
@@ -26,9 +26,10 @@ class RequestTokenEstimator:
26
26
  if isinstance(file, FileStore):
27
27
  file_tokens += file.size * 0.25
28
28
  else:
29
- from edsl.interviews.exceptions import InterviewTokenError
29
+ from .exceptions import InterviewTokenError
30
30
  raise InterviewTokenError(f"Prompt is of type {type(prompt)}")
31
- return len(combined_text) / 4.0 + file_tokens
31
+ result: float = len(combined_text) / 4.0 + file_tokens
32
+ return result
32
33
 
33
34
 
34
35
 
@@ -1,5 +1,5 @@
1
1
  from collections import UserDict
2
- from typing import DefaultDict
2
+ from typing import DefaultDict, Union, Optional
3
3
 
4
4
  from ..tokens import InterviewTokenUsage
5
5
 
@@ -43,7 +43,7 @@ class InterviewStatistic(UserDict):
43
43
  value: float,
44
44
  digits: int = 0,
45
45
  units: str = "",
46
- pretty_name: str = None,
46
+ pretty_name: Optional[str] = None,
47
47
  ):
48
48
  """Create a new InterviewStatistic object."""
49
49
  self.name = name
@@ -6,7 +6,7 @@ from typing import Literal
6
6
 
7
7
  from ..utilities.decorators import sync_wrapper
8
8
  from ..questions.exceptions import QuestionAnswerValidationError
9
- from ..data_transfer_models import AgentResponseDict, EDSLResultObjectInput
9
+ from ..base.data_transfer_models import AgentResponseDict, EDSLResultObjectInput
10
10
  from ..utilities.decorators import jupyter_nb_handler
11
11
 
12
12
  from .prompt_constructor import PromptConstructor
@@ -280,7 +280,7 @@ class InvigilatorAI(InvigilatorBase):
280
280
  }
281
281
  if "encoded_image" in prompts:
282
282
  params["encoded_image"] = prompts["encoded_image"]
283
- from edsl.invigilators.exceptions import InvigilatorNotImplementedError
283
+ from .exceptions import InvigilatorNotImplementedError
284
284
  raise InvigilatorNotImplementedError("encoded_image not implemented")
285
285
 
286
286
  if "files_list" in prompts:
edsl/jobs/__init__.py CHANGED
@@ -1,7 +1,44 @@
1
+ """
2
+ The jobs module provides tools for running and managing EDSL jobs.
3
+
4
+ It includes classes for job configuration, execution, pricing estimation,
5
+ and management of concurrent language model API calls.
6
+ """
7
+
1
8
  from .jobs import Jobs
2
9
  from .jobs import RunConfig, RunParameters, RunEnvironment # noqa: F401
3
10
  from .remote_inference import JobsRemoteInferenceHandler # noqa: F401
4
11
  from .jobs_runner_status import JobsRunnerStatusBase # noqa: F401
12
+ from .exceptions import (
13
+ JobsErrors,
14
+ JobsRunError,
15
+ MissingRemoteInferenceError,
16
+ InterviewError,
17
+ InterviewErrorPriorTaskCanceled,
18
+ InterviewTimeoutError,
19
+ JobsValueError,
20
+ JobsCompatibilityError,
21
+ JobsImplementationError,
22
+ RemoteInferenceError,
23
+ JobsTypeError
24
+ )
5
25
 
6
-
7
- __all__ = ["Jobs"]
26
+ __all__ = [
27
+ "Jobs",
28
+ "JobsErrors",
29
+ "JobsRunError",
30
+ "MissingRemoteInferenceError",
31
+ "InterviewError",
32
+ "InterviewErrorPriorTaskCanceled",
33
+ "InterviewTimeoutError",
34
+ "JobsValueError",
35
+ "JobsCompatibilityError",
36
+ "JobsImplementationError",
37
+ "RemoteInferenceError",
38
+ "JobsTypeError",
39
+ "JobsRemoteInferenceHandler",
40
+ "JobsRunnerStatusBase",
41
+ "RunConfig",
42
+ "RunParameters",
43
+ "RunEnvironment"
44
+ ]
@@ -9,7 +9,7 @@ from collections.abc import AsyncGenerator
9
9
  from typing import List, Generator, Tuple, TYPE_CHECKING
10
10
  from dataclasses import dataclass
11
11
  import asyncio
12
- from edsl.data_transfer_models import EDSLResultObjectInput
12
+ from ..data_transfer_models import EDSLResultObjectInput
13
13
 
14
14
  from ..results import Result
15
15
  from ..interviews import Interview
@@ -1,12 +1,12 @@
1
1
  import warnings
2
2
  from typing import TYPE_CHECKING
3
- from edsl.scenarios import ScenarioList
4
- from edsl.surveys import Survey
5
- from edsl.jobs.exceptions import JobsCompatibilityError
3
+ from ..scenarios import ScenarioList
4
+ from ..surveys import Survey
5
+ from .exceptions import JobsCompatibilityError
6
6
 
7
7
  if TYPE_CHECKING:
8
- from edsl.surveys.Survey import Survey
9
- from edsl.scenarios.ScenarioList import ScenarioList
8
+ from ..surveys.survey import Survey
9
+ from ..scenarios.scenario_list import ScenarioList
10
10
 
11
11
 
12
12
  class CheckSurveyScenarioCompatibility:
@@ -1,7 +1,7 @@
1
1
  from typing import Optional, Literal, TYPE_CHECKING
2
2
  from dataclasses import dataclass, asdict
3
3
  from collections import UserDict
4
- from edsl.data_transfer_models import EDSLResultObjectInput
4
+ from ..data_transfer_models import EDSLResultObjectInput
5
5
 
6
6
  # from edsl.data_transfer_models import VisibilityType
7
7
  from ..caching import Cache
@@ -86,7 +86,7 @@ class RunParameters(Base):
86
86
  def to_dict(self, add_edsl_version=False) -> dict:
87
87
  d = asdict(self)
88
88
  if add_edsl_version:
89
- from edsl import __version__
89
+ from .. import __version__
90
90
 
91
91
  d["edsl_version"] = __version__
92
92
  d["edsl_class_name"] = "RunConfig"
edsl/jobs/jobs.py CHANGED
@@ -620,7 +620,7 @@ class Jobs(Base):
620
620
  if jh.use_remote_inference(self.run_config.parameters.disable_remote_inference):
621
621
  job_info: RemoteJobInfo = self._start_remote_inference_job(jh)
622
622
  if background:
623
- from edsl.results import Results
623
+ from ..results import Results
624
624
 
625
625
  results = Results.from_job_info(job_info)
626
626
  return results, None
@@ -881,7 +881,7 @@ class Jobs(Base):
881
881
  ],
882
882
  }
883
883
  if add_edsl_version:
884
- from edsl import __version__
884
+ from .. import __version__
885
885
 
886
886
  d["edsl_version"] = __version__
887
887
  d["edsl_class_name"] = "Jobs"
edsl/jobs/jobs_checks.py CHANGED
@@ -3,7 +3,7 @@ Checks a Jobs object for missing API keys and other requirements.
3
3
  """
4
4
 
5
5
  import os
6
- from edsl.key_management.key_lookup_builder import MissingAPIKeyError
6
+ from ..key_management.key_lookup_builder import MissingAPIKeyError
7
7
 
8
8
 
9
9
  class JobsChecks:
@@ -16,7 +16,7 @@ class JobsChecks:
16
16
  self.jobs = jobs
17
17
 
18
18
  def check_api_keys(self) -> None:
19
- from edsl.language_models.model import Model
19
+ from ..language_models.model import Model
20
20
 
21
21
  if len(self.jobs.models) == 0:
22
22
  models = [Model()]
@@ -37,7 +37,7 @@ class JobsChecks:
37
37
  """
38
38
  missing_api_keys = set()
39
39
 
40
- from edsl.enums import service_to_api_keyname
40
+ from ..enums import service_to_api_keyname
41
41
 
42
42
  for model in self.jobs.models: # + [Model()]:
43
43
  if not model.has_valid_api_key():
@@ -134,8 +134,8 @@ class JobsChecks:
134
134
  def key_process(self):
135
135
  import secrets
136
136
  from dotenv import load_dotenv
137
- from edsl.coop.coop import Coop
138
- from edsl.utilities.utilities import write_api_key_to_env
137
+ from ..coop.coop import Coop
138
+ from ..utilities.utilities import write_api_key_to_env
139
139
 
140
140
  missing_api_keys = self.get_missing_api_keys()
141
141
 
@@ -140,8 +140,8 @@ class JobsComponentConstructor:
140
140
 
141
141
  @staticmethod
142
142
  def _get_empty_container_object(object):
143
- from edsl.agents import AgentList
144
- from edsl.scenarios import ScenarioList
143
+ from ..agents import AgentList
144
+ from ..scenarios import ScenarioList
145
145
 
146
146
  return {"Agent": AgentList([]), "Scenario": ScenarioList([])}.get(
147
147
  object.__class__.__name__, []
@@ -137,7 +137,7 @@ class JobsPrompts:
137
137
  def price_lookup(self) -> dict:
138
138
  """Fetches the price lookup from Coop if it is not already cached."""
139
139
  if self._price_lookup is None:
140
- from edsl.coop.coop import Coop
140
+ from ..coop.coop import Coop
141
141
 
142
142
  c = Coop()
143
143
  self._price_lookup = c.fetch_prices()
@@ -186,7 +186,7 @@ class JobsRunnerAsyncio:
186
186
  self.start_time = time.monotonic()
187
187
  self.completed = False
188
188
 
189
- from edsl.coop import Coop
189
+ from ..coop import Coop
190
190
 
191
191
  coop = Coop()
192
192
  endpoint_url = coop.get_progress_bar_url()
@@ -273,7 +273,7 @@ class JobsRunnerAsyncio:
273
273
  # breakpoint()
274
274
  results.bucket_collection = self.environment.bucket_collection
275
275
 
276
- from edsl.jobs.results_exceptions_handler import ResultsExceptionsHandler
276
+ from .results_exceptions_handler import ResultsExceptionsHandler
277
277
 
278
278
  results_exceptions_handler = ResultsExceptionsHandler(results, parameters)
279
279
 
@@ -43,7 +43,7 @@ class JobsRemoteInferenceHandler:
43
43
  self.verbose = verbose
44
44
  self.poll_interval = poll_interval
45
45
 
46
- from edsl.config import CONFIG
46
+ from ..config import CONFIG
47
47
 
48
48
  self.expected_parrot_url = CONFIG.get("EXPECTED_PARROT_URL")
49
49
  self.remote_inference_url = f"{self.expected_parrot_url}/home/remote-inference"
@@ -1,8 +1,8 @@
1
1
  from typing import Protocol
2
2
  import sys
3
3
  #from edsl.scenarios.FileStore import HTMLFileStore
4
- from edsl.config import CONFIG
5
- from edsl.coop.coop import Coop
4
+ from ..config import CONFIG
5
+ from ..coop.coop import Coop
6
6
  from ..scenarios import FileStore
7
7
  from .exceptions import JobsErrors
8
8
 
@@ -231,12 +231,16 @@ class LanguageModel(
231
231
  for key, value in kwargs.items():
232
232
  if key not in parameters:
233
233
  setattr(self, key, value)
234
-
234
+
235
235
  # Handle API key check skip for testing
236
236
  if kwargs.get("skip_api_key_check", False):
237
237
  # Skip the API key check. Sometimes this is useful for testing.
238
238
  self._api_token = None
239
239
 
240
+ # Add canned response to parameters
241
+ if "canned_response" in kwargs:
242
+ self.parameters["canned_response"] = kwargs["canned_response"]
243
+
240
244
  def _set_key_lookup(self, key_lookup: "KeyLookup") -> "KeyLookup":
241
245
  """Set up the API key lookup mechanism.
242
246
 
@@ -1,3 +1,26 @@
1
+ """
2
+ The notebooks module provides tools for working with Jupyter notebooks.
3
+
4
+ It includes classes for notebook creation, manipulation, and conversion
5
+ to other formats such as LaTeX.
6
+ """
7
+
1
8
  from .notebook import Notebook
9
+ from .notebook_to_latex import NotebookToLaTeX
10
+ from .exceptions import (
11
+ NotebookError,
12
+ NotebookValueError,
13
+ NotebookFormatError,
14
+ NotebookConversionError,
15
+ NotebookEnvironmentError,
16
+ )
2
17
 
3
- __all__ = ["Notebook"]
18
+ __all__ = [
19
+ "Notebook",
20
+ "NotebookToLaTeX",
21
+ "NotebookError",
22
+ "NotebookValueError",
23
+ "NotebookFormatError",
24
+ "NotebookConversionError",
25
+ "NotebookEnvironmentError",
26
+ ]
@@ -0,0 +1,82 @@
1
+ """
2
+ Custom exceptions for the notebooks module.
3
+ """
4
+
5
+ from ..base import BaseException
6
+
7
+
8
+ class NotebookError(BaseException):
9
+ """
10
+ Base exception class for all notebook-related errors.
11
+
12
+ This is the parent class for all exceptions related to notebook
13
+ operations, including creation, validation, and conversion.
14
+ """
15
+ relevant_doc = "https://docs.expectedparrot.com/"
16
+
17
+
18
+ class NotebookValueError(NotebookError):
19
+ """
20
+ Exception raised when an invalid value is provided to a notebook method.
21
+
22
+ This exception occurs when attempting to create or modify a notebook
23
+ with invalid values, such as:
24
+ - Invalid data format
25
+ - Incompatible notebook contents
26
+
27
+ Examples:
28
+ ```python
29
+ # Attempting to create a notebook with invalid data
30
+ notebook = Notebook(data=invalid_data) # Raises NotebookValueError
31
+ ```
32
+ """
33
+ relevant_doc = "https://docs.expectedparrot.com/"
34
+
35
+
36
+ class NotebookFormatError(NotebookError):
37
+ """
38
+ Exception raised when a notebook's format is invalid.
39
+
40
+ This exception occurs when the notebook structure does not conform
41
+ to the expected Jupyter Notebook format.
42
+
43
+ Examples:
44
+ ```python
45
+ # Attempting to load a notebook with invalid format
46
+ notebook = Notebook.from_dict(invalid_dict) # Raises NotebookFormatError
47
+ ```
48
+ """
49
+ relevant_doc = "https://docs.expectedparrot.com/"
50
+
51
+
52
+ class NotebookConversionError(NotebookError):
53
+ """
54
+ Exception raised when a notebook conversion fails.
55
+
56
+ This exception occurs when attempting to convert a notebook to another
57
+ format (like LaTeX) and the conversion process fails.
58
+
59
+ Examples:
60
+ ```python
61
+ # Attempting to convert a notebook to LaTeX with invalid options
62
+ notebook.to_latex(invalid_options) # Raises NotebookConversionError
63
+ ```
64
+ """
65
+ relevant_doc = "https://docs.expectedparrot.com/"
66
+
67
+
68
+ class NotebookEnvironmentError(NotebookError):
69
+ """
70
+ Exception raised when the notebook environment is not supportable.
71
+
72
+ This exception occurs when attempting to create a notebook in an
73
+ environment that doesn't provide required context, such as when
74
+ trying to create a notebook from within itself outside of VS Code.
75
+
76
+ Examples:
77
+ ```python
78
+ # Attempting to create a notebook from within itself in an unsupported IDE
79
+ notebook = Notebook() # Raises NotebookEnvironmentError
80
+ ```
81
+ """
82
+ relevant_doc = "https://docs.expectedparrot.com/"
@@ -2,7 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  import json
5
- from typing import Dict, List, Optional
5
+ from typing import Dict, List, Optional, TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from rich.table import Table
6
9
  from uuid import uuid4
7
10
 
8
11
  from ..base import Base
@@ -47,7 +50,8 @@ class Notebook(Base):
47
50
  self.data = json.loads(json.dumps(data))
48
51
  else:
49
52
  # TODO: Support for IDEs other than VSCode
50
- raise NotImplementedError(
53
+ from .exceptions import NotebookEnvironmentError
54
+ raise NotebookEnvironmentError(
51
55
  "Cannot create a notebook from within itself in this development environment"
52
56
  )
53
57
 
@@ -251,7 +255,7 @@ class Notebook(Base):
251
255
 
252
256
  :param filename: Name of the output folder and main tex file (without extension)
253
257
  """
254
- from .NotebookToLaTeX import NotebookToLaTeX
258
+ from .notebook_to_latex import NotebookToLaTeX
255
259
 
256
260
  NotebookToLaTeX(self).convert(filename)
257
261
 
@@ -122,7 +122,7 @@ To clean up build files:
122
122
 
123
123
  # Example usage:
124
124
  if __name__ == "__main__":
125
- from edsl import Notebook
125
+ from .. import Notebook
126
126
 
127
127
  # Create or load a notebook
128
128
  notebook = Notebook.example()
edsl/prompts/__init__.py CHANGED
@@ -1,4 +1,25 @@
1
- # from edsl.prompts.registry import get_classes
1
+ """
2
+ The prompts module provides tools for creating and managing prompts.
3
+
4
+ It includes classes for template-based prompts with variable substitution,
5
+ prompt rendering, and component management for language model interactions.
6
+ """
2
7
  from .prompt import Prompt
8
+ from .exceptions import (
9
+ PromptError,
10
+ TemplateRenderError,
11
+ PromptBadQuestionTypeError,
12
+ PromptBadLanguageModelTypeError,
13
+ PromptValueError,
14
+ PromptImplementationError
15
+ )
3
16
 
4
- __all__ = ["Prompt"]
17
+ __all__ = [
18
+ "Prompt",
19
+ "PromptError",
20
+ "TemplateRenderError",
21
+ "PromptBadQuestionTypeError",
22
+ "PromptBadLanguageModelTypeError",
23
+ "PromptValueError",
24
+ "PromptImplementationError"
25
+ ]
edsl/prompts/prompt.py CHANGED
@@ -145,7 +145,7 @@ class Prompt(PersistenceMixin, RepresentationMixin):
145
145
  if path_to_folder is None:
146
146
  from importlib import resources
147
147
 
148
- path_to_folder = resources.path("edsl.questions", "prompt_templates")
148
+ path_to_folder = resources.path("..questions", "prompt_templates")
149
149
 
150
150
  try:
151
151
  folder_path = Path(path_to_folder)