How to use when_keywords method in Gherkin-python

Best Python code snippet using gherkin-python

parser.py

Source:parser.py Github

copy

Full Screen

1# -*- coding: utf-8 -*-2"""3A Gherkin parser written using pyparsing.4"""5import os6from collections import OrderedDict7from copy import copy8from gherkin.dialect import Dialect9from gherkin.errors import ParserError10from gherkin.parser import Parser11from gherkin.token_matcher import TokenMatcher12from aloe import strings13from aloe.exceptions import AloeSyntaxError14from aloe.utils import memoizedproperty15# Pylint can't figure out methods vs. properties and which classes are16# abstract17# pylint:disable=abstract-method18class LanguageTokenMatcher(TokenMatcher):19 """Gherkin 3 token matcher that always uses the given language."""20 def __init__(self, dialect_name='en'):21 self.actual_dialect_name = dialect_name22 super().__init__(dialect_name=dialect_name)23 def _change_dialect(self, dialect_name, location=None):24 """Force the dialect name given in the constructor."""25 super()._change_dialect(self.actual_dialect_name, location=location)26def cell_values(row):27 """Extract cell values from a table header or row."""28 return tuple(cell['value'] for cell in row['cells'])29class Node(object):30 """31 A base parse node.32 """33 def __init__(self, parsed, filename=None):34 """Construct the node from Gherkin parse results."""35 self.line = parsed['location']['line']36 self.col = parsed['location']['column']37 self.filename = filename38 @property39 def feature(self):40 """The feature this node ultimately belongs to."""41 raise NotImplementedError42 @property43 def location(self):44 """Location as 'filename:line'"""45 return '{filename}:{line}'.format(46 filename=os.path.relpath(self.filename),47 line=self.line,48 )49 @property50 def text(self):51 """The text for this node."""52 raise NotImplementedError53 indent = 0 # The indent to use when printing the node54 def represented(self):55 """A representation of the node."""56 result = ' ' * self.indent + self.text.strip()57 return result58class Step(Node):59 """60 A single statement within a test.61 A :class:`Scenario` or :class:`Background` is composed of multiple62 :class:`Step`.63 """64 table = None65 """66 A Gherkin table as an iterable of rows, themselves iterables of cells.67 e.g.:68 .. code-block:: gherkin69 Then I have fruit:70 | apples | oranges |71 | 0 | 2 |72 Becomes:73 .. code-block:: python74 (('apples', 'oranges'), ('0', '2'))75 """76 multiline = None77 """78 A Gherkin multiline string with the appropriate indenting removed.79 .. code-block:: gherkin80 Then I have poem:81 \"\"\"82 Glittering-Minded deathless Aphrodite,83 I beg you, Zeus’s daughter, weaver of snares,84 Don’t shatter my heart with fierce85 Pain, goddess,86 \"\"\"87 """88 outline = None89 """90 If this step is a part of an outline, the reference to the outline.91 """92 def __init__(self, parsed, background=None, scenario=None, **kwargs):93 super().__init__(parsed, **kwargs)94 if background:95 self.background = background96 elif scenario:97 self.scenario = scenario98 else:99 raise ValueError(100 "Step must belong to either a scenario or a background.")101 self.sentence = parsed['keyword'] + parsed['text']102 """The sentence parsed for this step."""103 try:104 argument_type = parsed['argument']['type']105 except KeyError:106 argument_type = None107 if argument_type == 'DataTable':108 self.table = tuple(109 cell_values(row)110 for row in parsed['argument']['rows']111 )112 elif argument_type == 'DocString':113 self.multiline = parsed['argument']['content']114 @property115 def text(self):116 return self.sentence117 def __str__(self):118 return '<Step: "%s">' % self.sentence119 def __repr__(self):120 return str(self)121 @property122 def container(self):123 """The background or scenario that contains this step."""124 try:125 return self.background126 except AttributeError:127 return self.scenario128 def parse_steps_from_string(self, string, **kwargs):129 """130 Parse a number of steps, returns an iterable of :class:`Step`.131 This is used by :func:`step.behave_as`.132 """133 try:134 self.scenario # pylint:disable=pointless-statement135 container_text = \136 '%s: scenario' % self.feature.dialect.scenario_keywords[0]137 is_scenario = True138 except AttributeError:139 container_text = \140 '%s: ' % self.feature.dialect.background_keywords[0]141 is_scenario = False142 # Gherkin can't parse anything other than complete features143 feature_string = """144 # language: {feature.language}145 {feature.keyword}: feature146 {container_text}147 {string}148 """.format(149 container_text=container_text,150 feature=self.feature,151 string=string,152 )153 feature = self.feature.parse(string=feature_string,154 filename=self.filename)155 if is_scenario:156 return feature.scenarios[0].steps157 else:158 return feature.background.steps159 @property160 def feature(self):161 """162 The :class:`Feature` this step is a part of.163 """164 return self.container.feature165 @memoizedproperty166 def keys(self):167 """168 Return the first row of a table if this statement contains one.169 """170 if self.table:171 return tuple(self.table[0])172 else:173 return ()174 @memoizedproperty175 def hashes(self):176 """177 Return the table attached to the step as an iterable of hashes, where178 the first row - the column headings - supplies keys for all the others.179 e.g.:180 .. code-block:: gherkin181 Then I have fruit:182 | apples | oranges |183 | 0 | 2 |184 Becomes:185 .. code-block:: python186 ({187 'apples': '0',188 'oranges': '2',189 },)190 """191 if not self.table:192 return ()193 keys = self.keys194 return tuple(195 dict(zip(keys, row))196 for row in self.table[1:]197 )198 @memoizedproperty199 def max_length(self):200 """201 The max length of the feature, description and child blocks202 """203 return max(204 0,205 strings.get_terminal_width(self.represented(table=False,206 multiline=False)),207 *[strings.get_terminal_width(line)208 for line in self.represent_table().splitlines()]209 )210 indent = 4211 # pylint:disable=arguments-differ212 def represented(self, table=True, multiline=True, color=str):213 """214 Render the line.215 """216 lines = [color(super().represented())]217 if table and self.table:218 lines.append(self.represent_table(cell_wrap=color))219 if multiline and self.multiline:220 lines.append(self.represent_multiline(string_wrap=color))221 return '\n'.join(lines)222 # pylint:enable=arguments-differ223 def represent_table(self, **kwargs):224 """225 Render the table.226 :param cell_wrap: color to use inside the table cells227 """228 return strings.represent_table(229 self.table, indent=self.indent + 2, **kwargs)230 def represent_multiline(self, string_wrap=str):231 """232 Render the multiline.233 :param string_wrap: color to use inside the string234 """235 indent = self.indent + 2236 lines = [' ' * indent + '"""']237 lines += [' ' * indent + string_wrap(line)238 for line in self.multiline.splitlines()]239 lines += [' ' * indent + '"""']240 return '\n'.join(lines)241 def resolve_substitutions(self, outline):242 """243 Creates a copy of the step with any <variables> resolved.244 """245 replaced = copy(self)246 def replace_vars(string):247 """Replace all the variables in a string."""248 for key, value in outline.items():249 key = '<{key}>'.format(key=key)250 string = string.replace(key, value)251 return string252 replaced.sentence = replace_vars(self.sentence)253 if self.multiline:254 replaced.multiline = replace_vars(self.multiline)255 if self.table:256 replaced.table = tuple(257 tuple(258 replace_vars(cell)259 for cell in row260 )261 for row in self.table262 )263 replaced.outline = outline264 return replaced265 def step_keyword(self, kind):266 """267 An appropriate keyword for a particular kind of step268 (Given, When, Then) for the language the current step is written in.269 """270 dialect = self.feature.dialect271 keywords = {272 'given': dialect.given_keywords,273 'when': dialect.when_keywords,274 'then': dialect.then_keywords,275 }[kind]276 # Gherkin allows '*' as a keyword; skip it to be sure the keyword is277 # specifically for the given kind278 return next(279 keyword for keyword in keywords280 if not keyword.startswith('*')281 )282class StepContainer(Node):283 """A node containing steps, e.g. Feature:, Scenario:"""284 step_class = Step285 container_name = 'container' # override in subclasses286 @property287 def feature(self):288 return self._feature289 def __init__(self, parsed, feature=None, filename=None, **kwargs):290 super().__init__(parsed, filename=filename, **kwargs)291 self._feature = feature292 # Put a reference to the parent node into all the steps293 parent_ref = {self.container_name: self}294 self.steps = tuple(295 self.step_class(step, filename=filename, **parent_ref)296 for step in parsed['steps']297 )298 indent = 2299class HeaderNode(Node):300 """A node with a header consisting of a keyword and a name."""301 name_required = True302 def __init__(self, parsed, **kwargs):303 super().__init__(parsed, **kwargs)304 self.keyword = parsed['keyword']305 self.name = parsed['name'].strip()306 if self.name_required and self.name == '':307 raise AloeSyntaxError(308 self.filename,309 "{line}:{col} {klass} must have a name".format(310 line=self.line,311 col=self.col,312 klass=self.__class__.__name__))313 def __str__(self):314 return '<{klass}: "{name}">'.format(315 klass=self.__class__.__name__,316 name=self.name)317 def __repr__(self):318 return str(self)319 @property320 def text(self):321 """The text for this block."""322 return '{keyword}: {name}'.format(keyword=self.keyword,323 name=self.name).strip()324class TaggedNode(Node):325 """A node with attached tags."""326 def __init__(self, parsed, **kwargs):327 super().__init__(parsed, **kwargs)328 self._tags = tuple(329 tag['name'][1:] for tag in parsed['tags']330 )331 @property332 def tags(self):333 """334 Tags for a feature.335 Tags are applied to a feature using the appropriate Gherkin syntax:336 .. code-block:: gherkin337 @tag1 @tag2338 Feature: Eat leaves339 """340 return self._tags341 def represent_tags(self):342 """343 Render the tags of a tagged block.344 """345 return ' ' * self.indent + ' '.join('@%s' % tag for tag in self.tags)346class Background(HeaderNode, StepContainer):347 """The background of all :class:`Scenario` in a :class:`Feature`."""348 container_name = 'background'349 name_required = False350class Outline(OrderedDict, Node):351 """An outline within a :class:`Scenario`."""352 def __init__(self, keys, table_row, filename=None):353 """Construct the outline."""354 # Extract values355 OrderedDict.__init__(self, zip(keys, cell_values(table_row)))356 # Store the file and line information357 Node.__init__(self, table_row, filename=filename)358class Scenario(HeaderNode, TaggedNode, StepContainer):359 """A scenario within a :class:`Feature`."""360 container_name = 'scenario'361 def __init__(self, parsed, **kwargs):362 super().__init__(parsed, **kwargs)363 # Build a list of outline hashes364 # A single scenario can have multiple example blocks, the returned365 # token is a list of table tokens366 self.outlines = ()367 for example_table in parsed.get('examples', ()):368 # the first row of the table is the column headings369 keys = cell_values(example_table['tableHeader'])370 self.outlines += tuple(371 Outline(keys, row)372 for row in example_table['tableBody']373 )374 indent = 2375 def represent_outlines(self):376 """377 Render the outlines table.378 """379 return strings.represent_table(380 self.outlines_table, indent=self.indent + 2)381 @memoizedproperty382 def max_length(self):383 """384 The max horizontal length of the feature, description and child blocks.385 """386 return max(387 0,388 strings.get_terminal_width(self.represented()),389 *([step.max_length for step in self.steps]390 + [strings.get_terminal_width(line)391 for line in self.represent_outlines().splitlines()])392 )393 @memoizedproperty394 def outlines_table(self):395 """396 Return the scenario outline examples as a table.397 """398 # get the list of column headings399 headings_dict = OrderedDict()400 for outline in self.outlines:401 headings_dict.update(outline)402 headings = list(headings_dict.keys())403 table = [headings]404 # append the data to the table405 for outline in self.outlines:406 table.append([outline.get(cell, '') for cell in headings])407 return table408 @property409 def tags(self):410 """Tags for the :attr:`feature` and the scenario."""411 return self._tags + self.feature.tags412 @property413 def evaluated(self):414 """415 Yield the outline and steps.416 """417 for outline in self.outlines:418 steps = [step.resolve_substitutions(outline)419 for step in self.steps]420 # set a backref to the scenario421 for step in steps:422 step.scenario = self423 yield (outline, steps)424class Description(Node):425 """426 The description block of a feature.427 """428 def __init__(self, parsed, **kwargs):429 super().__init__(parsed, **kwargs)430 description = parsed.get('description', '')431 self.lines = tuple(line.strip() for line in description.split('\n'))432 def __str__(self):433 return '\n'.join(self.lines)434 def __repr__(self):435 return str(self)436 indent = 2437 def represented(self):438 return '\n'.join(439 self.represent_line(n)440 for n, _ in enumerate(self.lines)441 )442 def represent_line(self, idx):443 """444 Render the nth line in the description.445 """446 line = self.lines[idx]447 if line:448 result = ' ' * self.indent + line449 else:450 result = ''451 return result452 @memoizedproperty453 def description_at(self):454 """455 Return a tuple of lines in the string containing the description.456 """457 offset = self.line458 return tuple(offset + lineno for lineno, _459 in enumerate(self.lines))460 @memoizedproperty461 def max_length(self):462 """463 The maximum length of all description lines.464 """465 try:466 return max(467 strings.get_terminal_width(self.represent_line(n))468 for n, _ in enumerate(self.lines)469 )470 except ValueError:471 return 0472class Feature(HeaderNode, TaggedNode):473 """474 A complete Gherkin feature.475 Features can either be constructed :func:`from_file` or476 :func:`from_string`.477 """478 background_class = Background479 scenario_class = Scenario480 background = None481 def __init__(self, parsed, filename=None, **kwargs):482 # Gherkin's top level definition is a GherkinDocument, which doesn't483 # have a location484 parsed = parsed['feature']485 super().__init__(parsed, filename=filename, **kwargs)486 self.language = parsed['language']487 self.description_node = Description(parsed, filename=filename)488 scenarios = []489 for child in parsed['children']:490 if child['type'] == 'Background':491 # Gherkin syntax disallows multiple backgrounds492 assert not self.background, "Duplicate background found."493 self.background = self.background_class(child,494 filename=filename,495 feature=self)496 else:497 scenarios.append(child)498 self.scenarios = tuple(499 self.scenario_class(scenario, filename=filename, feature=self)500 for scenario in scenarios501 )502 @classmethod503 def parse(cls, string=None, filename=None, language=None):504 """505 Parse either a string or a file.506 """507 parser = Parser()508 if language:509 if language == 'pt-br':510 language = 'pt'511 token_matcher = LanguageTokenMatcher(language)512 else:513 token_matcher = TokenMatcher()514 try:515 return cls(516 parser.parse(string or filename, token_matcher=token_matcher),517 filename=filename,518 )519 except ParserError as ex:520 raise AloeSyntaxError(filename, str(ex)) from ex521 @classmethod522 def from_string(cls, string, language=None):523 """524 Parse a string into a :class:`Feature`.525 """526 return cls.parse(string=string, language=language)527 @classmethod528 def from_file(cls, filename, language=None):529 """530 Parse a file or filename into a :class:`Feature`.531 """532 return cls.parse(filename=filename, language=language)533 @property534 def description(self):535 """536 The description of the feature (the text that comes directly under537 the feature).538 """539 return str(self.description_node)540 @property541 def dialect(self):542 """543 The Gherkin dialect for the feature.544 """545 return Dialect.for_name(self.language)546 @property547 def feature(self):548 """549 Convenience property for generic functions.550 """551 return self552 @memoizedproperty553 def max_length(self):554 """555 The max horizontal length of the feature, description and child blocks.556 This is used for aligning rendered output.557 """558 return max(559 0,560 strings.get_terminal_width(561 self.represented(description=False)),562 self.description_node.max_length,563 *[scenario.max_length for scenario in self.scenarios]564 )565 # pylint:disable=arguments-differ566 def represented(self, description=True):567 result = super().represented()568 if description and self.description != '':569 result += '\n'570 result += self.description_node.represented()...

