From c5fa0f56e41ee03fd7b02f6474cbb4fd1bdf08e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20V=C3=A9zina?= <5130500+morpheus65535@users.noreply.github.com> Date: Fri, 13 Sep 2019 15:14:31 -0400 Subject: [PATCH] WIP --- libs/backports/configparser2/__init__.py | 1340 +++++++++++ libs/backports/configparser2/helpers.py | 171 ++ libs/bs4/formatter.py | 99 + libs/bs42.7/AUTHORS.txt | 43 + libs/bs42.7/COPYING.txt | 27 + libs/bs42.7/NEWS.txt | 1190 ++++++++++ libs/bs42.7/README.txt | 63 + libs/bs42.7/TODO.txt | 31 + libs/bs42.7/__init__.py | 529 +++++ libs/bs42.7/builder/__init__.py | 333 +++ libs/bs42.7/builder/_html5lib.py | 426 ++++ libs/bs42.7/builder/_htmlparser.py | 314 +++ libs/bs42.7/builder/_lxml.py | 258 +++ libs/bs42.7/dammit.py | 842 +++++++ libs/bs42.7/diagnose.py | 219 ++ libs/bs42.7/element.py | 1808 +++++++++++++++ libs/bs42.7/formatter.py | 99 + libs/bs42.7/testing.py | 770 +++++++ libs/bs42.7/tests/__init__.py | 1 + libs/bs42.7/tests/test_builder_registry.py | 147 ++ libs/bs42.7/tests/test_docs.py | 36 + libs/bs42.7/tests/test_html5lib.py | 130 ++ libs/bs42.7/tests/test_htmlparser.py | 34 + libs/bs42.7/tests/test_lxml.py | 76 + libs/bs42.7/tests/test_soup.py | 501 ++++ libs/bs42.7/tests/test_tree.py | 2050 +++++++++++++++++ libs/concurrent2.7/__init__.py | 3 + libs/concurrent2.7/futures/__init__.py | 23 + libs/concurrent2.7/futures/_base.py | 607 +++++ libs/concurrent2.7/futures/process.py | 359 +++ libs/concurrent2.7/futures/thread.py | 134 ++ libs/deathbycaptcha2.7.py | 516 +++++ libs/dogpile2.7/__init__.py | 4 + libs/dogpile2.7/cache/__init__.py | 4 + libs/dogpile2.7/cache/api.py | 215 ++ libs/dogpile2.7/cache/backends/__init__.py | 22 + libs/dogpile2.7/cache/backends/file.py | 447 ++++ libs/dogpile2.7/cache/backends/memcached.py | 364 +++ libs/dogpile2.7/cache/backends/memory.py | 124 + libs/dogpile2.7/cache/backends/null.py | 62 + libs/dogpile2.7/cache/backends/redis.py | 183 ++ libs/dogpile2.7/cache/exception.py | 25 + libs/dogpile2.7/cache/plugins/__init__.py | 0 libs/dogpile2.7/cache/plugins/mako_cache.py | 90 + libs/dogpile2.7/cache/proxy.py | 95 + libs/dogpile2.7/cache/region.py | 1498 ++++++++++++ libs/dogpile2.7/cache/util.py | 146 ++ libs/dogpile2.7/core.py | 17 + libs/dogpile2.7/lock.py | 158 ++ libs/dogpile2.7/util/__init__.py | 4 + libs/dogpile2.7/util/compat.py | 65 + libs/dogpile2.7/util/langhelpers.py | 123 + libs/dogpile2.7/util/nameregistry.py | 84 + libs/dogpile2.7/util/readwrite_lock.py | 132 ++ libs/soupsieve/__init__.py | 127 + libs/soupsieve/__meta__.py | 190 ++ libs/soupsieve/css_match.py | 1472 ++++++++++++ libs/soupsieve/css_parser.py | 1218 ++++++++++ libs/soupsieve/css_types.py | 344 +++ libs/soupsieve/util.py | 170 ++ libs/subliminal/subtitles/__init__.py | 88 + libs/subliminal/subtitles/subrip.py | 82 + libs/subliminal2.7/__init__.py | 21 + libs/subliminal2.7/cache.py | 16 + libs/subliminal2.7/cli.py | 458 ++++ libs/subliminal2.7/converters/__init__.py | 0 libs/subliminal2.7/converters/addic7ed.py | 32 + libs/subliminal2.7/converters/legendastv.py | 27 + libs/subliminal2.7/converters/shooter.py | 23 + libs/subliminal2.7/converters/thesubdb.py | 26 + libs/subliminal2.7/converters/tvsubtitles.py | 25 + libs/subliminal2.7/core.py | 777 +++++++ libs/subliminal2.7/exceptions.py | 29 + libs/subliminal2.7/extensions.py | 105 + libs/subliminal2.7/providers/__init__.py | 164 ++ libs/subliminal2.7/providers/addic7ed.py | 321 +++ libs/subliminal2.7/providers/legendastv.py | 522 +++++ libs/subliminal2.7/providers/napiprojekt.py | 108 + libs/subliminal2.7/providers/opensubtitles.py | 297 +++ libs/subliminal2.7/providers/podnapisi.py | 197 ++ libs/subliminal2.7/providers/shooter.py | 83 + libs/subliminal2.7/providers/subscenter.py | 243 ++ libs/subliminal2.7/providers/thesubdb.py | 88 + libs/subliminal2.7/providers/tvsubtitles.py | 226 ++ libs/subliminal2.7/refiners/__init__.py | 12 + libs/subliminal2.7/refiners/metadata.py | 99 + libs/subliminal2.7/refiners/omdb.py | 187 ++ libs/subliminal2.7/refiners/tvdb.py | 351 +++ libs/subliminal2.7/score.py | 234 ++ libs/subliminal2.7/subtitle.py | 261 +++ libs/subliminal2.7/utils.py | 152 ++ libs/subliminal2.7/video.py | 239 ++ libs/yaml/__init__.py | 402 ++++ libs/yaml/composer.py | 139 ++ libs/yaml/constructor.py | 720 ++++++ libs/yaml/cyaml.py | 101 + libs/yaml/dumper.py | 62 + libs/yaml/emitter.py | 1137 +++++++++ libs/yaml/error.py | 75 + libs/yaml/events.py | 86 + libs/yaml/loader.py | 63 + libs/yaml/nodes.py | 49 + libs/yaml/parser.py | 589 +++++ libs/yaml/reader.py | 185 ++ libs/yaml/representer.py | 389 ++++ libs/yaml/resolver.py | 227 ++ libs/yaml/scanner.py | 1435 ++++++++++++ libs/yaml/serializer.py | 111 + libs/yaml/tokens.py | 104 + 109 files changed, 31929 insertions(+) create mode 100644 libs/backports/configparser2/__init__.py create mode 100644 libs/backports/configparser2/helpers.py create mode 100644 libs/bs4/formatter.py create mode 100644 libs/bs42.7/AUTHORS.txt create mode 100644 libs/bs42.7/COPYING.txt create mode 100644 libs/bs42.7/NEWS.txt create mode 100644 libs/bs42.7/README.txt create mode 100644 libs/bs42.7/TODO.txt create mode 100644 libs/bs42.7/__init__.py create mode 100644 libs/bs42.7/builder/__init__.py create mode 100644 libs/bs42.7/builder/_html5lib.py create mode 100644 libs/bs42.7/builder/_htmlparser.py create mode 100644 libs/bs42.7/builder/_lxml.py create mode 100644 libs/bs42.7/dammit.py create mode 100644 libs/bs42.7/diagnose.py create mode 100644 libs/bs42.7/element.py create mode 100644 libs/bs42.7/formatter.py create mode 100644 libs/bs42.7/testing.py create mode 100644 libs/bs42.7/tests/__init__.py create mode 100644 libs/bs42.7/tests/test_builder_registry.py create mode 100644 libs/bs42.7/tests/test_docs.py create mode 100644 libs/bs42.7/tests/test_html5lib.py create mode 100644 libs/bs42.7/tests/test_htmlparser.py create mode 100644 libs/bs42.7/tests/test_lxml.py create mode 100644 libs/bs42.7/tests/test_soup.py create mode 100644 libs/bs42.7/tests/test_tree.py create mode 100644 libs/concurrent2.7/__init__.py create mode 100644 libs/concurrent2.7/futures/__init__.py create mode 100644 libs/concurrent2.7/futures/_base.py create mode 100644 libs/concurrent2.7/futures/process.py create mode 100644 libs/concurrent2.7/futures/thread.py create mode 100644 libs/deathbycaptcha2.7.py create mode 100644 libs/dogpile2.7/__init__.py create mode 100644 libs/dogpile2.7/cache/__init__.py create mode 100644 libs/dogpile2.7/cache/api.py create mode 100644 libs/dogpile2.7/cache/backends/__init__.py create mode 100644 libs/dogpile2.7/cache/backends/file.py create mode 100644 libs/dogpile2.7/cache/backends/memcached.py create mode 100644 libs/dogpile2.7/cache/backends/memory.py create mode 100644 libs/dogpile2.7/cache/backends/null.py create mode 100644 libs/dogpile2.7/cache/backends/redis.py create mode 100644 libs/dogpile2.7/cache/exception.py create mode 100644 libs/dogpile2.7/cache/plugins/__init__.py create mode 100644 libs/dogpile2.7/cache/plugins/mako_cache.py create mode 100644 libs/dogpile2.7/cache/proxy.py create mode 100644 libs/dogpile2.7/cache/region.py create mode 100644 libs/dogpile2.7/cache/util.py create mode 100644 libs/dogpile2.7/core.py create mode 100644 libs/dogpile2.7/lock.py create mode 100644 libs/dogpile2.7/util/__init__.py create mode 100644 libs/dogpile2.7/util/compat.py create mode 100644 libs/dogpile2.7/util/langhelpers.py create mode 100644 libs/dogpile2.7/util/nameregistry.py create mode 100644 libs/dogpile2.7/util/readwrite_lock.py create mode 100644 libs/soupsieve/__init__.py create mode 100644 libs/soupsieve/__meta__.py create mode 100644 libs/soupsieve/css_match.py create mode 100644 libs/soupsieve/css_parser.py create mode 100644 libs/soupsieve/css_types.py create mode 100644 libs/soupsieve/util.py create mode 100644 libs/subliminal/subtitles/__init__.py create mode 100644 libs/subliminal/subtitles/subrip.py create mode 100644 libs/subliminal2.7/__init__.py create mode 100644 libs/subliminal2.7/cache.py create mode 100644 libs/subliminal2.7/cli.py create mode 100644 libs/subliminal2.7/converters/__init__.py create mode 100644 libs/subliminal2.7/converters/addic7ed.py create mode 100644 libs/subliminal2.7/converters/legendastv.py create mode 100644 libs/subliminal2.7/converters/shooter.py create mode 100644 libs/subliminal2.7/converters/thesubdb.py create mode 100644 libs/subliminal2.7/converters/tvsubtitles.py create mode 100644 libs/subliminal2.7/core.py create mode 100644 libs/subliminal2.7/exceptions.py create mode 100644 libs/subliminal2.7/extensions.py create mode 100644 libs/subliminal2.7/providers/__init__.py create mode 100644 libs/subliminal2.7/providers/addic7ed.py create mode 100644 libs/subliminal2.7/providers/legendastv.py create mode 100644 libs/subliminal2.7/providers/napiprojekt.py create mode 100644 libs/subliminal2.7/providers/opensubtitles.py create mode 100644 libs/subliminal2.7/providers/podnapisi.py create mode 100644 libs/subliminal2.7/providers/shooter.py create mode 100644 libs/subliminal2.7/providers/subscenter.py create mode 100644 libs/subliminal2.7/providers/thesubdb.py create mode 100644 libs/subliminal2.7/providers/tvsubtitles.py create mode 100644 libs/subliminal2.7/refiners/__init__.py create mode 100644 libs/subliminal2.7/refiners/metadata.py create mode 100644 libs/subliminal2.7/refiners/omdb.py create mode 100644 libs/subliminal2.7/refiners/tvdb.py create mode 100644 libs/subliminal2.7/score.py create mode 100644 libs/subliminal2.7/subtitle.py create mode 100644 libs/subliminal2.7/utils.py create mode 100644 libs/subliminal2.7/video.py create mode 100644 libs/yaml/__init__.py create mode 100644 libs/yaml/composer.py create mode 100644 libs/yaml/constructor.py create mode 100644 libs/yaml/cyaml.py create mode 100644 libs/yaml/dumper.py create mode 100644 libs/yaml/emitter.py create mode 100644 libs/yaml/error.py create mode 100644 libs/yaml/events.py create mode 100644 libs/yaml/loader.py create mode 100644 libs/yaml/nodes.py create mode 100644 libs/yaml/parser.py create mode 100644 libs/yaml/reader.py create mode 100644 libs/yaml/representer.py create mode 100644 libs/yaml/resolver.py create mode 100644 libs/yaml/scanner.py create mode 100644 libs/yaml/serializer.py create mode 100644 libs/yaml/tokens.py diff --git a/libs/backports/configparser2/__init__.py b/libs/backports/configparser2/__init__.py new file mode 100644 index 000000000..972413562 --- /dev/null +++ b/libs/backports/configparser2/__init__.py @@ -0,0 +1,1340 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Configuration file parser. + +A configuration file consists of sections, lead by a "[section]" header, +and followed by "name: value" entries, with continuations and such in +the style of RFC 822. + +Intrinsic defaults can be specified by passing them into the +ConfigParser constructor as a dictionary. + +class: + +ConfigParser -- responsible for parsing a list of + configuration files, and managing the parsed database. + + methods: + + __init__(defaults=None, dict_type=_default_dict, allow_no_value=False, + delimiters=('=', ':'), comment_prefixes=('#', ';'), + inline_comment_prefixes=None, strict=True, + empty_lines_in_values=True): + Create the parser. When `defaults' is given, it is initialized into the + dictionary or intrinsic defaults. The keys must be strings, the values + must be appropriate for %()s string interpolation. + + When `dict_type' is given, it will be used to create the dictionary + objects for the list of sections, for the options within a section, and + for the default values. + + When `delimiters' is given, it will be used as the set of substrings + that divide keys from values. + + When `comment_prefixes' is given, it will be used as the set of + substrings that prefix comments in empty lines. Comments can be + indented. + + When `inline_comment_prefixes' is given, it will be used as the set of + substrings that prefix comments in non-empty lines. + + When `strict` is True, the parser won't allow for any section or option + duplicates while reading from a single source (file, string or + dictionary). Default is True. + + When `empty_lines_in_values' is False (default: True), each empty line + marks the end of an option. Otherwise, internal empty lines of + a multiline option are kept as part of the value. + + When `allow_no_value' is True (default: False), options without + values are accepted; the value presented for these is None. + + sections() + Return all the configuration section names, sans DEFAULT. + + has_section(section) + Return whether the given section exists. + + has_option(section, option) + Return whether the given option exists in the given section. + + options(section) + Return list of configuration options for the named section. + + read(filenames, encoding=None) + Read and parse the list of named configuration files, given by + name. A single filename is also allowed. Non-existing files + are ignored. Return list of successfully read files. + + read_file(f, filename=None) + Read and parse one configuration file, given as a file object. + The filename defaults to f.name; it is only used in error + messages (if f has no `name' attribute, the string `' is used). + + read_string(string) + Read configuration from a given string. + + read_dict(dictionary) + Read configuration from a dictionary. Keys are section names, + values are dictionaries with keys and values that should be present + in the section. If the used dictionary type preserves order, sections + and their keys will be added in order. Values are automatically + converted to strings. + + get(section, option, raw=False, vars=None, fallback=_UNSET) + Return a string value for the named option. All % interpolations are + expanded in the return values, based on the defaults passed into the + constructor and the DEFAULT section. Additional substitutions may be + provided using the `vars' argument, which must be a dictionary whose + contents override any pre-existing defaults. If `option' is a key in + `vars', the value from `vars' is used. + + getint(section, options, raw=False, vars=None, fallback=_UNSET) + Like get(), but convert value to an integer. + + getfloat(section, options, raw=False, vars=None, fallback=_UNSET) + Like get(), but convert value to a float. + + getboolean(section, options, raw=False, vars=None, fallback=_UNSET) + Like get(), but convert value to a boolean (currently case + insensitively defined as 0, false, no, off for False, and 1, true, + yes, on for True). Returns False or True. + + items(section=_UNSET, raw=False, vars=None) + If section is given, return a list of tuples with (name, value) for + each option in the section. Otherwise, return a list of tuples with + (section_name, section_proxy) for each section, including DEFAULTSECT. + + remove_section(section) + Remove the given file section and all its options. + + remove_option(section, option) + Remove the given option from the given section. + + set(section, option, value) + Set the given option. + + write(fp, space_around_delimiters=True) + Write the configuration state in .ini format. If + `space_around_delimiters' is True (the default), delimiters + between keys and values are surrounded by spaces. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from collections import MutableMapping +import functools +import io +import itertools +import re +import sys +import warnings + +from backports.configparser2.helpers import OrderedDict as _default_dict +from backports.configparser2.helpers import ChainMap as _ChainMap +from backports.configparser2.helpers import from_none, open, str, PY2 + +__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError", + "NoOptionError", "InterpolationError", "InterpolationDepthError", + "InterpolationSyntaxError", "ParsingError", + "MissingSectionHeaderError", + "ConfigParser", "SafeConfigParser", "RawConfigParser", + "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"] + +DEFAULTSECT = "DEFAULT" + +MAX_INTERPOLATION_DEPTH = 10 + + +# exception classes +class Error(Exception): + """Base class for ConfigParser exceptions.""" + + def __init__(self, msg=''): + self.message = msg + Exception.__init__(self, msg) + + def __repr__(self): + return self.message + + __str__ = __repr__ + + +class NoSectionError(Error): + """Raised when no section matches a requested option.""" + + def __init__(self, section): + Error.__init__(self, 'No section: %r' % (section,)) + self.section = section + self.args = (section, ) + + +class DuplicateSectionError(Error): + """Raised when a section is repeated in an input source. + + Possible repetitions that raise this exception are: multiple creation + using the API or in strict parsers when a section is found more than once + in a single input file, string or dictionary. + """ + + def __init__(self, section, source=None, lineno=None): + msg = [repr(section), " already exists"] + if source is not None: + message = ["While reading from ", repr(source)] + if lineno is not None: + message.append(" [line {0:2d}]".format(lineno)) + message.append(": section ") + message.extend(msg) + msg = message + else: + msg.insert(0, "Section ") + Error.__init__(self, "".join(msg)) + self.section = section + self.source = source + self.lineno = lineno + self.args = (section, source, lineno) + + +class DuplicateOptionError(Error): + """Raised by strict parsers when an option is repeated in an input source. + + Current implementation raises this exception only when an option is found + more than once in a single file, string or dictionary. + """ + + def __init__(self, section, option, source=None, lineno=None): + msg = [repr(option), " in section ", repr(section), + " already exists"] + if source is not None: + message = ["While reading from ", repr(source)] + if lineno is not None: + message.append(" [line {0:2d}]".format(lineno)) + message.append(": option ") + message.extend(msg) + msg = message + else: + msg.insert(0, "Option ") + Error.__init__(self, "".join(msg)) + self.section = section + self.option = option + self.source = source + self.lineno = lineno + self.args = (section, option, source, lineno) + + +class NoOptionError(Error): + """A requested option was not found.""" + + def __init__(self, option, section): + Error.__init__(self, "No option %r in section: %r" % + (option, section)) + self.option = option + self.section = section + self.args = (option, section) + + +class InterpolationError(Error): + """Base class for interpolation-related exceptions.""" + + def __init__(self, option, section, msg): + Error.__init__(self, msg) + self.option = option + self.section = section + self.args = (option, section, msg) + + +class InterpolationMissingOptionError(InterpolationError): + """A string substitution required a setting which was not available.""" + + def __init__(self, option, section, rawval, reference): + msg = ("Bad value substitution:\n" + "\tsection: [%s]\n" + "\toption : %s\n" + "\tkey : %s\n" + "\trawval : %s\n" + % (section, option, reference, rawval)) + InterpolationError.__init__(self, option, section, msg) + self.reference = reference + self.args = (option, section, rawval, reference) + + +class InterpolationSyntaxError(InterpolationError): + """Raised when the source text contains invalid syntax. + + Current implementation raises this exception when the source text into + which substitutions are made does not conform to the required syntax. + """ + + +class InterpolationDepthError(InterpolationError): + """Raised when substitutions are nested too deeply.""" + + def __init__(self, option, section, rawval): + msg = ("Value interpolation too deeply recursive:\n" + "\tsection: [%s]\n" + "\toption : %s\n" + "\trawval : %s\n" + % (section, option, rawval)) + InterpolationError.__init__(self, option, section, msg) + self.args = (option, section, rawval) + + +class ParsingError(Error): + """Raised when a configuration file does not follow legal syntax.""" + + def __init__(self, source=None, filename=None): + # Exactly one of `source'/`filename' arguments has to be given. + # `filename' kept for compatibility. + if filename and source: + raise ValueError("Cannot specify both `filename' and `source'. " + "Use `source'.") + elif not filename and not source: + raise ValueError("Required argument `source' not given.") + elif filename: + source = filename + Error.__init__(self, 'Source contains parsing errors: %r' % source) + self.source = source + self.errors = [] + self.args = (source, ) + + @property + def filename(self): + """Deprecated, use `source'.""" + warnings.warn( + "The 'filename' attribute will be removed in future versions. " + "Use 'source' instead.", + DeprecationWarning, stacklevel=2 + ) + return self.source + + @filename.setter + def filename(self, value): + """Deprecated, user `source'.""" + warnings.warn( + "The 'filename' attribute will be removed in future versions. " + "Use 'source' instead.", + DeprecationWarning, stacklevel=2 + ) + self.source = value + + def append(self, lineno, line): + self.errors.append((lineno, line)) + self.message += '\n\t[line %2d]: %s' % (lineno, line) + + +class MissingSectionHeaderError(ParsingError): + """Raised when a key-value pair is found before any section header.""" + + def __init__(self, filename, lineno, line): + Error.__init__( + self, + 'File contains no section headers.\nfile: %r, line: %d\n%r' % + (filename, lineno, line)) + self.source = filename + self.lineno = lineno + self.line = line + self.args = (filename, lineno, line) + + +# Used in parser getters to indicate the default behaviour when a specific +# option is not found it to raise an exception. Created to enable `None' as +# a valid fallback value. +_UNSET = object() + + +class Interpolation(object): + """Dummy interpolation that passes the value through with no changes.""" + + def before_get(self, parser, section, option, value, defaults): + return value + + def before_set(self, parser, section, option, value): + return value + + def before_read(self, parser, section, option, value): + return value + + def before_write(self, parser, section, option, value): + return value + + +class BasicInterpolation(Interpolation): + """Interpolation as implemented in the classic ConfigParser. + + The option values can contain format strings which refer to other values in + the same section, or values in the special default section. + + For example: + + something: %(dir)s/whatever + + would resolve the "%(dir)s" to the value of dir. All reference + expansions are done late, on demand. If a user needs to use a bare % in + a configuration file, she can escape it by writing %%. Other other % usage + is considered a user error and raises `InterpolationSyntaxError'.""" + + _KEYCRE = re.compile(r"%\(([^)]+)\)s") + + def before_get(self, parser, section, option, value, defaults): + L = [] + self._interpolate_some(parser, option, L, value, section, defaults, 1) + return ''.join(L) + + def before_set(self, parser, section, option, value): + tmp_value = value.replace('%%', '') # escaped percent signs + tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax + if '%' in tmp_value: + raise ValueError("invalid interpolation syntax in %r at " + "position %d" % (value, tmp_value.find('%'))) + return value + + def _interpolate_some(self, parser, option, accum, rest, section, map, + depth): + if depth > MAX_INTERPOLATION_DEPTH: + raise InterpolationDepthError(option, section, rest) + while rest: + p = rest.find("%") + if p < 0: + accum.append(rest) + return + if p > 0: + accum.append(rest[:p]) + rest = rest[p:] + # p is no longer used + c = rest[1:2] + if c == "%": + accum.append("%") + rest = rest[2:] + elif c == "(": + m = self._KEYCRE.match(rest) + if m is None: + raise InterpolationSyntaxError(option, section, + "bad interpolation variable reference %r" % rest) + var = parser.optionxform(m.group(1)) + rest = rest[m.end():] + try: + v = map[var] + except KeyError: + raise from_none(InterpolationMissingOptionError( + option, section, rest, var)) + if "%" in v: + self._interpolate_some(parser, option, accum, v, + section, map, depth + 1) + else: + accum.append(v) + else: + raise InterpolationSyntaxError( + option, section, + "'%%' must be followed by '%%' or '(', " + "found: %r" % (rest,)) + + +class ExtendedInterpolation(Interpolation): + """Advanced variant of interpolation, supports the syntax used by + `zc.buildout'. Enables interpolation between sections.""" + + _KEYCRE = re.compile(r"\$\{([^}]+)\}") + + def before_get(self, parser, section, option, value, defaults): + L = [] + self._interpolate_some(parser, option, L, value, section, defaults, 1) + return ''.join(L) + + def before_set(self, parser, section, option, value): + tmp_value = value.replace('$$', '') # escaped dollar signs + tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax + if '$' in tmp_value: + raise ValueError("invalid interpolation syntax in %r at " + "position %d" % (value, tmp_value.find('$'))) + return value + + def _interpolate_some(self, parser, option, accum, rest, section, map, + depth): + if depth > MAX_INTERPOLATION_DEPTH: + raise InterpolationDepthError(option, section, rest) + while rest: + p = rest.find("$") + if p < 0: + accum.append(rest) + return + if p > 0: + accum.append(rest[:p]) + rest = rest[p:] + # p is no longer used + c = rest[1:2] + if c == "$": + accum.append("$") + rest = rest[2:] + elif c == "{": + m = self._KEYCRE.match(rest) + if m is None: + raise InterpolationSyntaxError(option, section, + "bad interpolation variable reference %r" % rest) + path = m.group(1).split(':') + rest = rest[m.end():] + sect = section + opt = option + try: + if len(path) == 1: + opt = parser.optionxform(path[0]) + v = map[opt] + elif len(path) == 2: + sect = path[0] + opt = parser.optionxform(path[1]) + v = parser.get(sect, opt, raw=True) + else: + raise InterpolationSyntaxError( + option, section, + "More than one ':' found: %r" % (rest,)) + except (KeyError, NoSectionError, NoOptionError): + raise from_none(InterpolationMissingOptionError( + option, section, rest, ":".join(path))) + if "$" in v: + self._interpolate_some(parser, opt, accum, v, sect, + dict(parser.items(sect, raw=True)), + depth + 1) + else: + accum.append(v) + else: + raise InterpolationSyntaxError( + option, section, + "'$' must be followed by '$' or '{', " + "found: %r" % (rest,)) + + +class LegacyInterpolation(Interpolation): + """Deprecated interpolation used in old versions of ConfigParser. + Use BasicInterpolation or ExtendedInterpolation instead.""" + + _KEYCRE = re.compile(r"%\(([^)]*)\)s|.") + + def before_get(self, parser, section, option, value, vars): + rawval = value + depth = MAX_INTERPOLATION_DEPTH + while depth: # Loop through this until it's done + depth -= 1 + if value and "%(" in value: + replace = functools.partial(self._interpolation_replace, + parser=parser) + value = self._KEYCRE.sub(replace, value) + try: + value = value % vars + except KeyError as e: + raise from_none(InterpolationMissingOptionError( + option, section, rawval, e.args[0])) + else: + break + if value and "%(" in value: + raise InterpolationDepthError(option, section, rawval) + return value + + def before_set(self, parser, section, option, value): + return value + + @staticmethod + def _interpolation_replace(match, parser): + s = match.group(1) + if s is None: + return match.group() + else: + return "%%(%s)s" % parser.optionxform(s) + + +class RawConfigParser(MutableMapping): + """ConfigParser that does not do interpolation.""" + + # Regular expressions for parsing section headers and options + _SECT_TMPL = r""" + \[ # [ + (?P
[^]]+) # very permissive! + \] # ] + """ + _OPT_TMPL = r""" + (?P