def dynamic_exec(code, resolve, assign=None, delete=None, automatic_builtins=True,
                 filename=None, module_name=None, _type='exec'):
  """
  Transforms the Python source code *code* and evaluates it so that the
  *resolve* and *assign* functions are called respectively for when a global
  variable is access or assigned.

  If *resolve* is a mapping, *assign* must be omitted. #KeyError#s raised by
  the mapping are automatically converted to #NameError#s.

  Otherwise, *resolve* and *assign* must be callables that have the same
  interface as `__getitem__()`, and `__setitem__()`. If *assign* is omitted
  in that case, assignments will be redirected to a separate dictionary and
  keys in that dictionary will be checked before continuing with the *resolve*
  callback.
  """

  parse_filename = filename or '<string>'
  ast_node = transform(ast.parse(code, parse_filename, mode=_type))
  code = compile(ast_node, parse_filename, _type)
  if hasattr(resolve, '__getitem__'):
    if assign is not None:
      raise TypeError('"assign" parameter specified where "resolve" is a mapping')
    if delete is not None:
      raise TypeError('"delete" parameter specified where "resolve" is a mapping')
    input_mapping = resolve

    def resolve(x):
      try:
        return input_mapping[x]
      except KeyError:
        raise NameError(x)

    assign = input_mapping.__setitem__

    delete = input_mapping.__delitem__
  else:
    input_mapping = False

  class DynamicMapping(object):
    _data = {}
    _deleted = set()
    def __repr__(self):
      if input_mapping:
        return 'DynamicMapping({!r})'.format(input_mapping)
      else:
        return 'DynamicMapping(resolve={!r}, assign={!r})'.format(resolve, assign)
    def __getitem__(self, key):
      if key in self._deleted:
        raise NameError(key)
      if assign is None:
        try:
          return self._data[key]
        except KeyError:
          pass  # Continue with resolve()
      try:
        return resolve(key)
      except NameError as exc:
        if automatic_builtins and not key.startswith('_'):
          try:
            return getattr(builtins, key)
          except AttributeError:
            pass
        raise exc
    def __setitem__(self, key, value):
      self._deleted.discard(key)
      if assign is None:
        self._data[key] = value
      else:
        assign(key, value)
    def __delitem__(self, key):
      if delete is None:
        self._deleted.add(key)
      else:
        delete(key)
    def get(self, key, default=None):
      try:
        return self[key]
      except NameError:
        return default

  mapping = DynamicMapping()
  globals_ = {'__dict__': mapping}

  if filename:
    mapping['__file__'] = filename
    globals_['__file__'] = filename

  if module_name:
    mapping['__name__'] = module_name
    globals_['__name__'] = module_name

  return (exec_ if _type == 'exec' else eval)(code, globals_)
def dynamic_exec ( code , resolve , assign = None , delete = None , automatic_builtins = True , filename = None , module_name = None , _type = 'exec' ) : parse_filename = filename or '<string>' ast_node = transform ( ast . parse ( code , parse_filename , mode = _type ) ) code = compile ( ast_node , parse_filename , _type ) if hasattr ( resolve , '__getitem__' ) : if assign is not None : raise TypeError ( '"assign" parameter specified where "resolve" is a mapping' ) if delete is not None : raise TypeError ( '"delete" parameter specified where "resolve" is a mapping' ) input_mapping = resolve def resolve ( x ) : try : return input_mapping [ x ] except KeyError : raise NameError ( x ) assign = input_mapping . __setitem__ delete = input_mapping . __delitem__ else : input_mapping = False class DynamicMapping ( object ) : _data = { } _deleted = set ( ) def __repr__ ( self ) : if input_mapping : return 'DynamicMapping({!r})' . format ( input_mapping ) else : return 'DynamicMapping(resolve={!r}, assign={!r})' . format ( resolve , assign ) def __getitem__ ( self , key ) : if key in self . _deleted : raise NameError ( key ) if assign is None : try : return self . _data [ key ] except KeyError : pass try : return resolve ( key ) except NameError as exc : if automatic_builtins and not key . startswith ( '_' ) : try : return getattr ( builtins , key ) except AttributeError : pass raise exc def __setitem__ ( self , key , value ) : self . _deleted . discard ( key ) if assign is None : self . _data [ key ] = value else : assign ( key , value ) def __delitem__ ( self , key ) : if delete is None : self . _deleted . add ( key ) else : delete ( key ) def get ( self , key , default = None ) : try : return self [ key ] except NameError : return default mapping = DynamicMapping ( ) globals_ = { '__dict__' : mapping } if filename : mapping [ '__file__' ] = filename globals_ [ '__file__' ] = filename if module_name : mapping [ '__name__' ] = module_name globals_ [ '__name__' ] = module_name return ( exec_ if _type == 'exec' else eval ) ( code , globals_ )
Transforms the Python source code *code* and evaluates it so that the
  *resolve* and *assign* functions are called respectively for when a global
  variable is access or assigned.

  If *resolve* is a mapping, *assign* must be omitted. #KeyError#s raised by
  the mapping are automatically converted to #NameError#s.

  Otherwise, *resolve* and *assign* must be callables that have the same
  interface as `__getitem__()`, and `__setitem__()`. If *assign* is omitted
  in that case, assignments will be redirected to a separate dictionary and
  keys in that dictionary will be checked before continuing with the *resolve*
  callback.