edsl 0.1.39__py3-none-any.whl → 0.1.39.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 (85) hide show
  1. edsl/Base.py +0 -28
  2. edsl/__init__.py +1 -1
  3. edsl/__version__.py +1 -1
  4. edsl/agents/Agent.py +17 -9
  5. edsl/agents/Invigilator.py +14 -13
  6. edsl/agents/InvigilatorBase.py +1 -4
  7. edsl/agents/PromptConstructor.py +22 -42
  8. edsl/agents/QuestionInstructionPromptBuilder.py +1 -1
  9. edsl/auto/AutoStudy.py +5 -18
  10. edsl/auto/StageBase.py +40 -53
  11. edsl/auto/StageQuestions.py +1 -2
  12. edsl/auto/utilities.py +6 -0
  13. edsl/coop/coop.py +5 -21
  14. edsl/data/Cache.py +18 -29
  15. edsl/data/CacheHandler.py +2 -0
  16. edsl/data/RemoteCacheSync.py +46 -154
  17. edsl/enums.py +0 -7
  18. edsl/inference_services/AnthropicService.py +16 -38
  19. edsl/inference_services/AvailableModelFetcher.py +1 -7
  20. edsl/inference_services/GoogleService.py +1 -5
  21. edsl/inference_services/InferenceServicesCollection.py +2 -18
  22. edsl/inference_services/OpenAIService.py +31 -46
  23. edsl/inference_services/TestService.py +3 -1
  24. edsl/inference_services/TogetherAIService.py +3 -5
  25. edsl/inference_services/data_structures.py +2 -74
  26. edsl/jobs/AnswerQuestionFunctionConstructor.py +113 -148
  27. edsl/jobs/FetchInvigilator.py +3 -10
  28. edsl/jobs/InterviewsConstructor.py +4 -6
  29. edsl/jobs/Jobs.py +233 -299
  30. edsl/jobs/JobsChecks.py +2 -2
  31. edsl/jobs/JobsPrompts.py +1 -1
  32. edsl/jobs/JobsRemoteInferenceHandler.py +136 -160
  33. edsl/jobs/interviews/Interview.py +42 -80
  34. edsl/jobs/runners/JobsRunnerAsyncio.py +358 -88
  35. edsl/jobs/runners/JobsRunnerStatus.py +165 -133
  36. edsl/jobs/tasks/TaskHistory.py +3 -24
  37. edsl/language_models/LanguageModel.py +4 -59
  38. edsl/language_models/ModelList.py +8 -19
  39. edsl/language_models/__init__.py +1 -1
  40. edsl/language_models/registry.py +180 -0
  41. edsl/language_models/repair.py +1 -1
  42. edsl/questions/QuestionBase.py +26 -35
  43. edsl/questions/{question_base_gen_mixin.py → QuestionBaseGenMixin.py} +49 -52
  44. edsl/questions/QuestionBasePromptsMixin.py +1 -1
  45. edsl/questions/QuestionBudget.py +1 -1
  46. edsl/questions/QuestionCheckBox.py +2 -2
  47. edsl/questions/QuestionExtract.py +7 -5
  48. edsl/questions/QuestionFreeText.py +1 -1
  49. edsl/questions/QuestionList.py +15 -9
  50. edsl/questions/QuestionMatrix.py +1 -1
  51. edsl/questions/QuestionMultipleChoice.py +1 -1
  52. edsl/questions/QuestionNumerical.py +1 -1
  53. edsl/questions/QuestionRank.py +1 -1
  54. edsl/questions/{response_validator_abc.py → ResponseValidatorABC.py} +18 -6
  55. edsl/questions/{response_validator_factory.py → ResponseValidatorFactory.py} +1 -7
  56. edsl/questions/SimpleAskMixin.py +1 -1
  57. edsl/questions/__init__.py +1 -1
  58. edsl/results/DatasetExportMixin.py +119 -60
  59. edsl/results/Result.py +3 -109
  60. edsl/results/Results.py +39 -50
  61. edsl/scenarios/FileStore.py +0 -32
  62. edsl/scenarios/ScenarioList.py +7 -35
  63. edsl/scenarios/handlers/csv.py +0 -11
  64. edsl/surveys/Survey.py +20 -71
  65. {edsl-0.1.39.dist-info → edsl-0.1.39.dev2.dist-info}/METADATA +1 -1
  66. {edsl-0.1.39.dist-info → edsl-0.1.39.dev2.dist-info}/RECORD +78 -84
  67. {edsl-0.1.39.dist-info → edsl-0.1.39.dev2.dist-info}/WHEEL +1 -1
  68. edsl/jobs/async_interview_runner.py +0 -138
  69. edsl/jobs/check_survey_scenario_compatibility.py +0 -85
  70. edsl/jobs/data_structures.py +0 -120
  71. edsl/jobs/results_exceptions_handler.py +0 -98
  72. edsl/language_models/model.py +0 -256
  73. edsl/questions/data_structures.py +0 -20
  74. edsl/results/file_exports.py +0 -252
  75. /edsl/agents/{question_option_processor.py → QuestionOptionProcessor.py} +0 -0
  76. /edsl/questions/{answer_validator_mixin.py → AnswerValidatorMixin.py} +0 -0
  77. /edsl/questions/{loop_processor.py → LoopProcessor.py} +0 -0
  78. /edsl/questions/{register_questions_meta.py → RegisterQuestionsMeta.py} +0 -0
  79. /edsl/results/{results_fetch_mixin.py → ResultsFetchMixin.py} +0 -0
  80. /edsl/results/{results_tools_mixin.py → ResultsToolsMixin.py} +0 -0
  81. /edsl/results/{results_selector.py → Selector.py} +0 -0
  82. /edsl/scenarios/{directory_scanner.py → DirectoryScanner.py} +0 -0
  83. /edsl/scenarios/{scenario_join.py → ScenarioJoin.py} +0 -0
  84. /edsl/scenarios/{scenario_selector.py → ScenarioSelector.py} +0 -0
  85. {edsl-0.1.39.dist-info → edsl-0.1.39.dev2.dist-info}/LICENSE +0 -0