Full Screen

Full Screen

gherkin_template_processor.py

Source:gherkin_template_processor.py Github

copy

Full Screen

1import json2print("Make sure script is run using python3")3def generate_keyword_body(keywords):4 first_keyword = keywords[0].replace("'", "\\'")5 body = "\n\t("6 body += "'" + keywords[0].replace("'", "\\'") + "'"7 8 if len(body) > 1:9 for keyword in range(1,len(keywords)): 10 body += "\n\t\t| '{k}'".format(k=keywords[keyword].replace("'", "\\'"))11 body += "\n\t) "12 return body13 14language_data = json.load(open('languages/gherkin-languages.json'))15template = """lexer grammar GherkinLexer;16fragment LANGUAGE_KEYWORD : WS* '#' WS* 'language' WS* ':' WS*;17LANGUAGE_HEADER : LANGUAGE_KEYWORD 'en' LINE_END -> mode(DEFAULT_MODE) ;18"""19for language in language_data.keys():20 l = language_data[language]21 ul = language.upper().replace("-", "_")22 template += "\n" + ul + "_LANGUAGE_HEADER : LANGUAGE_KEYWORD '" + language + "' LINE_END -> mode(" + ul + "), type(LANGUAGE_HEADER) ;"23template += "\n//////////////////////////////////////////////////////////////////////////"24template += '''25FEATURE_KEYWORD : ('Feature'26 | 'Business Need'27 | 'Ability') ':' -> channel(HIDDEN) ;28SCENARIO_KEYWORD : ('Scenario' | 'Example') ':' -> channel(HIDDEN) ;29SCENARIO_OUTLINE_KEYWORD : 'Scenario Outline:' -> channel(HIDDEN);30BACKGROUND_KEYWORD : 'Background:' ;31EXAMPLES_KEYWORD : 'Examples:' | 'Scenarios:';32RULE_KEYWORD : 'Rule:' ;33STARTING_STEP_KEYWORD : GIVEN_KEYWORD34 | WHEN_KEYWORD35 | THEN_KEYWORD36 | WILD_KEYWORD37 ;38ALTERNATIVE_STEP_KEYWORD : AND_KEYWORD39 | BUT_KEYWORD40 | GIVEN_KEYWORD41 ;42GIVEN_KEYWORD : 'Given ' ;43WHEN_KEYWORD : 'When ' ;44THEN_KEYWORD : 'Then ' ;45WILD_KEYWORD : '* ' ;46AND_KEYWORD : 'And ';47BUT_KEYWORD : 'But ';48fragment CAPTURE_DATA : '<' ~[>\\t\\r\\n ]'>' ;49fragment DOCSTRING_DOUBLE_QUOTES : WS* '"""' (CAPTURE_DATA | ~'"' | '"' ~'"')*? '"""' LINE_END ;50fragment DOCSTRING_BACKTICKS : WS* '```' (~'`' | CAPTURE_DATA | '`' ~'`').*? '```' LINE_END;51fragment TAG : '@'~[ \\r\\n\\t@]+ ;52fragment ESCAPE_SEQUENCE : '\\\\' [\\\\|\\n]* ;53fragment CELL_CHARACTER54 : CAPTURE_DATA55 | ~[\\r\\n|\\\\]56 | ESCAPE_SEQUENCE57 ;58fragment CELL_DATA : WS* CELL_CHARACTER* '|';59DOCSTRING : DOCSTRING_DOUBLE_QUOTES | DOCSTRING_BACKTICKS ;60TAGS : WS* TAG (WS* TAG)* (COMMENT? | LINE_END);61FEATURE_TITLE : WS* FEATURE_KEYWORD ~[\\r\\n]* LINE_END ;62BACKGROUND_TITLE : WS* BACKGROUND_KEYWORD ~[\\r\\n]* COMMENT? LINE_END ;63EXAMPLES_TITLE : WS* EXAMPLES_KEYWORD ~[\\r\\n]* COMMENT? LINE_END ;64SCENARIO_TITLE : WS* SCENARIO_KEYWORD ~[\\r\\n]* LINE_END ;65SCENARIO_OUTLINE_TITLE : WS* SCENARIO_OUTLINE_KEYWORD (CAPTURE_DATA | ~[\\r\\n])* LINE_END ;66RULE_TITLE : WS* RULE_KEYWORD ~[\\r\\n]* LINE_END ;67GIVEN_STEP : WS* GIVEN_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;68WHEN_STEP : WS* WHEN_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;69THEN_STEP : WS* THEN_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;70AND_STEP : WS* AND_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;71BUT_STEP : WS* BUT_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;72WILD_STEP : WS* WILD_KEYWORD ~[ @\\r\\n|] ~[\\r\\n]* LINE_END;73DATA_ROW : WS* '|' CELL_DATA+ LINE_END ;74INVALID_LANGUAGE_HEADER : LANGUAGE_KEYWORD ~[\\r\\n]* LINE_END ;75COMMENT : WS* '#' ~[\\r\\n]* LINE_END -> channel(HIDDEN) ;76LINE_END : WS* (NEWLINE+ | EOF) -> skip;77NEWLINE : [\\r\\n] -> skip ;78WS : [ \\t] -> skip;79LONG_DESCRIPTION : WS* ~[ @\\r\\n|] ~[\\r\\n]* LINE_END ;80///////////////////////////////////////////////////81'''82for language in language_data.keys():83 print(language)84 ul = language.upper().replace('-', '_')85 ld = language_data[language]86 template += "\n//" + ld["name"]87 template += "\n//" + ld["native"]88 template += "\nmode " + ul + ";"89 # Feature90 template += "\n\t" + ul + "_FEATURE : ( "91 template += generate_keyword_body(ld["feature"]) + "':'"92 template += "\n\t\t) -> type(FEATURE_KEYWORD) ;"93 # Background94 template += """95 {lc}_BACKGROUND : (96 """.format(lc=ul)97 template += generate_keyword_body(ld["background"]) + "':'"98 template += "\n\t\t) -> type(BACKGROUND_KEYWORD);"99 # Scenario100 template += "\n\t" + ul + "_SCENARIO : (\n"101 template += generate_keyword_body(ld["scenario"]) + "':'"102 template += "\n\t) -> type(SCENARIO_KEYWORD);\n"103 # Scenario Outline104 template += "\n\t" + ul + "_SCENARIO_OUTLINE : (\n"105 template += generate_keyword_body(ld["scenarioOutline"])106 template += "\n\t) -> type(SCENARIO_OUTLINE_KEYWORD);\n"107 # Examples108 template += "\n\t" + ul + "_EXAMPLES : (\n"109 template += generate_keyword_body(ld["examples"]) + "':'"110 template += " ) -> type(EXAMPLES_KEYWORD) ;\n"111 # Rule112 template += "\n\t" + ul + "_RULE : (\n"113 template += generate_keyword_body(ld["rule"]) + "':'"114 template += " ) -> type(RULE_KEYWORD) ;\n"115 # Given116 template += "\n\t" + ul + "_GIVEN : (\n"117 given_keywords = ld["given"]118 if "* " in given_keywords: given_keywords.remove("* ")119 template += generate_keyword_body(given_keywords)120 template += " ) -> type(GIVEN_KEYWORD) ;\n"121 # When122 template += "\n\t" + ul + "_WHEN : (\n"123 when_keywords = ld["when"]124 if "* " in when_keywords: when_keywords.remove("* ")125 template += generate_keyword_body(when_keywords)126 template += " ) -> type(WHEN_KEYWORD) ;\n"127 # Then128 template += "\n\t" + ul + "_THEN : (\n"129 then_keywords = ld["then"]130 if "* " in then_keywords: then_keywords.remove("* ")131 template += generate_keyword_body(then_keywords)132 template += " ) -> type(THEN_KEYWORD) ;\n"133 # And134 template += "\n\t" + ul + "_AND : (\n"135 and_keywords = ld["and"]136 if "* " in and_keywords: and_keywords.remove("* ")137 template += generate_keyword_body(and_keywords)138 template += " ) -> type(AND_KEYWORD) ;\n"139 # But140 template += "\n\t" + ul + "_BUT : (\n"141 but_keywords = ld["but"]142 if "* " in but_keywords: but_keywords.remove("* ")143 template += generate_keyword_body(but_keywords)144 template += " ) -> type(BUT_KEYWORD) ;\n"145 # Starting step146 template += "\n\t" + ul + """_STARTING_STEP_KEYWORD : (\n147 {lc}_GIVEN148 | {lc}_WHEN149 | {lc}_THEN150 | WILD_KEYWORD151 ) -> type(STARTING_STEP_KEYWORD);152 """.format(lc=ul)153 template += "\n\t" + ul + """_ALTERNATIVE_STEP_KEYWORD : (\n154 {lc}_AND155 | {lc}_BUT156 ) -> type(ALTERNATIVE_STEP_KEYWORD);157 """.format(lc=ul)158 template += """159 {language_code}_FEATURE_TITLE : WS* {language_code}_FEATURE ~[\\r\\n]* WS* LINE_END -> type(FEATURE_TITLE) ;160 {language_code}_BACKGROUND_TITLE : WS* {language_code}_BACKGROUND ~[\\r\\n]* COMMENT? LINE_END -> type(BACKGROUND_TITLE) ;161 {language_code}_EXAMPLES_TITLE : WS* {language_code}_EXAMPLES ~[\\r\\n]* COMMENT? LINE_END -> type(EXAMPLES_TITLE);162 {language_code}_SCENARIO_TITLE : WS* {language_code}_SCENARIO ~[\\r\\n]* LINE_END -> type(SCENARIO_TITLE);163 {language_code}_SCENARIO_OUTLINE_TITLE : WS* {language_code}_SCENARIO_OUTLINE ~[\\r\\n]* LINE_END -> type(SCENARIO_OUTLINE_TITLE) ;164 {language_code}_RULE_TITLE : WS* {language_code}_RULE ~[\\r\\n]* LINE_END -> type(RULE_TITLE);165 {language_code}_GIVEN_STEP : WS* {language_code}_GIVEN ~[ @\\r\\n|] ~[\\r\\n]* LINE_END -> type(GIVEN_STEP);166 {language_code}_WHEN_STEP : WS* {language_code}_WHEN ~[ @\\r\\n|] ~[\\r\\n]* LINE_END -> type(WHEN_STEP);167 {language_code}_THEN_STEP : WS* {language_code}_THEN ~[ @\\r\\n|] ~[\\r\\n]* LINE_END -> type(THEN_STEP);168 {language_code}_AND_STEP : WS* {language_code}_AND ~[ @\\r\\n|] ~[\\r\\n]* LINE_END -> type(AND_STEP);169 {language_code}_BUT_STEP : WS* {language_code}_BUT ~[ @\\r\\n|] ~[\\r\\n]* LINE_END -> type(BUT_STEP);170""".format(language_code = ul)171 f = open("GherkinLexer.g4", "w")172 f.write(template)173 f.close()174print("GherkinLexer.g4 regenerated")...

