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
@@ -144,216 +144,216 @@ class DatasetExportMixin:
144
144
  for value in list_of_values:
145
145
  print(f"{key}: {value}")
146
146
 
147
- # def print(
148
- # self,
149
- # pretty_labels: Optional[dict] = None,
150
- # filename: Optional[str] = None,
151
- # format: Optional[Literal["rich", "html", "markdown", "latex"]] = None,
152
- # interactive: bool = False,
153
- # split_at_dot: bool = True,
154
- # max_rows=None,
155
- # tee=False,
156
- # iframe=False,
157
- # iframe_height: int = 200,
158
- # iframe_width: int = 600,
159
- # web=False,
160
- # return_string: bool = False,
161
- # ) -> Union[None, str, "Results"]:
162
- # """Print the results in a pretty format.
163
-
164
- # :param pretty_labels: A dictionary of pretty labels for the columns.
165
- # :param filename: The filename to save the results to.
166
- # :param format: The format to print the results in. Options are 'rich', 'html', 'markdown', or 'latex'.
167
- # :param interactive: Whether to print the results interactively in a Jupyter notebook.
168
- # :param split_at_dot: Whether to split the column names at the last dot w/ a newline.
169
- # :param max_rows: The maximum number of rows to print.
170
- # :param tee: Whether to return the dataset.
171
- # :param iframe: Whether to display the table in an iframe.
172
- # :param iframe_height: The height of the iframe.
173
- # :param iframe_width: The width of the iframe.
174
- # :param web: Whether to display the table in a web browser.
175
- # :param return_string: Whether to return the output as a string instead of printing.
176
-
177
- # :return: None if tee is False and return_string is False, the dataset if tee is True, or a string if return_string is True.
178
-
179
- # Example: Print in rich format at the terminal
180
-
181
- # >>> from edsl.results import Results
182
- # >>> r = Results.example()
183
- # >>> r.select('how_feeling').print(format = "rich")
184
- # ┏━━━━━━━━━━━━━━┓
185
- # ┃ answer ┃
186
- # ┃ .how_feeling ┃
187
- # ┡━━━━━━━━━━━━━━┩
188
- # │ OK │
189
- # ├──────────────┤
190
- # │ Great │
191
- # ├──────────────┤
192
- # │ Terrible │
193
- # ├──────────────┤
194
- # │ OK │
195
- # └──────────────┘
196
-
197
- # >>> r = Results.example()
198
- # >>> r2 = r.select("how_feeling").print(format = "rich", tee = True, max_rows = 2)
199
- # ┏━━━━━━━━━━━━━━┓
200
- # ┃ answer ┃
201
- # ┃ .how_feeling ┃
202
- # ┡━━━━━━━━━━━━━━┩
203
- # │ OK │
204
- # ├──────────────┤
205
- # │ Great │
206
- # └──────────────┘
207
- # >>> r2
208
- # Dataset([{'answer.how_feeling': ['OK', 'Great', 'Terrible', 'OK']}])
209
-
210
- # >>> r.select('how_feeling').print(format = "rich", max_rows = 2)
211
- # ┏━━━━━━━━━━━━━━┓
212
- # ┃ answer ┃
213
- # ┃ .how_feeling ┃
214
- # ┡━━━━━━━━━━━━━━┩
215
- # │ OK │
216
- # ├──────────────┤
217
- # │ Great │
218
- # └──────────────┘
219
-
220
- # >>> r.select('how_feeling').print(format = "rich", split_at_dot = False)
221
- # ┏━━━━━━━━━━━━━━━━━━━━┓
222
- # ┃ answer.how_feeling ┃
223
- # ┡━━━━━━━━━━━━━━━━━━━━┩
224
- # │ OK │
225
- # ├────────────────────┤
226
- # │ Great │
227
- # ├────────────────────┤
228
- # │ Terrible │
229
- # ├────────────────────┤
230
- # │ OK │
231
- # └────────────────────┘
232
-
233
- # Example: using the pretty_labels parameter
234
-
235
- # >>> r.select('how_feeling').print(format="rich", pretty_labels = {'answer.how_feeling': "How are you feeling"})
236
- # ┏━━━━━━━━━━━━━━━━━━━━━┓
237
- # ┃ How are you feeling ┃
238
- # ┡━━━━━━━━━━━━━━━━━━━━━┩
239
- # │ OK │
240
- # ├─────────────────────┤
241
- # │ Great │
242
- # ├─────────────────────┤
243
- # │ Terrible │
244
- # ├─────────────────────┤
245
- # │ OK │
246
- # └─────────────────────┘
247
-
248
- # Example: printing in markdown format
249
-
250
- # >>> r.select('how_feeling').print(format='markdown')
251
- # | answer.how_feeling |
252
- # |--|
253
- # | OK |
254
- # | Great |
255
- # | Terrible |
256
- # | OK |
257
- # ...
258
-
259
- # >>> r.select('how_feeling').print(format='latex')
260
- # \\begin{tabular}{l}
261
- # ...
262
- # \\end{tabular}
263
- # <BLANKLINE>
264
- # """
265
- # from IPython.display import HTML, display
266
- # from edsl.utilities.utilities import is_notebook
267
- # import io
268
- # import sys
269
-
270
- # def _determine_format(format):
271
- # if format is None:
272
- # if is_notebook():
273
- # format = "html"
274
- # else:
275
- # format = "rich"
276
- # if format not in ["rich", "html", "markdown", "latex"]:
277
- # raise ValueError(
278
- # "format must be one of 'rich', 'html', 'markdown', or 'latex'."
279
- # )
280
-
281
- # return format
282
-
283
- # format = _determine_format(format)
284
-
285
- # if pretty_labels is None:
286
- # pretty_labels = {}
287
-
288
- # if pretty_labels != {}: # only split at dot if there are no pretty labels
289
- # split_at_dot = False
290
-
291
- # def _create_data():
292
- # for index, entry in enumerate(self):
293
- # key, list_of_values = list(entry.items())[0]
294
- # yield {pretty_labels.get(key, key): list_of_values[:max_rows]}
295
-
296
- # new_data = list(_create_data())
297
-
298
- # # Capture output if return_string is True
299
- # if return_string:
300
- # old_stdout = sys.stdout
301
- # sys.stdout = io.StringIO()
302
-
303
- # output = None
304
-
305
- # if format == "rich":
306
- # from edsl.utilities.interface import print_dataset_with_rich
307
-
308
- # output = print_dataset_with_rich(
309
- # new_data, filename=filename, split_at_dot=split_at_dot
310
- # )
311
- # elif format == "markdown":
312
- # from edsl.utilities.interface import print_list_of_dicts_as_markdown_table
313
-
314
- # output = print_list_of_dicts_as_markdown_table(new_data, filename=filename)
315
- # elif format == "latex":
316
- # df = self.to_pandas()
317
- # df.columns = [col.replace("_", " ") for col in df.columns]
318
- # latex_string = df.to_latex(index=False)
319
-
320
- # if filename is not None:
321
- # with open(filename, "w") as f:
322
- # f.write(latex_string)
323
- # else:
324
- # print(latex_string)
325
- # output = latex_string
326
- # elif format == "html":
327
- # from edsl.utilities.interface import print_list_of_dicts_as_html_table
328
-
329
- # html_source = print_list_of_dicts_as_html_table(
330
- # new_data, interactive=interactive
331
- # )
332
-
333
- # if iframe:
334
- # iframe = f""""
335
- # <iframe srcdoc="{ html.escape(html_source) }" style="width: {iframe_width}px; height: {iframe_height}px;"></iframe>
336
- # """
337
- # display(HTML(iframe))
338
- # elif is_notebook():
339
- # display(HTML(html_source))
340
- # else:
341
- # from edsl.utilities.interface import view_html
342
-
343
- # view_html(html_source)
344
-
345
- # output = html_source
346
-
347
- # # Restore stdout and get captured output if return_string is True
348
- # if return_string:
349
- # captured_output = sys.stdout.getvalue()
350
- # sys.stdout = old_stdout
351
- # return captured_output or output
352
-
353
- # if tee:
354
- # return self
355
-
356
- # return None
147
+ def print(
148
+ self,
149
+ pretty_labels: Optional[dict] = None,
150
+ filename: Optional[str] = None,
151
+ format: Optional[Literal["rich", "html", "markdown", "latex"]] = None,
152
+ interactive: bool = False,
153
+ split_at_dot: bool = True,
154
+ max_rows=None,
155
+ tee=False,
156
+ iframe=False,
157
+ iframe_height: int = 200,
158
+ iframe_width: int = 600,
159
+ web=False,
160
+ return_string: bool = False,
161
+ ) -> Union[None, str, "Results"]:
162
+ """Print the results in a pretty format.
163
+
164
+ :param pretty_labels: A dictionary of pretty labels for the columns.
165
+ :param filename: The filename to save the results to.
166
+ :param format: The format to print the results in. Options are 'rich', 'html', 'markdown', or 'latex'.
167
+ :param interactive: Whether to print the results interactively in a Jupyter notebook.
168
+ :param split_at_dot: Whether to split the column names at the last dot w/ a newline.
169
+ :param max_rows: The maximum number of rows to print.
170
+ :param tee: Whether to return the dataset.
171
+ :param iframe: Whether to display the table in an iframe.
172
+ :param iframe_height: The height of the iframe.
173
+ :param iframe_width: The width of the iframe.
174
+ :param web: Whether to display the table in a web browser.
175
+ :param return_string: Whether to return the output as a string instead of printing.
176
+
177
+ :return: None if tee is False and return_string is False, the dataset if tee is True, or a string if return_string is True.
178
+
179
+ Example: Print in rich format at the terminal
180
+
181
+ >>> from edsl.results import Results
182
+ >>> r = Results.example()
183
+ >>> r.select('how_feeling').print(format = "rich")
184
+ ┏━━━━━━━━━━━━━━┓
185
+ ┃ answer ┃
186
+ ┃ .how_feeling ┃
187
+ ┡━━━━━━━━━━━━━━┩
188
+ │ OK │
189
+ ├──────────────┤
190
+ │ Great │
191
+ ├──────────────┤
192
+ │ Terrible │
193
+ ├──────────────┤
194
+ │ OK │
195
+ └──────────────┘
196
+
197
+ >>> r = Results.example()
198
+ >>> r2 = r.select("how_feeling").print(format = "rich", tee = True, max_rows = 2)
199
+ ┏━━━━━━━━━━━━━━┓
200
+ ┃ answer ┃
201
+ ┃ .how_feeling ┃
202
+ ┡━━━━━━━━━━━━━━┩
203
+ │ OK │
204
+ ├──────────────┤
205
+ │ Great │
206
+ └──────────────┘
207
+ >>> r2
208
+ Dataset([{'answer.how_feeling': ['OK', 'Great', 'Terrible', 'OK']}])
209
+
210
+ >>> r.select('how_feeling').print(format = "rich", max_rows = 2)
211
+ ┏━━━━━━━━━━━━━━┓
212
+ ┃ answer ┃
213
+ ┃ .how_feeling ┃
214
+ ┡━━━━━━━━━━━━━━┩
215
+ │ OK │
216
+ ├──────────────┤
217
+ │ Great │
218
+ └──────────────┘
219
+
220
+ >>> r.select('how_feeling').print(format = "rich", split_at_dot = False)
221
+ ┏━━━━━━━━━━━━━━━━━━━━┓
222
+ ┃ answer.how_feeling ┃
223
+ ┡━━━━━━━━━━━━━━━━━━━━┩
224
+ │ OK │
225
+ ├────────────────────┤
226
+ │ Great │
227
+ ├────────────────────┤
228
+ │ Terrible │
229
+ ├────────────────────┤
230
+ │ OK │
231
+ └────────────────────┘
232
+
233
+ Example: using the pretty_labels parameter
234
+
235
+ >>> r.select('how_feeling').print(format="rich", pretty_labels = {'answer.how_feeling': "How are you feeling"})
236
+ ┏━━━━━━━━━━━━━━━━━━━━━┓
237
+ ┃ How are you feeling ┃
238
+ ┡━━━━━━━━━━━━━━━━━━━━━┩
239
+ │ OK │
240
+ ├─────────────────────┤
241
+ │ Great │
242
+ ├─────────────────────┤
243
+ │ Terrible │
244
+ ├─────────────────────┤
245
+ │ OK │
246
+ └─────────────────────┘
247
+
248
+ Example: printing in markdown format
249
+
250
+ >>> r.select('how_feeling').print(format='markdown')
251
+ | answer.how_feeling |
252
+ |--|
253
+ | OK |
254
+ | Great |
255
+ | Terrible |
256
+ | OK |
257
+ ...
258
+
259
+ >>> r.select('how_feeling').print(format='latex')
260
+ \\begin{tabular}{l}
261
+ ...
262
+ \\end{tabular}
263
+ <BLANKLINE>
264
+ """
265
+ from IPython.display import HTML, display
266
+ from edsl.utilities.utilities import is_notebook
267
+ import io
268
+ import sys
269
+
270
+ def _determine_format(format):
271
+ if format is None:
272
+ if is_notebook():
273
+ format = "html"
274
+ else:
275
+ format = "rich"
276
+ if format not in ["rich", "html", "markdown", "latex"]:
277
+ raise ValueError(
278
+ "format must be one of 'rich', 'html', 'markdown', or 'latex'."
279
+ )
280
+
281
+ return format
282
+
283
+ format = _determine_format(format)
284
+
285
+ if pretty_labels is None:
286
+ pretty_labels = {}
287
+
288
+ if pretty_labels != {}: # only split at dot if there are no pretty labels
289
+ split_at_dot = False
290
+
291
+ def _create_data():
292
+ for index, entry in enumerate(self):
293
+ key, list_of_values = list(entry.items())[0]
294
+ yield {pretty_labels.get(key, key): list_of_values[:max_rows]}
295
+
296
+ new_data = list(_create_data())
297
+
298
+ # Capture output if return_string is True
299
+ if return_string:
300
+ old_stdout = sys.stdout
301
+ sys.stdout = io.StringIO()
302
+
303
+ output = None
304
+
305
+ if format == "rich":
306
+ from edsl.utilities.interface import print_dataset_with_rich
307
+
308
+ output = print_dataset_with_rich(
309
+ new_data, filename=filename, split_at_dot=split_at_dot
310
+ )
311
+ elif format == "markdown":
312
+ from edsl.utilities.interface import print_list_of_dicts_as_markdown_table
313
+
314
+ output = print_list_of_dicts_as_markdown_table(new_data, filename=filename)
315
+ elif format == "latex":
316
+ df = self.to_pandas()
317
+ df.columns = [col.replace("_", " ") for col in df.columns]
318
+ latex_string = df.to_latex(index=False)
319
+
320
+ if filename is not None:
321
+ with open(filename, "w") as f:
322
+ f.write(latex_string)
323
+ else:
324
+ print(latex_string)
325
+ output = latex_string
326
+ elif format == "html":
327
+ from edsl.utilities.interface import print_list_of_dicts_as_html_table
328
+
329
+ html_source = print_list_of_dicts_as_html_table(
330
+ new_data, interactive=interactive
331
+ )
332
+
333
+ if iframe:
334
+ iframe = f""""
335
+ <iframe srcdoc="{ html.escape(html_source) }" style="width: {iframe_width}px; height: {iframe_height}px;"></iframe>
336
+ """
337
+ display(HTML(iframe))
338
+ elif is_notebook():
339
+ display(HTML(html_source))
340
+ else:
341
+ from edsl.utilities.interface import view_html
342
+
343
+ view_html(html_source)
344
+
345
+ output = html_source
346
+
347
+ # Restore stdout and get captured output if return_string is True
348
+ if return_string:
349
+ captured_output = sys.stdout.getvalue()
350
+ sys.stdout = old_stdout
351
+ return captured_output or output
352
+
353
+ if tee:
354
+ return self
355
+
356
+ return None
357
357
 
