1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# -*- coding: utf-8 -*-
#------------------------------------------------------------------------------
# file: $Id$
# auth: Philip J Grabner <grabner@cadit.com>
# date: 2016/12/14
# copy: (C) Copyright 2016-EOT Cadit Inc., All Rights Reserved.
#------------------------------------------------------------------------------
import re
import os
import six
from six.moves import configparser as CP
#------------------------------------------------------------------------------
if six.PY3:
_real_BasicInterpolation = CP.BasicInterpolation
_real_BasicInterpolation_before_get = CP.BasicInterpolation.before_get
else:
_real_BasicInterpolation = object
_real_BasicInterpolation_before_get = None
#------------------------------------------------------------------------------
class InterpolationMissingEnvError(CP.InterpolationMissingOptionError): pass
class InterpolationMissingSuperError(CP.InterpolationMissingOptionError): pass
#------------------------------------------------------------------------------
class BasicInterpolationMixin(object):
def before_get(self, parser, section, option, value, defaults):
def base_interpolate(*args, **kw):
return _real_BasicInterpolation_before_get(parser._interpolation, *args, **kw)
return interpolate(parser, base_interpolate, section, option, value, defaults)
#------------------------------------------------------------------------------
class IniheritInterpolation(BasicInterpolationMixin, _real_BasicInterpolation):
# todo: rewrite this to use a more PY3-oriented approach...
pass
#------------------------------------------------------------------------------
_env_cre = re.compile(r'%\(ENV:([^:)]+)(:-([^)]*))?\)s', flags=re.DOTALL)
_super_cre = re.compile(r'%\(SUPER(:-([^)]*))?\)s', flags=re.DOTALL)
def interpolate(parser, base_interpolate, section, option, rawval, vars):
# todo: ugh. this should be rewritten so that it uses
# `BasicInterpolationMixin` so as to be more "future-proof"...
value = rawval
depth = CP.MAX_INTERPOLATION_DEPTH
erepl = lambda match: _env_replace(
match, parser, base_interpolate, section, option, rawval, vars)
srepl = lambda match: _super_replace(
match, parser, parser, None, section, option, rawval, vars)
while depth and ( _env_cre.search(value) or _super_cre.search(value) ):
depth -= 1
value = _env_cre.sub(erepl, value)
value = _super_cre.sub(srepl, value)
if not depth and ( _env_cre.search(value) or _super_cre.search(value) ):
raise CP.InterpolationDepthError(option, section, rawval)
if '%(SUPER)s' in value:
raise InterpolationMissingSuperError(option, section, rawval, 'SUPER')
if base_interpolate is None:
return value
vars = dict(vars)
while True:
# ok, this is... uh... "tricky"... basically, we don't want to
# pre-emptively expand SUPER & ENV expressions because then we may
# trip invalid expressions that aren't actually used. thus, we
# only expand keys that are actually requested, and we detect by
# catching InterpolationMissingOptionError's...
try:
return base_interpolate(parser, section, option, value, vars)
except CP.InterpolationMissingOptionError as err:
for key, val in list(vars.items()):
if err.reference.lower() in val.lower():
newval = interpolate(parser, None, section, key, val, vars)
if newval != val:
vars[key] = newval
break
else:
raise
#------------------------------------------------------------------------------
def interpolate_super(parser, src, dst, section, option, value):
srepl = lambda match: _super_replace(
match, parser, src, dst, section, option, value, None)
value = _super_cre.sub(srepl, value)
return value
#------------------------------------------------------------------------------
def _env_replace(match, parser, base_interpolate, section, option, rawval, vars):
if match.group(1) in os.environ:
return os.environ.get(match.group(1))
if match.group(2):
return match.group(3)
raise InterpolationMissingEnvError(option, section, rawval, match.group(1))
#------------------------------------------------------------------------------
def _super_replace(match, parser, src, dst, section, option, rawval, vars):
if dst \
and ( section == parser.IM_DEFAULTSECT or dst.has_section(section) ) \
and dst.has_option(section, option):
try:
return dst.get(section, option, raw=True, vars=vars)
except TypeError:
return dst.get(section, option)
if dst:
return match.group(0)
if match.group(1):
return match.group(2)
raise InterpolationMissingSuperError(option, section, rawval, 'SUPER')
#------------------------------------------------------------------------------
# end of $Id$
# $ChangeLog$
#------------------------------------------------------------------------------
|