Full Screen

Full Screen

Constants.py

Source:Constants.py Github

copy

Full Screen

1"""2This file is where the magic happens3All the constants and regex expressions are defined4I explain every line as every variable is quite self explanatory5"""6match_types = ["optional", "once", "at_least_once"]7def or_reg(keyword_list, match_type="once"):8 """9 Function that given a keyword list creates the regex or operator10 :param keyword_list: The keyword list11 :param match_type: If the operator is required or optional12 :return: (keyword_1|keyword_2)match_type13 """14 sorted_by_length = sorted(keyword_list, key=len, reverse=True)15 ret_regex = "("16 for i, key_word in enumerate(sorted_by_length):17 ret_regex += key_word18 if i != len(sorted_by_length) - 1:19 ret_regex += "|"20 ret_regex += ")"21 if match_type == match_types[0]:22 ret_regex += "?"23 elif match_type == match_types[1]:24 ret_regex += ""25 else:26 ret_regex += "+"27 return ret_regex28WORDS = "[a-zA-Z0-9 -]+"29WORD = "[a-zA-Z0-9-]+"30def or_join(args):31 return "|".join(args)32def optional(arg):33 return f"({arg})?"34complete_negation = "it is not the case that"35complete_negation_tokens = ["it", "is", "not", "the", "case", "that"]36base_regex = f"({complete_negation} )?"37defeasible_indicators = ["normally", "usually"]38separator = " "39negation_keywords = [40 ["do", "not"],41 ["does", "not"],42 "not",43 "never",44 "dont",45 "don't",46 "doesnt",47 "doesn't",48]49base_filler_words = ["the", "must", "a", "an"]50prepositions = [51 "aboard",52 "about",53 "above",54 "across",55 "after",56 "against",57 "along",58 "amid",59 "among",60 "anti",61 "around",62 "as",63 "at",64 "before",65 "behind",66 "below",67 "beneath",68 "beside",69 "besides",70 "between",71 "beyond",72 "but",73 "by",74 "concerning",75 "considering",76 "despite",77 "down",78 "during",79 "except",80 "excepting",81 "excluding",82 "following",83 "for",84 "from",85 "in",86 "inside",87 "into",88 "like",89 "minus",90 "near",91 "of",92 "off",93 "on",94 "onto",95 "opposite",96 "outside",97 "over",98 "past",99 "per",100 "plus",101 "regarding",102 "round",103 "since",104 "than",105 "through",106 "to",107 "toward",108 "towards",109 "under",110 "underneath",111 "unlike",112 "until",113 "up",114 "upon",115 "versus",116 "via",117 "with",118 "within",119 "without",120]121connection_keywords = ["or", "and", ";", "nor", ","]122and_connection_keywords = ["and", ";"]123or_connection_keywords = ["or", "nor"]124demoregen_regex = f"Neither {WORDS} (nor|and|or) {WORDS}"125true_connected_regex = f"{WORDS} (or|and|;|,) {WORDS}"126connected_regex = f"{base_regex}({demoregen_regex}|{true_connected_regex})"127# If-and-only-if keywords128iff_keywords = ["if and only if", "iff"]129iff_regex = f"{WORDS} ({or_join(iff_keywords)}) {WORDS}"130# Unless keywords131unless_keywords = ["unless"]132unless_split_tokens = [",", "then", ", then"]133unless_split_right = ["unless"]134unless_left_regex = (135 f"{or_reg(unless_keywords)} {WORDS}{or_reg(unless_split_tokens)} {WORDS}"136)137unless_right_regex = f"{WORDS}{or_reg(unless_split_right)} {WORDS}"138unless_regex = f"{base_regex}({unless_left_regex}|{unless_right_regex})"139# When keywords and regex140when_keywords = ["when", "if"]141when_split_tokens = [",", "then", ", then"]142when_split_right = ["because", ", because", "if", ", if", ", because of"]143when_left_regex = f"{or_reg(when_keywords)} {WORDS}{or_reg(when_split_tokens)} {WORDS}"144when_right_regex = f"{WORDS}{or_reg(when_split_right)} {WORDS}"145when_regex = f"{optional(or_join(defeasible_indicators))}{optional(' ')}{optional(', ')}{base_regex}({when_left_regex}|{when_right_regex})"146de_morgan_expression = "neither"147pluralism_keywords = ["all", "some", "no"]148pos_middle_keywords = ["have", "are", "is an", "is a", "is", "has"]149neg_middle_keywords = [150 "have not",151 "are not",152 "is not an",153 "is not a",154 "is not",155 "has not",156]157def get_opposite_of(middle_keyword):158 if middle_keyword in pos_middle_keywords:159 position = pos_middle_keywords.index(middle_keyword)160 return neg_middle_keywords[position]161 elif middle_keyword in neg_middle_keywords:162 position = neg_middle_keywords.index(middle_keyword)163 return pos_middle_keywords[position]164 else:165 return "do not " + middle_keyword166middle_keywords = pos_middle_keywords + neg_middle_keywords167to_be_sentences = f"{or_reg(pluralism_keywords)} {WORDS} {or_reg(middle_keywords)} .+"168verb_sentences = f"{or_reg(pluralism_keywords)} {WORDS}"169syllogism_regex = f"{to_be_sentences}|{verb_sentences}"170conclusion_regex = "(Therefore, )?"171syllogism_regex_complete = f"{conclusion_regex}{base_regex}{syllogism_regex}"172pos_function_keywords = ["is the", "is an", "is a", "is", "are"]173neg_function_keywords = ["is not the", "is not an", "is not a", "is not", "are not"]174def get_opposite_of_function(middle_keyword):175 if middle_keyword in pos_function_keywords:176 position = pos_function_keywords.index(middle_keyword)177 return neg_function_keywords[position]178 if middle_keyword in neg_function_keywords:179 position = neg_function_keywords.index(middle_keyword)180 return pos_function_keywords[position]181function_keywords = pos_function_keywords + neg_function_keywords182function_split_keywords = ["than", "of"]183single_function_regex = f"{WORD} {or_reg(function_keywords)} {WORD}"184multi_function_regex = f"{WORD} {or_reg(function_keywords)} {WORD} {or_reg(function_split_keywords)} {WORD}"185function_regex = f"{base_regex}({multi_function_regex}|{single_function_regex})"186quantified_keywords_plural = ["For each", "For all"]187quantified_keywords_singular = ["There is a", "It exists a"]188quantified_keywords_split = [",", " ,", " it is the case that", "\s"]189quantified_keywords = quantified_keywords_plural + quantified_keywords_singular190quantified_regex_plural = f"{or_reg(quantified_keywords_plural)} {WORD}{or_reg(quantified_keywords_split, match_types[0])}.+"191quantified_regex_singular = f"{or_reg(quantified_keywords_singular)} {WORD}{or_reg(quantified_keywords_split, match_types[0])}.+"192quantified_regex = (193 f"{base_regex}({quantified_regex_plural}|{quantified_regex_singular})"...

