edsl 0.1.33__py3-none-any.whl → 0.1.33.dev1__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 (180) hide show
  1. edsl/Base.py +3 -9
  2. edsl/__init__.py +3 -8
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +8 -40
  5. edsl/agents/AgentList.py +0 -43
  6. edsl/agents/Invigilator.py +219 -135
  7. edsl/agents/InvigilatorBase.py +59 -148
  8. edsl/agents/{PromptConstructor.py → PromptConstructionMixin.py} +89 -138
  9. edsl/agents/__init__.py +0 -1
  10. edsl/config.py +56 -47
  11. edsl/coop/coop.py +7 -50
  12. edsl/data/Cache.py +1 -35
  13. edsl/data_transfer_models.py +38 -73
  14. edsl/enums.py +0 -4
  15. edsl/exceptions/language_models.py +1 -25
  16. edsl/exceptions/questions.py +5 -62
  17. edsl/exceptions/results.py +0 -4
  18. edsl/inference_services/AnthropicService.py +11 -13
  19. edsl/inference_services/AwsBedrock.py +17 -19
  20. edsl/inference_services/AzureAI.py +20 -37
  21. edsl/inference_services/GoogleService.py +12 -16
  22. edsl/inference_services/GroqService.py +0 -2
  23. edsl/inference_services/InferenceServiceABC.py +3 -58
  24. edsl/inference_services/OpenAIService.py +54 -48
  25. edsl/inference_services/models_available_cache.py +6 -0
  26. edsl/inference_services/registry.py +0 -6
  27. edsl/jobs/Answers.py +12 -10
  28. edsl/jobs/Jobs.py +21 -36
  29. edsl/jobs/buckets/BucketCollection.py +15 -24
  30. edsl/jobs/buckets/TokenBucket.py +14 -93
  31. edsl/jobs/interviews/Interview.py +78 -366
  32. edsl/jobs/interviews/InterviewExceptionEntry.py +19 -85
  33. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +286 -0
  34. edsl/jobs/interviews/{InterviewExceptionCollection.py → interview_exception_tracking.py} +68 -14
  35. edsl/jobs/interviews/retry_management.py +37 -0
  36. edsl/jobs/runners/JobsRunnerAsyncio.py +175 -146
  37. edsl/jobs/runners/JobsRunnerStatusMixin.py +333 -0
  38. edsl/jobs/tasks/QuestionTaskCreator.py +23 -30
  39. edsl/jobs/tasks/TaskHistory.py +213 -148
  40. edsl/language_models/LanguageModel.py +156 -261
  41. edsl/language_models/ModelList.py +2 -2
  42. edsl/language_models/RegisterLanguageModelsMeta.py +29 -14
  43. edsl/language_models/registry.py +6 -23
  44. edsl/language_models/repair.py +19 -0
  45. edsl/prompts/Prompt.py +2 -52
  46. edsl/questions/AnswerValidatorMixin.py +26 -23
  47. edsl/questions/QuestionBase.py +249 -329
  48. edsl/questions/QuestionBudget.py +41 -99
  49. edsl/questions/QuestionCheckBox.py +35 -227
  50. edsl/questions/QuestionExtract.py +27 -98
  51. edsl/questions/QuestionFreeText.py +29 -52
  52. edsl/questions/QuestionFunctional.py +0 -7
  53. edsl/questions/QuestionList.py +22 -141
  54. edsl/questions/QuestionMultipleChoice.py +65 -159
  55. edsl/questions/QuestionNumerical.py +46 -88
  56. edsl/questions/QuestionRank.py +24 -182
  57. edsl/questions/RegisterQuestionsMeta.py +12 -31
  58. edsl/questions/__init__.py +4 -3
  59. edsl/questions/derived/QuestionLikertFive.py +5 -10
  60. edsl/questions/derived/QuestionLinearScale.py +2 -15
  61. edsl/questions/derived/QuestionTopK.py +1 -10
  62. edsl/questions/derived/QuestionYesNo.py +3 -24
  63. edsl/questions/descriptors.py +7 -43
  64. edsl/questions/question_registry.py +2 -6
  65. edsl/results/Dataset.py +0 -20
  66. edsl/results/DatasetExportMixin.py +48 -46
  67. edsl/results/Result.py +5 -32
  68. edsl/results/Results.py +46 -135
  69. edsl/results/ResultsDBMixin.py +3 -3
  70. edsl/scenarios/FileStore.py +10 -71
  71. edsl/scenarios/Scenario.py +25 -96
  72. edsl/scenarios/ScenarioImageMixin.py +2 -2
  73. edsl/scenarios/ScenarioList.py +39 -361
  74. edsl/scenarios/ScenarioListExportMixin.py +0 -9
  75. edsl/scenarios/ScenarioListPdfMixin.py +4 -150
  76. edsl/study/SnapShot.py +1 -8
  77. edsl/study/Study.py +0 -32
  78. edsl/surveys/Rule.py +1 -10
  79. edsl/surveys/RuleCollection.py +5 -21
  80. edsl/surveys/Survey.py +310 -636
  81. edsl/surveys/SurveyExportMixin.py +9 -71
  82. edsl/surveys/SurveyFlowVisualizationMixin.py +1 -2
  83. edsl/surveys/SurveyQualtricsImport.py +4 -75
  84. edsl/utilities/gcp_bucket/simple_example.py +9 -0
  85. edsl/utilities/utilities.py +1 -9
  86. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/METADATA +2 -5
  87. edsl-0.1.33.dev1.dist-info/RECORD +209 -0
  88. edsl/TemplateLoader.py +0 -24
  89. edsl/auto/AutoStudy.py +0 -117
  90. edsl/auto/StageBase.py +0 -230
  91. edsl/auto/StageGenerateSurvey.py +0 -178
  92. edsl/auto/StageLabelQuestions.py +0 -125
  93. edsl/auto/StagePersona.py +0 -61
  94. edsl/auto/StagePersonaDimensionValueRanges.py +0 -88
  95. edsl/auto/StagePersonaDimensionValues.py +0 -74
  96. edsl/auto/StagePersonaDimensions.py +0 -69
  97. edsl/auto/StageQuestions.py +0 -73
  98. edsl/auto/SurveyCreatorPipeline.py +0 -21
  99. edsl/auto/utilities.py +0 -224
  100. edsl/coop/PriceFetcher.py +0 -58
  101. edsl/inference_services/MistralAIService.py +0 -120
  102. edsl/inference_services/TestService.py +0 -80
  103. edsl/inference_services/TogetherAIService.py +0 -170
  104. edsl/jobs/FailedQuestion.py +0 -78
  105. edsl/jobs/runners/JobsRunnerStatus.py +0 -331
  106. edsl/language_models/fake_openai_call.py +0 -15
  107. edsl/language_models/fake_openai_service.py +0 -61
  108. edsl/language_models/utilities.py +0 -61
  109. edsl/questions/QuestionBaseGenMixin.py +0 -133
  110. edsl/questions/QuestionBasePromptsMixin.py +0 -266
  111. edsl/questions/Quick.py +0 -41
  112. edsl/questions/ResponseValidatorABC.py +0 -170
  113. edsl/questions/decorators.py +0 -21
  114. edsl/questions/prompt_templates/question_budget.jinja +0 -13
  115. edsl/questions/prompt_templates/question_checkbox.jinja +0 -32
  116. edsl/questions/prompt_templates/question_extract.jinja +0 -11
  117. edsl/questions/prompt_templates/question_free_text.jinja +0 -3
  118. edsl/questions/prompt_templates/question_linear_scale.jinja +0 -11
  119. edsl/questions/prompt_templates/question_list.jinja +0 -17
  120. edsl/questions/prompt_templates/question_multiple_choice.jinja +0 -33
  121. edsl/questions/prompt_templates/question_numerical.jinja +0 -37
  122. edsl/questions/templates/__init__.py +0 -0
  123. edsl/questions/templates/budget/__init__.py +0 -0
  124. edsl/questions/templates/budget/answering_instructions.jinja +0 -7
  125. edsl/questions/templates/budget/question_presentation.jinja +0 -7
  126. edsl/questions/templates/checkbox/__init__.py +0 -0
  127. edsl/questions/templates/checkbox/answering_instructions.jinja +0 -10
  128. edsl/questions/templates/checkbox/question_presentation.jinja +0 -22
  129. edsl/questions/templates/extract/__init__.py +0 -0
  130. edsl/questions/templates/extract/answering_instructions.jinja +0 -7
  131. edsl/questions/templates/extract/question_presentation.jinja +0 -1
  132. edsl/questions/templates/free_text/__init__.py +0 -0
  133. edsl/questions/templates/free_text/answering_instructions.jinja +0 -0
  134. edsl/questions/templates/free_text/question_presentation.jinja +0 -1
  135. edsl/questions/templates/likert_five/__init__.py +0 -0
  136. edsl/questions/templates/likert_five/answering_instructions.jinja +0 -10
  137. edsl/questions/templates/likert_five/question_presentation.jinja +0 -12
  138. edsl/questions/templates/linear_scale/__init__.py +0 -0
  139. edsl/questions/templates/linear_scale/answering_instructions.jinja +0 -5
  140. edsl/questions/templates/linear_scale/question_presentation.jinja +0 -5
  141. edsl/questions/templates/list/__init__.py +0 -0
  142. edsl/questions/templates/list/answering_instructions.jinja +0 -4
  143. edsl/questions/templates/list/question_presentation.jinja +0 -5
  144. edsl/questions/templates/multiple_choice/__init__.py +0 -0
  145. edsl/questions/templates/multiple_choice/answering_instructions.jinja +0 -9
  146. edsl/questions/templates/multiple_choice/html.jinja +0 -0
  147. edsl/questions/templates/multiple_choice/question_presentation.jinja +0 -12
  148. edsl/questions/templates/numerical/__init__.py +0 -0
  149. edsl/questions/templates/numerical/answering_instructions.jinja +0 -8
  150. edsl/questions/templates/numerical/question_presentation.jinja +0 -7
  151. edsl/questions/templates/rank/__init__.py +0 -0
  152. edsl/questions/templates/rank/answering_instructions.jinja +0 -11
  153. edsl/questions/templates/rank/question_presentation.jinja +0 -15
  154. edsl/questions/templates/top_k/__init__.py +0 -0
  155. edsl/questions/templates/top_k/answering_instructions.jinja +0 -8
  156. edsl/questions/templates/top_k/question_presentation.jinja +0 -22
  157. edsl/questions/templates/yes_no/__init__.py +0 -0
  158. edsl/questions/templates/yes_no/answering_instructions.jinja +0 -6
  159. edsl/questions/templates/yes_no/question_presentation.jinja +0 -12
  160. edsl/results/DatasetTree.py +0 -145
  161. edsl/results/Selector.py +0 -118
  162. edsl/results/tree_explore.py +0 -115
  163. edsl/surveys/instructions/ChangeInstruction.py +0 -47
  164. edsl/surveys/instructions/Instruction.py +0 -34
  165. edsl/surveys/instructions/InstructionCollection.py +0 -77
  166. edsl/surveys/instructions/__init__.py +0 -0
  167. edsl/templates/error_reporting/base.html +0 -24
  168. edsl/templates/error_reporting/exceptions_by_model.html +0 -35
  169. edsl/templates/error_reporting/exceptions_by_question_name.html +0 -17
  170. edsl/templates/error_reporting/exceptions_by_type.html +0 -17
  171. edsl/templates/error_reporting/interview_details.html +0 -116
  172. edsl/templates/error_reporting/interviews.html +0 -10
  173. edsl/templates/error_reporting/overview.html +0 -5
  174. edsl/templates/error_reporting/performance_plot.html +0 -2
  175. edsl/templates/error_reporting/report.css +0 -74
  176. edsl/templates/error_reporting/report.html +0 -118
  177. edsl/templates/error_reporting/report.js +0 -25
  178. edsl-0.1.33.dist-info/RECORD +0 -295
  179. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/LICENSE +0 -0
  180. {edsl-0.1.33.dist-info → edsl-0.1.33.dev1.dist-info}/WHEEL +0 -0
