edsl 0.1.38__py3-none-any.whl → 0.1.38.dev2__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 (53) hide show
  1. edsl/Base.py +31 -60
  2. edsl/__version__.py +1 -1
  3. edsl/agents/Agent.py +9 -18
  4. edsl/agents/AgentList.py +8 -59
  5. edsl/agents/Invigilator.py +7 -18
  6. edsl/agents/InvigilatorBase.py +19 -0
  7. edsl/agents/PromptConstructor.py +4 -5
  8. edsl/config.py +0 -8
  9. edsl/coop/coop.py +7 -74
  10. edsl/data/Cache.py +2 -27
  11. edsl/data/CacheEntry.py +3 -8
  12. edsl/data/RemoteCacheSync.py +19 -0
  13. edsl/enums.py +0 -2
  14. edsl/inference_services/GoogleService.py +15 -7
  15. edsl/inference_services/registry.py +0 -2
  16. edsl/jobs/Jobs.py +548 -88
  17. edsl/jobs/interviews/Interview.py +11 -11
  18. edsl/jobs/runners/JobsRunnerAsyncio.py +35 -140
  19. edsl/jobs/runners/JobsRunnerStatus.py +2 -0
  20. edsl/jobs/tasks/TaskHistory.py +16 -15
  21. edsl/language_models/LanguageModel.py +84 -44
  22. edsl/language_models/ModelList.py +1 -47
  23. edsl/language_models/registry.py +4 -57
  24. edsl/prompts/Prompt.py +3 -8
  25. edsl/questions/QuestionBase.py +16 -20
  26. edsl/questions/QuestionExtract.py +4 -3
  27. edsl/questions/question_registry.py +6 -36
  28. edsl/results/Dataset.py +15 -146
  29. edsl/results/DatasetExportMixin.py +217 -231
  30. edsl/results/DatasetTree.py +4 -134
  31. edsl/results/Result.py +9 -18
  32. edsl/results/Results.py +51 -145
  33. edsl/scenarios/FileStore.py +13 -187
  34. edsl/scenarios/Scenario.py +4 -61
  35. edsl/scenarios/ScenarioList.py +62 -237
  36. edsl/surveys/Survey.py +2 -16
  37. edsl/surveys/SurveyFlowVisualizationMixin.py +9 -67
  38. edsl/surveys/instructions/Instruction.py +0 -12
  39. edsl/templates/error_reporting/interview_details.html +3 -3
  40. edsl/templates/error_reporting/interviews.html +9 -18
  41. edsl/utilities/utilities.py +0 -15
  42. {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.dist-info}/METADATA +1 -2
  43. {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.dist-info}/RECORD +45 -53
  44. edsl/inference_services/PerplexityService.py +0 -163
  45. edsl/jobs/JobsChecks.py +0 -147
  46. edsl/jobs/JobsPrompts.py +0 -268
  47. edsl/jobs/JobsRemoteInferenceHandler.py +0 -239
  48. edsl/results/CSSParameterizer.py +0 -108
  49. edsl/results/TableDisplay.py +0 -198
  50. edsl/results/table_display.css +0 -78
  51. edsl/scenarios/ScenarioJoin.py +0 -127
  52. {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.dist-info}/LICENSE +0 -0
  53. {edsl-0.1.38.dist-info → edsl-0.1.38.dev2.dist-info}/WHEEL +0 -0
@@ -41,20 +41,18 @@ from edsl.data_transfer_models import (
41
41
  AgentResponseDict,
42
42
  )
43
43
 
44
- if TYPE_CHECKING:
45
- from edsl.data.Cache import Cache
46
- from edsl.scenarios.FileStore import FileStore
47
- from edsl.questions.QuestionBase import QuestionBase
48
44
 
49
45
  from edsl.config import CONFIG
50
46
  from edsl.utilities.decorators import sync_wrapper, jupyter_nb_handler
51
- from edsl.utilities.decorators import remove_edsl_version
52
-
53
- from edsl.Base import PersistenceMixin
47
+ from edsl.utilities.decorators import add_edsl_version, remove_edsl_version
48
+ from edsl.language_models.repair import repair
49
+ from edsl.enums import InferenceServiceType
50
+ from edsl.Base import RichPrintingMixin, PersistenceMixin
54
51
  from edsl.language_models.RegisterLanguageModelsMeta import RegisterLanguageModelsMeta
55
- from edsl.language_models.KeyLookup import KeyLookup
56
52
  from edsl.exceptions.language_models import LanguageModelBadResponseError
57
53
 
54
+ from edsl.language_models.KeyLookup import KeyLookup
55
+
58
56
  TIMEOUT = float(CONFIG.get("EDSL_API_TIMEOUT"))
59
57
 
60
58
 
@@ -118,11 +116,29 @@ def handle_key_error(func):
118
116
 
119
117
 
120
118
  class LanguageModel(
121
- PersistenceMixin,
122
- ABC,
123
- metaclass=RegisterLanguageModelsMeta,
119
+ RichPrintingMixin, PersistenceMixin, ABC, metaclass=RegisterLanguageModelsMeta
124
120
  ):
125
- """ABC for Language Models."""
121
+ """ABC for LLM subclasses.
122
+
123
+ TODO:
124
+
125
+ 1) Need better, more descriptive names for functions
126
+
127
+ get_model_response_no_cache (currently called async_execute_model_call)
128
+
129
+ get_model_response (currently called async_get_raw_response; uses cache & adds tracking info)
130
+ Calls:
131
+ - async_execute_model_call
132
+ - _updated_model_response_with_tracking
133
+
134
+ get_answer (currently called async_get_response)
135
+ This parses out the answer block and does some error-handling.
136
+ Calls:
137
+ - async_get_raw_response
138
+ - parse_response
139
+
140
+
141
+ """
126
142
 
127
143
  _model_ = None