Full Screen

Full Screen

token_matcher.py

Source:token_matcher.py Github

copy

Full Screen

1import re2from .dialect import Dialect3from .errors import NoSuchLanguageException4class TokenMatcher(object):5 LANGUAGE_RE = re.compile(r"^\s*#\s*language\s*:\s*([a-zA-Z\-_]+)\s*$")6 def __init__(self, dialect_name='en'):7 self._default_dialect_name = dialect_name8 self._change_dialect(dialect_name)9 self.reset()10 def reset(self):11 if self.dialect_name != self._default_dialect_name:12 self._change_dialect(self._default_dialect_name)13 self._indent_to_remove = 014 self._active_doc_string_separator = None15 def match_FeatureLine(self, token):16 return self._match_title_line(token, 'FeatureLine', self.dialect.feature_keywords)17 def match_ScenarioLine(self, token):18 return self._match_title_line(token, 'ScenarioLine', self.dialect.scenario_keywords)19 def match_ScenarioOutlineLine(self, token):20 return self._match_title_line(token, 'ScenarioOutlineLine',21 self.dialect.scenario_outline_keywords)22 def match_BackgroundLine(self, token):23 return self._match_title_line(token, 'BackgroundLine', self.dialect.background_keywords)24 def match_ExamplesLine(self, token):25 return self._match_title_line(token, 'ExamplesLine', self.dialect.examples_keywords)26 def match_TableRow(self, token):27 if not token.line.startswith('|'):28 return False29 # TODO: indent30 self._set_token_matched(token, 'TableRow', items=token.line.table_cells)31 return True32 def match_StepLine(self, token):33 keywords = (self.dialect.given_keywords +34 self.dialect.when_keywords +35 self.dialect.then_keywords +36 self.dialect.and_keywords +37 self.dialect.but_keywords)38 for keyword in (k for k in keywords if token.line.startswith(k)):39 title = token.line.get_rest_trimmed(len(keyword))40 self._set_token_matched(token, 'StepLine', title, keyword)41 return True42 return False43 def match_Comment(self, token):44 if not token.line.startswith('#'):45 return False46 text = token.line._line_text # take the entire line, including leading space47 self._set_token_matched(token, 'Comment', text, indent=0)48 return True49 def match_Empty(self, token):50 if not token.line.is_empty():51 return False52 self._set_token_matched(token, 'Empty', indent=0)53 return True54 def match_Language(self, token):55 match = self.LANGUAGE_RE.match(token.line.get_line_text())56 if not match:57 return False58 dialect_name = match.group(1)59 self._set_token_matched(token, 'Language', dialect_name)60 self._change_dialect(dialect_name, token.location)61 return True62 def match_TagLine(self, token):63 if not token.line.startswith('@'):64 return False65 self._set_token_matched(token, 'TagLine', items=token.line.tags)66 return True67 def match_DocStringSeparator(self, token):68 if not self._active_doc_string_separator:69 # open70 return (self._match_DocStringSeparator(token, '"""', True) or71 self._match_DocStringSeparator(token, '```', True))72 else:73 # close74 return self._match_DocStringSeparator(token, self._active_doc_string_separator, False)75 def _match_DocStringSeparator(self, token, separator, is_open):76 if not token.line.startswith(separator):77 return False78 content_type = None79 if is_open:80 content_type = token.line.get_rest_trimmed(len(separator))81 self._active_doc_string_separator = separator82 self._indent_to_remove = token.line.indent83 else:84 self._active_doc_string_separator = None85 self._indent_to_remove = 086 # TODO: Use the separator as keyword. That's needed for pretty printing.87 self._set_token_matched(token, 'DocStringSeparator', content_type)88 return True89 def match_Other(self, token):90 # take the entire line, except removing DocString indents91 text = token.line.get_line_text(self._indent_to_remove)92 self._set_token_matched(token, 'Other', self._unescaped_docstring(text), indent=0)93 return True94 def match_EOF(self, token):95 if not token.eof():96 return False97 self._set_token_matched(token, 'EOF')98 return True99 def _match_title_line(self, token, token_type, keywords):100 for keyword in (k for k in keywords if token.line.startswith_title_keyword(k)):101 title = token.line.get_rest_trimmed(len(keyword) + len(':'))102 self._set_token_matched(token, token_type, title, keyword)103 return True104 return False105 def _set_token_matched(self, token, matched_type, text=None,106 keyword=None, indent=None, items=None):107 if items is None:108 items = []109 token.matched_type = matched_type110 # text == '' should not result in None111 token.matched_text = text.rstrip('\r\n') if text is not None else None112 token.matched_keyword = keyword113 if indent is not None:114 token.matched_indent = indent115 else:116 token.matched_indent = token.line.indent if token.line else 0117 token.matched_items = items118 token.location['column'] = token.matched_indent + 1119 token.matched_gherkin_dialect = self.dialect_name120 def _change_dialect(self, dialect_name, location=None):121 dialect = Dialect.for_name(dialect_name)122 if not dialect:123 raise NoSuchLanguageException(dialect_name, location)124 self.dialect_name = dialect_name125 self.dialect = dialect126 def _unescaped_docstring(self, text):...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Gherkin-python automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful