def _parse()

in python/qpid_dispatch_internal/management/config.py [0:0]


    def _parse(self, lines):
        """
        Parse config file format into a section list

        The config file format is a text file in JSON-ish syntax.  It allows
        the user to define a set of Entities which contain Attributes.
        Attributes may be either a single item or a map of nested attributes.

        Entities and map Attributes start with a single open brace on a line by
        itself (no non-comment text after the opening brace!)

        Entities and map Attributes are terminated by a single closing brace
        that appears on a line by itself (no trailing comma and no non-comment
        trailing text!)

        Entity names and Attribute names and items are NOT enclosed in quotes
        nor are they terminated with commas, however some select Attributes
        have values which are expected to be valid JSON (double quoted
        strings, etc)

        Unlike JSON the config file also allows comments.  A comment begins
        with the '#' character and is terminated at the end of line.
        """

        # note: these regexes expect that trailing comment and leading and
        # trailing whitespace has been removed
        #
        entity = re.compile(r'([\w-]+)[ \t]*{[ \t]*$')                    # WORD {
        attr_map = re.compile(r'([\$]*[\w-]+)[ \t]*:[ \t]*{[ \t]*$')      # WORD: {
        json_map = re.compile(r'("[\$]*[\w-]+)"[ \t]*:[ \t]*{[ \t]*$')    # "WORD": {
        attr_item = re.compile(r'([\w-]+)[ \t]*:[ \t]*([^ \t{]+.*)$')     # WORD1: VALUE
        end = re.compile(r'^}$')                                          # } (only)
        json_end = re.compile(r'}$')                                      # } (at eol)

        # The 'pattern:' and 'bindingKey:' attributes in the schema are special
        # snowflakes. They allow '#' characters in their value, so they cannot
        # be treated as comment delimiters
        special_snowflakes = ['pattern', 'bindingKey', 'hostname']
        hash_ok = re.compile(r'([\w-]+)[ \t]*:[ \t]*([\S]+).*')

        # the 'openProperties' and 'groups' attributes are also special
        # snowflakes in that their value is expected to be valid JSON.  These
        # values do allow single line comments which are stripped out, but the
        # remaining content is expected to be valid JSON.
        json_snowflakes = ['openProperties', 'groups']

        self._line_num = 1
        self._child_level = 0
        self._in_json = False

        def sub(line):
            """Do substitutions to make line json-friendly"""
            line = line.strip()

            # ignore empty and comment lines
            if not line or line.startswith("#"):
                self._line_num += 1
                return ""

            # watch JSON for embedded maps and map terminations
            # always pass JSON as-is except appending a comma at the end
            if self._in_json:
                if json_map.search(line):
                    self._child_level += 1
                if json_end.search(line):
                    self._child_level -= 1
                    if self._child_level == 0:
                        self._in_json = False
                        line = re.sub(json_end, r'},', line)
                self._line_num += 1
                return line

            # filter off pattern items before stripping comments
            if attr_item.search(line):
                if re.sub(attr_item, r'\1', line) in special_snowflakes:
                    self._line_num += 1
                    return re.sub(hash_ok, r'"\1": "\2",', line)

            # now trim trailing comment
            line = line.split('#')[0].strip()

            if entity.search(line):
                # WORD {  --> ["WORD", {
                line = re.sub(entity, r'["\1", {', line)
            elif attr_map.search(line):
                # WORD: {  --> ["WORD": {
                key = re.sub(attr_map, r'\1', line)
                line = re.sub(attr_map, r'"\1": {', line)
                self._child_level += 1
                if key in json_snowflakes:
                    self._in_json = True
            elif attr_item.search(line):
                # WORD: VALUE --> "WORD": "VALUE"
                line = re.sub(attr_item, r'"\1": "\2",', line)
            elif end.search(line):
                # }  --> "}," or "}]," depending on nesting level
                if self._child_level > 0:
                    line = re.sub(end, r'},', line)
                    self._child_level -= 1
                else:
                    # end top level entity list item
                    line = re.sub(end, r'}],', line)
            else:
                # unexpected syntax, let json parser figure it out
                self._log(LOG_WARNING,
                          "Invalid config file syntax (line %d):\n"
                          ">>> %s"
                          % (self._line_num, line))
            self._line_num += 1
            return line

        js_text = "[%s]" % ("\n".join([sub(l) for l in lines]))
        if self._in_json or self._child_level != 0:
            self._log(LOG_WARNING,
                      "Configuration file: invalid entity nesting detected.")
        spare_comma = re.compile(r',\s*([]}])')  # Strip spare commas
        js_text = re.sub(spare_comma, r'\1', js_text)
        # Convert dictionary keys to camelCase
        try:
            sections = json.loads(js_text)
        except Exception as e:
            self.dump_json("Contents of failed config file", js_text)
            raise
        Config.transform_sections(sections)
        return sections