Best Python code snippet using gherkin-python
parser.py
Source:parser.py  
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()...gherkin_template_processor.py
Source:gherkin_template_processor.py  
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")...token_matcher.py
Source:token_matcher.py  
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):...dialect.py
Source:dialect.py  
...33    @property34    def when_keywords(self):35        return self.spec['when']36    @property37    def then_keywords(self):38        return self.spec['then']39    @property40    def and_keywords(self):41        return self.spec['and']42    @property43    def but_keywords(self):...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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