358
358
  def to_csv(
359
359
  self,
@@ -405,7 +405,6 @@ class DatasetExportMixin:
405
405
  writer = csv.writer(f)
406
406
  writer.writerow(header)
407
407
  writer.writerows(rows)
408
- # print(f"Saved to {filename}")
409
408
  else:
410
409
  output = io.StringIO()
411
410
  writer = csv.writer(output)
@@ -516,14 +515,7 @@ class DatasetExportMixin:
516
515
  from edsl import AgentList, Agent
517
516
 
518
517
  list_of_dicts = self.to_dicts(remove_prefix=remove_prefix)
519
- agents = []
520
- for d in list_of_dicts:
521
- if "name" in d:
522
- d["agent_name"] = d.pop("name")
523
- agents.append(Agent(d, name=d["agent_name"]))
524
- else:
525
- agents.append(Agent(d))
526
- return AgentList(agents)
518
+ return AgentList([Agent(d) for d in list_of_dicts])
527
519
 
528
520
  def to_dicts(self, remove_prefix: bool = True) -> list[dict]:
529
521
  """Convert the results to a list of dictionaries.
@@ -659,7 +651,9 @@ class DatasetExportMixin:
659
651
  >>> r.select('how_feeling').tally('answer.how_feeling', output = "dict")
660
652
  {'OK': 2, 'Great': 1, 'Terrible': 1}
661
653
  >>> r.select('how_feeling').tally('answer.how_feeling', output = "Dataset")
662
- Dataset([{'answer.how_feeling': ['OK', 'Great', 'Terrible']}, {'count': [2, 1, 1]}])
654
+ Dataset([{'value': ['OK', 'Great', 'Terrible']}, {'count': [2, 1, 1]}])
655
+ >>> r.select('how_feeling', 'period').tally('how_feeling', 'period', output = "dict")
656
+ {('OK', 'morning'): 1, ('Great', 'afternoon'): 1, ('Terrible', 'morning'): 1, ('OK', 'afternoon'): 1}
663
657
  """
664
658
  from collections import Counter
665
659
 
@@ -670,6 +664,8 @@ class DatasetExportMixin:
670
664
  column.split(".")[-1] for column in self.relevant_columns()
671
665
  ]
672
666
 
667
+ # breakpoint()
668
+
673
669
  if not all(
674
670
  f in self.relevant_columns() or f in relevant_columns_without_prefix
675
671
  for f in fields
@@ -707,22 +703,12 @@ class DatasetExportMixin:
707
703
  )
708
704
  return sorted_tally
709
705
  elif output == "Dataset":
710
- dataset = Dataset(
706
+ return Dataset(
711
707
  [
712
708
  {"value": list(sorted_tally.keys())},
713
709
  {"count": list(sorted_tally.values())},
714
710
  ]
715
711
  )
716
- # return dataset
717
- sl = dataset.to_scenario_list().unpack(
718
- "value",
719
- new_names=[fields] if isinstance(fields, str) else fields,
720
- keep_original=False,
721
- )
722
- keys = list(sl[0].keys())
723
- keys.remove("count")
724
- keys.append("count")
725
- return sl.reorder_keys(keys).to_dataset()
726
712
 
727
713
 
728
714
  if __name__ == "__main__":