@@ -1,11 +1,5 @@
1
1
  import textwrap
2
2
  from random import random
3
- from edsl.config import CONFIG
4
-
5
- # if "EDSL_DEFAULT_MODEL" not in CONFIG:
6
- # default_model = "test"
7
- # else:
8
- # default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
9
3
 
10
4
 
11
5
  def get_model_class(model_name, registry=None):
@@ -33,24 +27,20 @@ class Meta(type):
33
27
 
34
28
 
35
29
  class Model(metaclass=Meta):
36
- default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
30
+ default_model = "gpt-4-1106-preview"
37
31
 
38
- def __new__(
39
- cls, model_name=None, registry=None, service_name=None, *args, **kwargs
40
- ):
32
+ def __new__(cls, model_name=None, registry=None, *args, **kwargs):
41
33
  # Map index to the respective subclass
42
34
  if model_name is None:
43
- model_name = (
44
- cls.default_model
45
- ) # when model_name is None, use the default model, set in the config file
35
+ model_name = cls.default_model
46
36
  from edsl.inference_services.registry import default
47
37
 
48
38
  registry = registry or default
49
39
 
50
- if isinstance(model_name, int): # can refer to a model by index
40
+ if isinstance(model_name, int):
51
41
  model_name = cls.available(name_only=True)[model_name]
