@@ -101,22 +101,83 @@ def from_dict(cls, data: dict[str, Any]) -> Self:
101
101
102
102
103
103
@dataclass
104
- class DataTable :
104
+ class ExamplesTable :
105
105
location : Location
106
106
name : str | None = None
107
- tableHeader : Row | None = None
108
- tableBody : list [Row ] | None = field (default_factory = list )
107
+ table_header : Row | None = None
108
+ table_body : list [Row ] | None = field (default_factory = list )
109
109
110
110
@classmethod
111
111
def from_dict (cls , data : dict [str , Any ]) -> Self :
112
112
return cls (
113
113
location = Location .from_dict (data ["location" ]),
114
114
name = data .get ("name" ),
115
- tableHeader = Row .from_dict (data ["tableHeader" ]) if data .get ("tableHeader" ) else None ,
116
- tableBody = [Row .from_dict (row ) for row in data .get ("tableBody" , [])],
115
+ table_header = Row .from_dict (data ["tableHeader" ]) if data .get ("tableHeader" ) else None ,
116
+ table_body = [Row .from_dict (row ) for row in data .get ("tableBody" , [])],
117
117
)
118
118
119
119
120
+ @dataclass
121
+ class DataTable :
122
+ location : Location
123
+ rows : list [Row ]
124
+
125
+ @classmethod
126
+ def from_dict (cls , data : dict [str , Any ]) -> Self :
127
+ return cls (
128
+ location = Location .from_dict (data ["location" ]), rows = [Row .from_dict (row ) for row in data .get ("rows" , [])]
129
+ )
130
+
131
+ def transpose (self ) -> Self :
132
+ # Transpose the cells, turning rows into columns
133
+ if not self .rows :
134
+ return self # Return itself if there are no rows to transpose
135
+
136
+ # Get the list of lists of cell values (i.e., extract all row cells)
137
+ cells_matrix = [row .cells for row in self .rows ]
138
+
139
+ # Check the maximum number of columns (to handle different row lengths)
140
+ max_columns = max (len (row ) for row in cells_matrix )
141
+
142
+ # Create a list to store the transposed cells
143
+ transposed_cells = []
144
+
145
+ for col_idx in range (max_columns ):
146
+ # Create a new list for each transposed column
147
+ transposed_column = []
148
+ for row in cells_matrix :
149
+ if col_idx < len (row ): # Ensure we don't go out of bounds
150
+ transposed_column .append (row [col_idx ])
151
+ else :
152
+ transposed_column .append (Cell (location = Location (0 , 0 ), value = "" )) # Empty cell
153
+
154
+ # Create a new row from the transposed column
155
+ transposed_row = Row (id = str (col_idx ), location = self .location , cells = transposed_column )
156
+ transposed_cells .append (transposed_row )
157
+
158
+ # Return a new DataTable with transposed rows
159
+ return DataTable (location = self .location , rows = transposed_cells )
160
+
161
+ def to_dict (self ) -> dict [str , list [str ]]:
162
+ # Ensure there are at least two rows: one for the header and one for the values
163
+ if len (self .rows ) < 2 :
164
+ raise ValueError ("DataTable needs at least two rows: one for headers and one for values" )
165
+
166
+ # Extract the header row (first row)
167
+ header = [cell .value for cell in self .rows [0 ].cells ]
168
+
169
+ # Extract the values from subsequent rows
170
+ values_rows = [[cell .value for cell in row .cells ] for row in self .rows [1 :]]
171
+
172
+ # Transpose the values so that each column corresponds to a header key
173
+ transposed_values = list (zip (* values_rows ))
174
+
175
+ # Map each header to the corresponding list of values
176
+ result_dict = {header [i ]: list (transposed_values [i ]) for i in range (len (header ))}
177
+
178
+ return result_dict
179
+
180
+
120
181
@dataclass
121
182
class DocString :
122
183
content : str
@@ -136,22 +197,22 @@ def from_dict(cls, data: dict[str, Any]) -> Self:
136
197
class Step :
137
198
id : str
138
199
keyword : str
139
- keywordType : str
200
+ keyword_type : str
140
201
location : Location
141
202
text : str
142
- dataTable : DataTable | None = None
143
- docString : DocString | None = None
203
+ data_table : DataTable | None = None
204
+ doc_string : DocString | None = None
144
205
145
206
@classmethod
146
207
def from_dict (cls , data : dict [str , Any ]) -> Self :
147
208
return cls (
148
209
id = data ["id" ],
149
210
keyword = data ["keyword" ].strip (),
150
- keywordType = data ["keywordType" ],
211
+ keyword_type = data ["keywordType" ],
151
212
location = Location .from_dict (data ["location" ]),
152
213
text = data ["text" ],
153
- dataTable = DataTable .from_dict (data ["dataTable" ]) if data .get ("dataTable" ) else None ,
154
- docString = DocString .from_dict (data ["docString" ]) if data .get ("docString" ) else None ,
214
+ data_table = DataTable .from_dict (data ["dataTable" ]) if data .get ("dataTable" ) else None ,
215
+ doc_string = DocString .from_dict (data ["docString" ]) if data .get ("docString" ) else None ,
155
216
)
156
217
157
218
@@ -175,7 +236,7 @@ class Scenario:
175
236
description : str
176
237
steps : list [Step ]
177
238
tags : list [Tag ]
178
- examples : list [DataTable ] = field (default_factory = list )
239
+ examples : list [ExamplesTable ] = field (default_factory = list )
179
240
180
241
@classmethod
181
242
def from_dict (cls , data : dict [str , Any ]) -> Self :
@@ -187,7 +248,7 @@ def from_dict(cls, data: dict[str, Any]) -> Self:
187
248
description = data ["description" ],
188
249
steps = [Step .from_dict (step ) for step in data ["steps" ]],
189
250
tags = [Tag .from_dict (tag ) for tag in data ["tags" ]],
190
- examples = [DataTable .from_dict (example ) for example in data ["examples" ]],
251
+ examples = [ExamplesTable .from_dict (example ) for example in data ["examples" ]],
191
252
)
192
253
193
254
0 commit comments