128
144
  key_sequence = (
@@ -180,7 +196,7 @@ class LanguageModel(
180
196
  system_prompt = "You are a helpful agent pretending to be a human."
181
197
  return self.execute_model_call(user_prompt, system_prompt)
182
198
 
183
- def set_key_lookup(self, key_lookup: KeyLookup) -> None:
199
+ def set_key_lookup(self, key_lookup: KeyLookup):
184
200
  del self._api_token
185
201
  self.key_lookup = key_lookup
186
202
 
@@ -195,14 +211,10 @@ class LanguageModel(
195
211
  def __getitem__(self, key):
196
212
  return getattr(self, key)
197
213
 
198
- def _repr_html_(self) -> str:
199
- d = {"model": self.model}
200
- d.update(self.parameters)
201
- data = [[k, v] for k, v in d.items()]
202
- from tabulate import tabulate
214
+ def _repr_html_(self):
215
+ from edsl.utilities.utilities import data_to_html
203
216
 
204
- table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
205
- return f"<pre>{table}</pre>"
217
+ return data_to_html(self.to_dict())
206
218
 
207
219
  def hello(self, verbose=False):
208
220
  """Runs a simple test to check if the model is working."""
@@ -223,6 +235,7 @@ class LanguageModel(
223
235
  This method is used to check if the model has a valid API key.
224
236
  """
225
237
  from edsl.enums import service_to_api_keyname
238
+ import os
226
239
 
227
240
  if self._model_ == "test":
228
241
  return True
@@ -235,9 +248,9 @@ class LanguageModel(
235
248
  """Allow the model to be used as a key in a dictionary."""
236
249
  from edsl.utilities.utilities import dict_hash
237
250
 
238
- return dict_hash(self.to_dict(add_edsl_version=False))
251
+ return dict_hash(self.to_dict())
239
252
 
240
- def __eq__(self, other) -> bool:
253
+ def __eq__(self, other):
241
254
  """Check is two models are the same.
242
255
 
243
256
  >>> m1 = LanguageModel.example()
@@ -265,11 +278,15 @@ class LanguageModel(
265
278
  @property
266
279
  def RPM(self):
267
280
  """Model's requests-per-minute limit."""
281
+ # self._set_rate_limits()
282
+ # return self._safety_factor * self.__rate_limits["rpm"]
268
283
  return self._rpm
269
284
 
270
285
  @property
271
286
  def TPM(self):
272
287
  """Model's tokens-per-minute limit."""
288
+ # self._set_rate_limits()
289
+ # return self._safety_factor * self.__rate_limits["tpm"]
273
290
  return self._tpm
274
291
 
275
292
  @property
@@ -297,6 +314,8 @@ class LanguageModel(
297
314
  >>> LanguageModel._overide_default_parameters(passed_parameter_dict={"temperature": 0.5}, default_parameter_dict={"temperature":0.9, "max_tokens": 1000})
298
315
  {'temperature': 0.5, 'max_tokens': 1000}
299
316
  """
317
+ # parameters = dict({})
318
+
300
319
  # this is the case when data is loaded from a dict after serialization
301
320
  if "parameters" in passed_parameter_dict:
302
321
  passed_parameter_dict = passed_parameter_dict["parameters"]
@@ -410,10 +429,9 @@ class LanguageModel(
410
429
  self,
411
430
  user_prompt: str,
412
431
  system_prompt: str,
413
- cache: Cache,
432
+ cache: "Cache",
414
433
  iteration: int = 0,
415
- files_list: Optional[List[FileStore]] = None,
416
- invigilator=None,
434
+ files_list=None,
417
435
  ) -> ModelResponse:
418
436
  """Handle caching of responses.
419
437
 
@@ -437,6 +455,7 @@ class LanguageModel(
437
455
 
438
456
  if files_list:
439
457
  files_hash = "+".join([str(hash(file)) for file in files_list])
458
+ # print(f"Files hash: {files_hash}")
440
459
  user_prompt_with_hashes = user_prompt + f" {files_hash}"
441
460
  else:
442
461
  user_prompt_with_hashes = user_prompt
@@ -462,7 +481,9 @@ class LanguageModel(
462
481
  "user_prompt": user_prompt,
463
482
  "system_prompt": system_prompt,
464
483
  "files_list": files_list,
484
+ # **({"encoded_image": encoded_image} if encoded_image else {}),
465
485
  }
486
+ # response = await f(**params)
466
487
  response = await asyncio.wait_for(f(**params), timeout=TIMEOUT)
467
488
  new_cache_key = cache.store(
468
489
  **cache_call_params, response=response
@@ -483,9 +504,11 @@ class LanguageModel(
483
504
  _async_get_intended_model_call_outcome
484
505
  )
485
506
 
507
+ # get_raw_response = sync_wrapper(async_get_raw_response)
508
+
486
509
  def simple_ask(
487
510
  self,
488
- question: QuestionBase,
511
+ question: "QuestionBase",
489
512
  system_prompt="You are a helpful agent pretending to be a human.",
490
513
  top_logprobs=2,
491
514
  ):
@@ -500,10 +523,9 @@ class LanguageModel(
500
523
  self,
501
524
  user_prompt: str,
502
525
  system_prompt: str,
503
- cache: Cache,
526
+ cache: "Cache",
504
527
  iteration: int = 1,
505
- files_list: Optional[List[FileStore]] = None,
506
- **kwargs,
528
+ files_list: Optional[List["File"]] = None,
507
529
  ) -> dict:
508
530
  """Get response, parse, and return as string.
509
531
 
@@ -521,9 +543,6 @@ class LanguageModel(
521
543
  "cache": cache,
522
544
  "files_list": files_list,
523
545
  }
524
- if "invigilator" in kwargs:
525
- params.update({"invigilator": kwargs["invigilator"]})
526
-
527
546
  model_inputs = ModelInputs(user_prompt=user_prompt, system_prompt=system_prompt)
528
547
  model_outputs = await self._async_get_intended_model_call_outcome(**params)
529
548
  edsl_dict = self.parse_response(model_outputs.response)
@@ -534,6 +553,8 @@ class LanguageModel(
534
553
  )
535
554
  return agent_response_dict
536
555
 
556
+ # return await self._async_prepare_response(model_call_outcome, cache=cache)
557
+
537
558
  get_response = sync_wrapper(async_get_response)
538
559
 
539
560
  def cost(self, raw_response: dict[str, Any]) -> Union[float, str]:
@@ -583,7 +604,10 @@ class LanguageModel(
583
604
 
584
605
  return input_cost + output_cost
585
606
 
586
- def to_dict(self, add_edsl_version: bool = True) -> dict[str, Any]:
607
+ #######################
608
+ # SERIALIZATION METHODS
609
+ #######################
610
+ def to_dict(self, add_edsl_version=True) -> dict[str, Any]:
587
611
  """Convert instance to a dictionary
588
612
 
589
613
  >>> m = LanguageModel.example()
@@ -605,8 +629,18 @@ class LanguageModel(
605
629
  from edsl.language_models.registry import get_model_class
606
630
 
607
631
  model_class = get_model_class(data["model"])
632
+ # data["use_cache"] = True
608
633
  return model_class(**data)
609
634
 
635
+ #######################
636
+ # DUNDER METHODS
637
+ #######################
638
+ def print(self):
639
+ from rich import print_json
640
+ import json
641
+
642
+ print_json(json.dumps(self.to_dict()))
643
+
610
644
  def __repr__(self) -> str:
611
645
  """Return a string representation of the object."""
612
646
  param_string = ", ".join(
@@ -620,21 +654,33 @@ class LanguageModel(
620
654
 
621
655
  def __add__(self, other_model: Type[LanguageModel]) -> Type[LanguageModel]:
622
656
  """Combine two models into a single model (other_model takes precedence over self)."""
623
- import warnings
624
-
625
- warnings.warn(
657
+ print(
626
658
  f"""Warning: one model is replacing another. If you want to run both models, use a single `by` e.g.,
627
659
  by(m1, m2, m3) not by(m1).by(m2).by(m3)."""
628
660
  )
629
661
  return other_model or self
630
662
 
663
+ def rich_print(self):
664
+ """Display an object as a table."""
665
+ from rich.table import Table
666
+
667
+ table = Table(title="Language Model")
668
+ table.add_column("Attribute", style="bold")
669
+ table.add_column("Value")
670
+
671
+ to_display = self.__dict__.copy()
672
+ for attr_name, attr_value in to_display.items():
673
+ table.add_row(attr_name, repr(attr_value))
674
+
675
+ return table
676
+
631
677
  @classmethod
632
678
  def example(
633
679
  cls,
634
680
  test_model: bool = False,
635
681
  canned_response: str = "Hello world",
636
682
  throw_exception: bool = False,
637
- ) -> LanguageModel:
683
+ ):
638
684
  """Return a default instance of the class.
639
685
 
640
686
  >>> from edsl.language_models import LanguageModel
@@ -645,17 +691,11 @@ class LanguageModel(
645
691
  >>> q = QuestionFreeText(question_text = "What is your name?", question_name = 'example')
646
692
  >>> q.by(m).run(cache = False, disable_remote_cache = True, disable_remote_inference = True).select('example').first()
647
693
  'WOWZA!'
648
- >>> m = LanguageModel.example(test_model = True, canned_response = "WOWZA!", throw_exception = True)
649
- >>> r = q.by(m).run(cache = False, disable_remote_cache = True, disable_remote_inference = True, print_exceptions = True)
650
- Exception report saved to ...
651
- Also see: ...
652
694
  """
653
695
  from edsl import Model
654
696
 
655
697
  if test_model:
656
- m = Model(
657
- "test", canned_response=canned_response, throw_exception=throw_exception
658
- )
698
+ m = Model("test", canned_response=canned_response)
659
699
  return m
660
700
  else:
661
701
  return Model(skip_api_key_check=True)
@@ -1,4 +1,4 @@
1
- from typing import Optional, List
1
+ from typing import Optional
2
2
  from collections import UserList
3
3
  from edsl import Model
4
4
 
@@ -10,8 +10,6 @@ from edsl.utilities.utilities import dict_hash
10
10
 
11
11
 
12
12
  class ModelList(Base, UserList):
13
- __documentation__ = """https://docs.expectedparrot.com/en/latest/language_models.html#module-edsl.language_models.ModelList"""
14
-
15
13
  def __init__(self, data: Optional[list] = None):
16
14
  """Initialize the ScenarioList class.
17
15
 
@@ -39,9 +37,6 @@ class ModelList(Base, UserList):
39
37
  def __repr__(self):
40
38
  return f"ModelList({super().__repr__()})"
41
39
 
42
- def _summary(self):
43
- return {"EDSL Class": "ModelList", "Number of Models": len(self)}
44
-
45
40
  def __hash__(self):
46
41
  """Return a hash of the ModelList. This is used for comparison of ModelLists.
47
42
 
@@ -53,42 +48,6 @@ class ModelList(Base, UserList):
53
48
 
54
49
  return dict_hash(self.to_dict(sort=True, add_edsl_version=False))
55
50
 
56
- def to_scenario_list(self):
57
- from edsl import ScenarioList, Scenario
58
-
59
- sl = ScenarioList()
60
- for model in self:
61
- d = {"model": model.model}
62
- d.update(model.parameters)
63
- sl.append(Scenario(d))
64
- return sl
65
-
66
- def tree(self, node_list: Optional[List[str]] = None):
67
- return self.to_scenario_list().tree(node_list)
68
-
69
- def table(
70
- self,
71
- *fields,
72
- tablefmt: Optional[str] = None,
73
- pretty_labels: Optional[dict] = None,
74
- ):
75
- """
76
- >>> ModelList.example().table("model")
77
- model
78
- -------
79
- gpt-4o
80
- gpt-4o
81
- gpt-4o
82
- """
83
- return (
84
- self.to_scenario_list()
85
- .to_dataset()
86
- .table(*fields, tablefmt=tablefmt, pretty_labels=pretty_labels)
87
- )
88
-
89
- def to_list(self):
90
- return self.to_scenario_list().to_list()
91
-
92
51
  def to_dict(self, sort=False, add_edsl_version=True):
93
52
  if sort:
94
53
  model_list = sorted([model for model in self], key=lambda x: hash(x))
@@ -112,11 +71,6 @@ class ModelList(Base, UserList):
112
71
 
113
72
  return d
114
73
 
115
- def _repr_html_(self):
116
- """Return an HTML representation of the ModelList."""
117
- footer = f"<a href={self.__documentation__}>(docs)</a>"
118
- return str(self.summary(format="html")) + footer
119
-
120
74
  @classmethod
121
75
  def from_names(self, *args, **kwargs):
122
76
  """A a model list from a list of names"""
@@ -7,49 +7,6 @@ from edsl.config import CONFIG
7
7
  # else:
8
8
  # default_model = CONFIG.get("EDSL_DEFAULT_MODEL")
9
9
 
10
- from collections import UserList
11
-
12
-
13
- class PrettyList(UserList):
14
- def __init__(self, data=None, columns=None):
15
- super().__init__(data)
16
- self.columns = columns
17
-
18
- def _repr_html_(self):
19
- if isinstance(self[0], list) or isinstance(self[0], tuple):
20
- num_cols = len(self[0])
21
- else:
22
- num_cols = 1
23
-
24
- if self.columns:
25
- columns = self.columns
26
- else:
27
- columns = list(range(num_cols))
28
-
29
- if num_cols > 1:
30
- return (
31
- "<pre><table>"
32
- + "".join(["<th>" + str(column) + "</th>" for column in columns])
33
- + "".join(
34
- [
35
- "<tr>"
36
- + "".join(["<td>" + str(x) + "</td>" for x in row])
37
- + "</tr>"
38
- for row in self
39
- ]
40
- )
41
- + "</table></pre>"
42
- )
43
- else:
44
- return (
45
- "<pre><table>"
46
- + "".join(["<th>" + str(index) + "</th>" for index in columns])
47
- + "".join(
48
- ["<tr>" + "<td>" + str(row) + "</td>" + "</tr>" for row in self]
49
- )
50
- + "</table></pre>"
51
- )
52
-
53
10
 
54
11
  def get_model_class(model_name, registry=None):
55
12
  from edsl.inference_services.registry import default
@@ -125,27 +82,17 @@ class Model(metaclass=Meta):
125
82
 
126
83
  if search_term is None:
127
84
  if name_only:
128
- return PrettyList(
129
- [m[0] for m in full_list],
130
- columns=["Model Name", "Service Name", "Code"],
131
- )
85
+ return [m[0] for m in full_list]
132
86
  else:
133
- return PrettyList(
134
- full_list, columns=["Model Name", "Service Name", "Code"]
135
- )
87
+ return full_list
136
88
  else:
137
89
  filtered_results = [
138
90
  m for m in full_list if search_term in m[0] or search_term in m[1]
139
91
  ]
140
92
  if name_only:
141
- return PrettyList(
142
- [m[0] for m in filtered_results],
143
- columns=["Model Name", "Service Name", "Code"],
144
- )
93
+ return [m[0] for m in filtered_results]
145
94
  else:
146
- return PrettyList(
147
- filtered_results, columns=["Model Name", "Service Name", "Code"]
148
- )
95
+ return filtered_results
149
96
 
150
97
  @classmethod
151
98
  def check_models(cls, verbose=False):
edsl/prompts/Prompt.py CHANGED
@@ -29,14 +29,9 @@ class Prompt(PersistenceMixin, RichPrintingMixin):
29
29
 
30
30
  def _repr_html_(self):
31
31
  """Return an HTML representation of the Prompt."""
32
- # from edsl.utilities.utilities import data_to_html
33
- # return data_to_html(self.to_dict())
34
- d = self.to_dict()
35
- data = [[k, v] for k, v in d.items()]
36
- from tabulate import tabulate
37
-
38
- table = str(tabulate(data, headers=["keys", "values"], tablefmt="html"))
39
- return f"<pre>{table}</pre>"
32
+ from edsl.utilities.utilities import data_to_html
33
+
34
+ return data_to_html(self.to_dict())
40
35
 
41
36
  def __len__(self):
42
37
  """Return the length of the prompt text."""
@@ -82,8 +82,7 @@ class QuestionBase(
82
82
  if not hasattr(self, "_fake_data_factory"):
83
83
  from polyfactory.factories.pydantic_factory import ModelFactory
84
84
 
85
- class FakeData(ModelFactory[self.response_model]):
86
- ...
85
+ class FakeData(ModelFactory[self.response_model]): ...
87
86
 
88
87
  self._fake_data_factory = FakeData
89
88
  return self._fake_data_factory
@@ -264,9 +263,12 @@ class QuestionBase(
264
263
  >>> m.execute_model_call("", "")
265
264
  {'message': [{'text': "Yo, what's up?"}], 'usage': {'prompt_tokens': 1, 'completion_tokens': 1}}
266
265
  >>> Q.run_example(show_answer = True, model = m, disable_remote_cache = True, disable_remote_inference = True)
267
- answer.how_are_you
268
- --------------------
269
- Yo, what's up?
266
+ ┏━━━━━━━━━━━━━━━━┓
267
+ ┃ answer ┃
268
+ .how_are_you ┃
269
+ ┡━━━━━━━━━━━━━━━━┩
270
+ │ Yo, what's up? │
271
+ └────────────────┘
270
272
  """
271
273
  if model is None:
272
274
  from edsl import Model
@@ -282,7 +284,7 @@ class QuestionBase(
282
284
  )
283
285
  )
284
286
  if show_answer:
285
- return results.select("answer.*").print()
287
+ results.select("answer.*").print()
286
288
  else:
287
289
  return results
288
290
 
@@ -360,22 +362,16 @@ class QuestionBase(
360
362
 
361
363
  # region: Magic methods
362
364
  def _repr_html_(self):
363
- # from edsl.utilities.utilities import data_to_html
365
+ from edsl.utilities.utilities import data_to_html
364
366
 
365
- data = self.to_dict(add_edsl_version=False)
366
- # keys = list(data.keys())
367
- # values = list(data.values())
368
- from tabulate import tabulate
369
-
370
- return tabulate(data.items(), headers=["keys", "values"], tablefmt="html")
371
-
372
- # try:
373
- # _ = data.pop("edsl_version")
374
- # _ = data.pop("edsl_class_name")
375
- # except KeyError:
376
- # print("Serialized question lacks edsl version, but is should have it.")
367
+ data = self.to_dict()
368
+ try:
369
+ _ = data.pop("edsl_version")
370
+ _ = data.pop("edsl_class_name")
371
+ except KeyError:
372
+ print("Serialized question lacks edsl version, but is should have it.")
377
373
 
378
- # return data_to_html(data)
374
+ return data_to_html(data)
379
375
 
380
376
  def __getitem__(self, key: str) -> Any:
381
377
  """Get an attribute of the question so it can be treated like a dictionary.
@@ -1,7 +1,4 @@
1
1
  from __future__ import annotations
2
- import json
3
- import re
4
-
5
2
  from typing import Any, Optional, Dict
6
3
  from edsl.questions.QuestionBase import QuestionBase
7
4
  from edsl.questions.descriptors import AnswerTemplateDescriptor
@@ -14,6 +11,9 @@ from edsl.questions.decorators import inject_exception
14
11
  from typing import Dict, Any
15
12
  from pydantic import create_model, Field
16
13
 
14
+ import json
15
+ import re
16
+
17
17
 
18
18
  def extract_json(text, expected_keys, verbose=False):
19
19
  # Escape special regex characters in keys
@@ -112,6 +112,7 @@ class QuestionExtract(QuestionBase):
112
112
 
113
113
  :param question_name: The name of the question.
114
114
  :param question_text: The text of the question.
115
+ :param question_options: The options the respondent should select from.
115
116
  :param answer_template: The template for the answer.
116
117
  """
117
118
  self.question_name = question_name
@@ -90,22 +90,6 @@ class Question(metaclass=Meta):
90
90
  coop = Coop()
91
91
  return coop.patch(uuid, url, description, value, visibility)
92
92
 
93
- @classmethod
94
- def list_question_types(cls):
95
- """Return a list of available question types.
96
-
97
- >>> from edsl import Question
98
- >>> Question.list_question_types()
99
- ['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
100
- """
101
- return [
102
- q
103
- for q in sorted(
104
- list(RegisterQuestionsMeta.question_types_to_classes().keys())
105
- )
106
- if q not in ["budget"]
107
- ]
108
-
109
93
  @classmethod
110
94
  def available(cls, show_class_names: bool = False) -> Union[list, dict]:
111
95
  """Return a list of available question types.
@@ -114,32 +98,18 @@ class Question(metaclass=Meta):
114
98
 
115
99
  Example usage:
116
100
 
101
+ >>> from edsl import Question
102
+ >>> Question.available()
103
+ ['checkbox', 'extract', 'free_text', 'functional', 'likert_five', 'linear_scale', 'list', 'multiple_choice', 'numerical', 'rank', 'top_k', 'yes_no']
117
104
  """
118
- from edsl.results.Dataset import Dataset
119
-
120
105
  exclude = ["budget"]
121
106
  if show_class_names:
122
107
  return RegisterQuestionsMeta.question_types_to_classes()
123
108
  else:
124
- question_list = [
125
- q
126
- for q in sorted(
127
- set(RegisterQuestionsMeta.question_types_to_classes().keys())
128
- )
129
- if q not in exclude
130
- ]
131
- d = RegisterQuestionsMeta.question_types_to_classes()
132
- question_classes = [d[q] for q in question_list]
133
- example_questions = [repr(q.example()) for q in question_classes]
134
-
135
- return Dataset(
136
- [
137
- {"question_type": [q for q in question_list]},
138
- {"question_class": [q.__name__ for q in question_classes]},
139
- {"example_question": example_questions},
140
- ],
141
- print_parameters={"containerHeight": "auto"},
109
+ question_list = sorted(
110
+ set(RegisterQuestionsMeta.question_types_to_classes().keys())
142
111
  )
112
+ return [q for q in question_list if q not in exclude]
143
113
 
144
114
 
145
115
  def get_question_class(question_type):