def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    class StringSubber(object):
        """A class to construct the results of a scons_subst() call.

        This binds a specific construction environment, mode, target and
        source with two methods (substitute() and expand()) that handle
        the expansion.
        """
        def __init__(self, env, mode, conv, gvars):
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (__HOLE__, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception, e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'], s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):
                def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
                    return conv(substitute(l, lvars))
                return list(map(func, s))
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                         source=lvars['SOURCES'],
                         env=self.env,
                         for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        return s
                    s = self.conv(s)
                return self.substitute(s, lvars)
            elif s is None:
                return ''
            else:
                return s

        def substitute(self, args, lvars):
            """Substitute expansions in an argument or list of arguments.

            This serves as a wrapper for splitting up a string into
            separate tokens.
            """
            if is_String(args) and not isinstance(args, CmdStringHolder):
                args = str(args)        # In case it's a UserString.
                try:
                    def sub_match(match):
                        return self.conv(self.expand(match.group(1), lvars))
                    result = _dollar_exps.sub(sub_match, args)
                except TypeError:
                    # If the internal conversion routine doesn't return
                    # strings (it could be overridden to return Nodes, for
                    # example), then the 1.5.2 re module will throw this
                    # exception.  Back off to a slower, general-purpose
                    # algorithm that works for all data types.
                    args = _separate_args.findall(args)
                    result = []
                    for a in args:
                        result.append(self.conv(self.expand(a, lvars)))
                    if len(result) == 1:
                        result = result[0]
                    else:
                        result = ''.join(map(str, result))
                return result
            else:
                return self.expand(args, lvars)

    if conv is None:
        conv = _strconv[mode]

    # Doing this every time is a bit of a waste, since the Executor
    # has typically already populated the OverrideEnvironment with
    # $TARGET/$SOURCE variables.  We're keeping this (for now), though,
    # because it supports existing behavior that allows us to call
    # an Action directly with an arbitrary target+source pair, which
    # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
    # If we dropped that behavior (or found another way to cover it),
    # we could get rid of this call completely and just rely on the
    # Executor setting the variables.
    if 'TARGET' not in lvars:
        d = subst_dict(target, source)
        if d:
            lvars = lvars.copy()
            lvars.update(d)

    # We're (most likely) going to eval() things.  If Python doesn't
    # find a __builtins__ value in the global dictionary used for eval(),
    # it copies the current global values for you.  Avoid this by
    # setting it explicitly and then deleting, so we don't pollute the
    # construction environment Dictionary(ies) that are typically used
    # for expansion.
    gvars['__builtins__'] = __builtins__

    ss = StringSubber(env, mode, conv, gvars)
    result = ss.substitute(strSubst, lvars)

    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)

    return result

#Subst_List_Strings = {}
dataset/ETHPy150Open kayhayen/Nuitka/nuitka/build/inline_copy/lib/scons-2.3.2/SCons/Subst.py/scons_subst