|
55 | 55 | from pathlib import Path |
56 | 56 | from uuid import UUID |
57 | 57 | from decimal import Decimal, DecimalException |
58 | | -from configparser import ConfigParser, DEFAULTSECT |
| 58 | +from configparser import (ConfigParser, DEFAULTSECT, ExtendedInterpolation, |
| 59 | + MAX_INTERPOLATION_DEPTH, InterpolationDepthError, |
| 60 | + InterpolationSyntaxError, NoSectionError, NoOptionError, |
| 61 | + InterpolationMissingOptionError) |
59 | 62 | from inspect import signature, Signature, Parameter |
60 | 63 | from enum import Enum, Flag |
61 | 64 | import os |
@@ -140,6 +143,74 @@ def _power_of_two(value): |
140 | 143 | return False |
141 | 144 | return value == 2 ** (value.bit_length() - 1) |
142 | 145 |
|
| 146 | +class EnvExtendedInterpolation(ExtendedInterpolation): |
| 147 | + """.. versionadded:: 1.8.0 |
| 148 | +
|
| 149 | + Modified version of `configparser.ExtendedInterpolation` class that adds special |
| 150 | + handling for "env" section that returns value of specified environment variable, |
| 151 | + or empty string if such variable is not defined. |
| 152 | +
|
| 153 | + Example:: |
| 154 | +
|
| 155 | + ${env:path} is reference to PATH environment variable. |
| 156 | + """ |
| 157 | + def _interpolate_some(self, parser, option, accum, rest, section, map, |
| 158 | + depth): |
| 159 | + rawval = parser.get(section, option, raw=True, fallback=rest) |
| 160 | + if depth > MAX_INTERPOLATION_DEPTH: |
| 161 | + raise InterpolationDepthError(option, section, rawval) |
| 162 | + while rest: |
| 163 | + p = rest.find("$") |
| 164 | + if p < 0: |
| 165 | + accum.append(rest) |
| 166 | + return |
| 167 | + if p > 0: |
| 168 | + accum.append(rest[:p]) |
| 169 | + rest = rest[p:] |
| 170 | + # p is no longer used |
| 171 | + c = rest[1:2] |
| 172 | + if c == "$": |
| 173 | + accum.append("$") |
| 174 | + rest = rest[2:] |
| 175 | + elif c == "{": |
| 176 | + m = self._KEYCRE.match(rest) |
| 177 | + if m is None: |
| 178 | + raise InterpolationSyntaxError(option, section, |
| 179 | + "bad interpolation variable reference %r" % rest) |
| 180 | + path = m.group(1).split(':') |
| 181 | + rest = rest[m.end():] |
| 182 | + sect = section |
| 183 | + opt = option |
| 184 | + try: |
| 185 | + if len(path) == 1: |
| 186 | + opt = parser.optionxform(path[0]) |
| 187 | + v = map[opt] |
| 188 | + elif len(path) == 2: |
| 189 | + sect = path[0] |
| 190 | + opt = parser.optionxform(path[1]) |
| 191 | + if sect == 'env': |
| 192 | + v = os.getenv(opt.upper(), '') |
| 193 | + else: |
| 194 | + v = parser.get(sect, opt, raw=True) |
| 195 | + else: |
| 196 | + raise InterpolationSyntaxError( |
| 197 | + option, section, |
| 198 | + "More than one ':' found: %r" % (rest,)) |
| 199 | + except (KeyError, NoSectionError, NoOptionError): |
| 200 | + raise InterpolationMissingOptionError( |
| 201 | + option, section, rawval, ":".join(path)) from None |
| 202 | + if "$" in v: |
| 203 | + self._interpolate_some(parser, opt, accum, v, sect, |
| 204 | + dict(parser.items(sect, raw=True)), |
| 205 | + depth + 1) |
| 206 | + else: |
| 207 | + accum.append(v) |
| 208 | + else: |
| 209 | + raise InterpolationSyntaxError( |
| 210 | + option, section, |
| 211 | + "'$' must be followed by '$' or '{', " |
| 212 | + "found: %r" % (rest,)) |
| 213 | + |
143 | 214 | class DirectoryScheme: |
144 | 215 | """Class that provide paths to typically used application directories. |
145 | 216 |
|
|
0 commit comments