22
22
STEP_PARAM_RE = re .compile (r"<(.+?)>" )
23
23
24
24
25
+ def get_tag_names (tag_data : list [GherkinTag ]) -> set [str ]:
26
+ """Extract tag names from tag data.
27
+
28
+ Args:
29
+ tag_data (List[dict]): The tag data to extract names from.
30
+
31
+ Returns:
32
+ set[str]: A set of tag names.
33
+ """
34
+ return {tag .name .lstrip ("@" ) for tag in tag_data }
35
+
36
+
25
37
@dataclass (eq = False )
26
38
class Feature :
27
39
"""Represents a feature parsed from a feature file.
@@ -64,6 +76,7 @@ class Examples:
64
76
name : str | None = None
65
77
example_params : list [str ] = field (default_factory = list )
66
78
examples : list [Sequence [str ]] = field (default_factory = list )
79
+ tags : set [str ] = field (default_factory = set )
67
80
68
81
def set_param_names (self , keys : Iterable [str ]) -> None :
69
82
"""Set the parameter names for the examples.
@@ -144,20 +157,19 @@ def steps(self) -> list[Step]:
144
157
"""
145
158
return (self .feature .background .steps if self .feature .background else []) + self ._steps
146
159
147
- def render (self , context : Mapping [str , Any ]) -> list [ Scenario ] :
160
+ def render (self , context : Mapping [str , Any ]) -> Scenario :
148
161
"""Render the scenario with the given context.
149
162
150
163
Args:
151
164
context (Mapping[str, Any]): The context for rendering steps.
152
165
153
166
Returns:
154
- list[ Scenario] : A list of Scenario objects with steps rendered based on the context.
167
+ Scenario: A Scenario object with steps rendered based on the context.
155
168
"""
156
- scenarios = []
157
- base_context = context or {}
158
- base_steps = [
169
+ background_steps = self .feature .background .steps if self .feature .background else []
170
+ scenario_steps = [
159
171
Step (
160
- name = step .render (base_context ),
172
+ name = step .render (context ),
161
173
type = step .type ,
162
174
indent = step .indent ,
163
175
line_number = step .line_number ,
@@ -167,52 +179,16 @@ def render(self, context: Mapping[str, Any]) -> list[Scenario]:
167
179
)
168
180
for step in self ._steps
169
181
]
170
- background_steps = self .feature .background .steps if self .feature .background else []
171
-
172
- if not self .examples :
173
- # Render a single scenario without examples
174
- scenarios .append (
175
- Scenario (
176
- feature = self .feature ,
177
- keyword = self .keyword ,
178
- name = self .name ,
179
- line_number = self .line_number ,
180
- steps = background_steps + base_steps ,
181
- tags = self .tags ,
182
- description = self .description ,
183
- )
184
- )
185
- else :
186
- # Render multiple scenarios with each example context
187
- for examples in self .examples :
188
- for example_context in examples .as_contexts ():
189
- full_context = {** base_context , ** example_context }
190
- example_steps = [
191
- Step (
192
- name = step .render (full_context ),
193
- type = step .type ,
194
- indent = step .indent ,
195
- line_number = step .line_number ,
196
- keyword = step .keyword ,
197
- datatable = step .datatable ,
198
- docstring = step .docstring ,
199
- )
200
- for step in self ._steps
201
- ]
202
- example_tags = self .tags .union (examples .tags if hasattr (examples , "tags" ) else set ())
203
- scenarios .append (
204
- Scenario (
205
- feature = self .feature ,
206
- keyword = self .keyword ,
207
- name = self .name ,
208
- line_number = self .line_number ,
209
- steps = background_steps + example_steps ,
210
- tags = example_tags ,
211
- description = self .description ,
212
- )
213
- )
214
-
215
- return scenarios
182
+ steps = background_steps + scenario_steps
183
+ return Scenario (
184
+ feature = self .feature ,
185
+ keyword = self .keyword ,
186
+ name = self .name ,
187
+ line_number = self .line_number ,
188
+ steps = steps ,
189
+ tags = self .tags ,
190
+ description = self .description ,
191
+ )
216
192
217
193
218
194
@dataclass (eq = False )
@@ -364,18 +340,6 @@ def __init__(self, basedir: str, filename: str, encoding: str = "utf-8"):
364
340
self .rel_filename = os .path .join (os .path .basename (basedir ), filename )
365
341
self .encoding = encoding
366
342
367
- @staticmethod
368
- def get_tag_names (tag_data : list [GherkinTag ]) -> set [str ]:
369
- """Extract tag names from tag data.
370
-
371
- Args:
372
- tag_data (List[dict]): The tag data to extract names from.
373
-
374
- Returns:
375
- set[str]: A set of tag names.
376
- """
377
- return {tag .name .lstrip ("@" ) for tag in tag_data }
378
-
379
343
def parse_steps (self , steps_data : list [GherkinStep ]) -> list [Step ]:
380
344
"""Parse a list of step data into Step objects.
381
345
@@ -432,7 +396,7 @@ def parse_scenario(self, scenario_data: GherkinScenario, feature: Feature) -> Sc
432
396
name = scenario_data .name ,
433
397
line_number = scenario_data .location .line ,
434
398
templated = templated ,
435
- tags = self . get_tag_names (scenario_data .tags ),
399
+ tags = get_tag_names (scenario_data .tags ),
436
400
description = textwrap .dedent (scenario_data .description ),
437
401
)
438
402
for step in self .parse_steps (scenario_data .steps ):
@@ -443,6 +407,7 @@ def parse_scenario(self, scenario_data: GherkinScenario, feature: Feature) -> Sc
443
407
examples = Examples (
444
408
line_number = example_data .location .line ,
445
409
name = example_data .name ,
410
+ tags = get_tag_names (example_data .tags ),
446
411
)
447
412
if example_data .table_header is not None :
448
413
param_names = [cell .value for cell in example_data .table_header .cells ]
@@ -482,7 +447,7 @@ def parse(self) -> Feature:
482
447
filename = self .abs_filename ,
483
448
rel_filename = self .rel_filename ,
484
449
name = feature_data .name ,
485
- tags = self . get_tag_names (feature_data .tags ),
450
+ tags = get_tag_names (feature_data .tags ),
486
451
background = None ,
487
452
line_number = feature_data .location .line ,
488
453
description = textwrap .dedent (feature_data .description ),
0 commit comments