@@ -1,252 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- import io
3
- import csv
4
- import base64
5
- from typing import Optional, Union, Tuple, List, Any, Dict
6
- from openpyxl import Workbook
7
-
8
- from edsl.scenarios.FileStore import FileStore
9
-
10
-
11
- class FileExport(ABC):
12
- def __init__(
13
- self,
14
- data: Any,
15
- filename: Optional[str] = None,
16
- remove_prefix: bool = False,
17
- pretty_labels: Optional[Dict[str, str]] = None,
18
- ):
19
- self.data = data
20
- self.filename = filename # or self._get_default_filename()
21
- self.remove_prefix = remove_prefix
22
- self.pretty_labels = pretty_labels
23
-
24
- @property
25
- def mime_type(self) -> str:
26
- """Return the MIME type for this export format."""
27
- return self.__class__.mime_type
28
-
29
- @property
30
- def suffix(self) -> str:
31
- """Return the file suffix for this format."""
32
- return self.__class__.suffix
33
-
34
- @property
35
- def is_binary(self) -> bool:
36
- """Whether the format is binary or text-based."""
37
- return self.__class__.is_binary
38
-
39
- def _get_default_filename(self) -> str:
40
- """Generate default filename for this format."""
41
- return f"results.{self.suffix}"
42
-
43
- def _create_filestore(self, data: Union[str, bytes]) -> "FileStore":
44
- """Create a FileStore instance with encoded data."""
45
- if isinstance(data, str):
46
- base64_string = base64.b64encode(data.encode()).decode()
47
- else:
48
- base64_string = base64.b64encode(data).decode()
49
-
50
- from edsl.scenarios.FileStore import FileStore
51
-
52
- path = self.filename or self._get_default_filename()
53
-
54
- fs = FileStore(
55
- path=path,
56
- mime_type=self.mime_type,
57
- binary=self.is_binary,
58
- suffix=self.suffix,
59
- base64_string=base64_string,
60
- )
61
-
62
- if self.filename is not None:
63
- fs.write(self.filename)
64
- return None
65
- return fs
66
-
67
- @abstractmethod
68
- def format_data(self) -> Union[str, bytes]:
69
- """Convert the input data to the target format."""
70
- pass
71
-
72
- def export(self) -> Optional["FileStore"]:
73
- """Export the data to a FileStore instance."""
74
- formatted_data = self.format_data()
75
- return self._create_filestore(formatted_data)
76
-
77
-
78
- class JSONLExport(FileExport):
79
- mime_type = "application/jsonl"
80
- suffix = "jsonl"
81
- is_binary = False
82
-
83
- def format_data(self) -> str:
84
- output = io.StringIO()
85
- for entry in self.data:
86
- key, values = list(entry.items())[0]
87
- output.write(f'{{"{key}": {values}}}\n')
88
- return output.getvalue()
89
-
90
-
91
- class TabularExport(FileExport, ABC):
92
- """Base class for exports that use tabular data."""
93
-
94
- def __init__(self, *args, **kwargs):
95
- super().__init__(*args, **kwargs)
96
- self.header, self.rows = self.data._get_tabular_data(
97
- remove_prefix=self.remove_prefix, pretty_labels=self.pretty_labels
98
- )
99
-
100
-
101
- class CSVExport(TabularExport):
102
- mime_type = "text/csv"
103
- suffix = "csv"
104
- is_binary = False
105
-
106
- def format_data(self) -> str:
107
- output = io.StringIO()
108
- writer = csv.writer(output)
109
- writer.writerow(self.header)
110
- writer.writerows(self.rows)
111
- return output.getvalue()
112
-
113
-
114
- class ExcelExport(TabularExport):
115
- mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
116
- suffix = "xlsx"
117
- is_binary = True
118
-
119
- def __init__(self, *args, sheet_name: Optional[str] = None, **kwargs):
120
- super().__init__(*args, **kwargs)
121
- self.sheet_name = sheet_name or "Results"
122
-
123
- def format_data(self) -> bytes:
124
- wb = Workbook()
125
- ws = wb.active
126
- ws.title = self.sheet_name
127
-
128
- # Write header
129
- for col, value in enumerate(self.header, 1):
130
- ws.cell(row=1, column=col, value=value)
131
-
132
- # Write data rows
133
- for row_idx, row_data in enumerate(self.rows, 2):
134
- for col, value in enumerate(row_data, 1):
135
- ws.cell(row=row_idx, column=col, value=value)
136
-
137
- # Save to bytes buffer
138
- buffer = io.BytesIO()
139
- wb.save(buffer)
140
- buffer.seek(0)
141
- return buffer.getvalue()
142
-
143
-
144
- import sqlite3
145
- from typing import Any
146
-
147
-
148
- class SQLiteExport(TabularExport):
149
- mime_type = "application/x-sqlite3"
150
- suffix = "db"
151
- is_binary = True
152
-
153
- def __init__(
154
- self, *args, table_name: str = "results", if_exists: str = "replace", **kwargs
155
- ):
156
- """
157
- Initialize SQLite export.
158
-
159
- Args:
160
- table_name: Name of the table to create
161
- if_exists: How to handle existing table ('fail', 'replace', or 'append')
162
- """
163
- super().__init__(*args, **kwargs)
164
- self.table_name = table_name
165
- self.if_exists = if_exists
166
-
167
- def _get_column_types(self) -> list[tuple[str, str]]:
168
- """Infer SQL column types from the data."""
169
- column_types = []
170
-
171
- # Check first row of data for types
172
- if self.rows:
173
- first_row = self.rows[0]
174
- for header, value in zip(self.header, first_row):
175
- if isinstance(value, bool):
176
- sql_type = "BOOLEAN"
177
- elif isinstance(value, int):
178
- sql_type = "INTEGER"
179
- elif isinstance(value, float):
180
- sql_type = "REAL"
181
- else:
182
- sql_type = "TEXT"
183
- column_types.append((header, sql_type))
184
- else:
185
- # If no data, default to TEXT
186
- column_types = [(header, "TEXT") for header in self.header]
187
-
188
- return column_types
189
-
190
- def _create_table(self, cursor: sqlite3.Cursor) -> None:
191
- """Create the table with appropriate schema."""
192
- column_types = self._get_column_types()
193
-
194
- # Drop existing table if replace mode
195
- if self.if_exists == "replace":
196
- cursor.execute(f"DROP TABLE IF EXISTS {self.table_name}")
197
- elif self.if_exists == "fail":
198
- cursor.execute(
199
- f"SELECT name FROM sqlite_master WHERE type='table' AND name=?",
200
- (self.table_name,),
201
- )
202
- if cursor.fetchone():
203
- raise ValueError(f"Table {self.table_name} already exists")
204
-
205
- # Create table
206
- columns = ", ".join(f'"{col}" {dtype}' for col, dtype in column_types)
207
- create_table_sql = f"""
208
- CREATE TABLE IF NOT EXISTS {self.table_name} (
209
- {columns}
210
- )
211
- """
212
- cursor.execute(create_table_sql)
213
-
214
- def format_data(self) -> bytes:
215
- """Convert the data to a SQLite database file."""
216
- buffer = io.BytesIO()
217
-
218
- # Create in-memory database
219
- conn = sqlite3.connect(":memory:")
220
- cursor = conn.cursor()
221
-
222
- # Create table and insert data
223
- self._create_table(cursor)
224
-
225
- # Prepare placeholders for INSERT
226
- placeholders = ",".join(["?" for _ in self.header])
227
- insert_sql = f"INSERT INTO {self.table_name} ({','.join(self.header)}) VALUES ({placeholders})"
228
-
229
- # Insert data
230
- cursor.executemany(insert_sql, self.rows)
231
- conn.commit()
232
-
233
- # Save to file buffer
234
- conn.backup(sqlite3.connect(buffer))
235
- conn.close()
236
-
237
- buffer.seek(0)
238
- return buffer.getvalue()
239
-
240
- def _validate_params(self) -> None:
241
- """Validate initialization parameters."""
242
- valid_if_exists = {"fail", "replace", "append"}
243
- if self.if_exists not in valid_if_exists:
244
- raise ValueError(
245
- f"if_exists must be one of {valid_if_exists}, got {self.if_exists}"
246
- )
247
-
248
- # Validate table name (basic SQLite identifier validation)
249
- if not self.table_name.isalnum() and not all(c in "_" for c in self.table_name):
250
- raise ValueError(
251
- f"Invalid table name: {self.table_name}. Must contain only alphanumeric characters and underscores."
252
- )
File without changes
File without changes
File without changes