52
42
 
53
- factory = registry.create_model_factory(model_name, service_name=service_name)
43
+ factory = registry.create_model_factory(model_name)
54
44
  return factory(*args, **kwargs)
55
45
 
56
46
  @classmethod
@@ -68,18 +58,11 @@ class Model(metaclass=Meta):
68
58
  return [r._inference_service_ for r in registry.services]
69
59
 
70
60
  @classmethod
71
- def available(cls, search_term=None, name_only=False, registry=None, service=None):
61
+ def available(cls, search_term=None, name_only=False, registry=None):
72
62
  from edsl.inference_services.registry import default
73
63
 
74
64
  registry = registry or default
75
65
  full_list = registry.available()
76
-
77
- if service is not None:
78
- if service not in cls.services(registry=registry):
79
- raise ValueError(f"Service {service} not found in available services.")
80
-
81
- full_list = [m for m in full_list if m[1] == service]
82
-
83
66
  if search_term is None:
84
67
  if name_only:
85
68
  return [m[0] for m in full_list]
@@ -141,6 +141,25 @@ def repair(
141
141
  return repair_wrapper(bad_json, error_message, user_prompt, system_prompt, cache)
142
142
 
143
143
 
144
+ # Example usage:
145
+ # result, success = repair_wrapper('{"name": "John Doe", "age": 30,}') # example bad JSON
146
+
147
+
148
+ # def repair_wrapper(bad_json, error_message=""):
149
+ # loop = asyncio.get_event_loop()
150
+ # if loop.is_running():
151
+ # # Add repair as a task to the running loop
152
+ # task = loop.create_task(repair(bad_json, error_message))
153
+ # return task
154
+ # else:
155
+ # # Run a new event loop for repair
156
+ # return loop.run_until_complete(repair(bad_json, error_message))
157
+
158
+
159
+ # Example usage:
160
+ # result, success = repair_wrapper('{"name": "John Doe", "age": 30,}') # example bad JSON
161
+
162
+
144
163
  if __name__ == "__main__":
145
164
  bad_json = """
146
165
  {
edsl/prompts/Prompt.py CHANGED
@@ -3,17 +3,13 @@ from typing import Optional
3
3
  from abc import ABC
4
4
  from typing import Any, List
5
5
 
6
- from jinja2 import Environment, FileSystemLoader
7
- from typing import Union, Dict
8
- from pathlib import Path
9
-
10
6
  from rich.table import Table
11
7
  from jinja2 import Template, Environment, meta, TemplateSyntaxError, Undefined
12
8
 
13
9
 
14
10
  class PreserveUndefined(Undefined):
15
11
  def __str__(self):
16
- return "{{ " + str(self._undefined_name) + " }}"
12
+ return "{{ " + self._undefined_name + " }}"
17
13
 
18
14
 
19
15
  from edsl.exceptions.prompts import TemplateRenderError
@@ -74,50 +70,6 @@ class PromptBase(
74
70
  text = f.read()
75
71
  return cls(text=text)
76
72
 
77
- @classmethod
78
- def from_template(
79
- cls,
80
- file_name: str,
81
- path_to_folder: Optional[Union[str, Path]] = None,
82
- **kwargs: Dict[str, Any],
83
- ) -> "PromptBase":
84
- """Create a `PromptBase` from a Jinja template.
85
-
86
- Args:
87
- file_name (str): The name of the Jinja template file.
88
- path_to_folder (Union[str, Path]): The path to the folder containing the template.
89
- Can be absolute or relative.
90
- **kwargs: Variables to be passed to the template for rendering.
91
-
92
- Returns:
93
- PromptBase: An instance of PromptBase with the rendered template as text.
94
- """
95
- # if file_name lacks the .j2 extension, add it
96
- if not file_name.endswith(".jinja"):
97
- file_name += ".jinja"
98
-
99
- # Convert path_to_folder to a Path object if it's a string
100
- if path_to_folder is None:
101
- from importlib import resources
102
- import os
103
-
104
- path_to_folder = resources.path("edsl.questions", "prompt_templates")
105
-
106
- try:
107
- folder_path = Path(path_to_folder)
108
- except Exception as e:
109
- raise ValueError(f"Invalid path: {path_to_folder}. Error: {e}")
110
-
111
- with open(folder_path.joinpath(file_name), "r") as f:
112
- text = f.read()
113
- return cls(text=text)
114
- # Resolve the path to get the absolute path
115
- # absolute_path = folder_path.resolve()
116
- # env = Environment(loader=FileSystemLoader(absolute_path))
117
- # template = env.get_template(file_name)
118
- # rendered_text = template.render({})
119
- # return cls(text=rendered_text)
120
-
121
73
  @property
122
74
  def text(self):
123
75
  """Return the `Prompt` text."""
@@ -295,9 +247,7 @@ class PromptBase(
295
247
  "Too much nesting - you created an infinite loop here, pal"
296
248
  )
297
249
  except TemplateSyntaxError as e:
298
- raise TemplateRenderError(
299
- f"Template syntax error: {e}. Bad template: {text}"
300
- )
250
+ raise TemplateRenderError(f"Template syntax error: {e}")
301
251
 
302
252
  def to_dict(self) -> dict[str, Any]:
303
253
  """Return the `Prompt` as a dictionary.
@@ -16,27 +16,19 @@ class AnswerValidatorMixin:
16
16
  - Question specific validation: validators for specific question types
17
17
  """
18
18
 
19
- def failing_job(self):
20
- from edsl import Agent
21
-
22
- a = Agent()
23
-
24
- def f(self, question, scenario):
25
- return []
26
-
27
- a.add_direct_question_answering_method(f, validate_response=True)
28
- from edsl import QuestionNumerical
29
-
30
- q = QuestionNumerical.example()
31
- results = q.by(a).run()
32
- return results
33
-
34
19
  #####################
35
20
  # TEMPLATE VALIDATION
36
21
  #####################
37
22
  def _validate_answer_template_basic(self, answer: Any) -> None:
38
23
  """Check that the answer (i) is a dictionary (ii) has an 'answer' key.
39
24
 
25
+ >>> avm = AnswerValidatorMixin()
26
+ >>> avm._validate_answer_template_basic({'answer': 1})
27
+ >>> avm._validate_answer_template_basic([])
28
+ Traceback (most recent call last):
29
+ ...
30
+ edsl.exceptions.questions.QuestionAnswerValidationError: Answer must be a dictionary (got []).
31
+
40
32
  - E.g., both {'answer': 1} and {'answer': {'a': 1}, 'other_key'=[1,2,3]} are valid
41
33
  """
42
34
  if not isinstance(answer, dict):
@@ -64,9 +56,14 @@ class AnswerValidatorMixin:
64
56
  def _validate_answer_key_value_numeric(
65
57
  self, answer: dict[str, Any], key: str
66
58
  ) -> None:
67
- """Check that the value is numeric (int or float).
68
- Can also deal with strings that contain commas and other characters.
69
-
59
+ """Check that the value of a key is numeric (int or float).
60
+
61
+ >>> avm = AnswerValidatorMixin()
62
+ >>> avm._validate_answer_key_value_numeric({'answer': 1}, 'answer')
63
+ >>> avm._validate_answer_key_value_numeric({'answer': 'poo'}, 'answer')
64
+ Traceback (most recent call last):
65
+ ...
66
+ edsl.exceptions.questions.QuestionAnswerValidationError: Answer should be numerical (int or float). Got 'poo'
70
67
  """
71
68
  value = answer.get(key)
72
69
  initial_value = value
@@ -131,6 +128,15 @@ class AnswerValidatorMixin:
131
128
 
132
129
  :param answer: Answer to validate
133
130
 
131
+ >>> avm = AnswerValidatorMixin()
132
+ >>> avm.question_options = ["a", "b", "c"]
133
+ >>> avm.min_selections = 1
134
+ >>> avm.max_selections = 2
135
+ >>> avm._validate_answer_checkbox({"answer": ["0", "1"]})
136
+ >>> avm._validate_answer_checkbox({"answer": []})
137
+ Traceback (most recent call last):
138
+ ...
139
+ edsl.exceptions.questions.QuestionAnswerValidationError:...
134
140
 
135
141
  Check that answer["answer"]:
136
142
  - has elements that are strings, bytes-like objects or real numbers evaluating to integers
@@ -281,9 +287,6 @@ class AnswerValidatorMixin:
281
287
 
282
288
 
283
289
  if __name__ == "__main__":
284
- pass
285
- # import doctest
286
-
287
- # doctest.testmod(optionflags=doctest.ELLIPSIS)
290
+ import doctest
288
291
 
289
- # results = AnswerValidatorMixin().failing_job()
292
+ doctest.testmod(optionflags=doctest.ELLIPSIS)