NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

xreload.py (7439B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\codereload\xreload.py
      2 import collections
      3 import gc
      4 import imp
      5 import logging
      6 import marshal
      7 import sys
      8 import types
      9 import weakref
     10 log = logging.getLogger(__name__)
     11 
     12 def _expressyourself(obj):
     13     try:
     14         return obj.__class__
     15     except AttributeError:
     16         return type(obj)
     17 
     18 
     19 def _safestr(obj):
     20     try:
     21         return str(obj)
     22     except Exception:
     23         pass
     24 
     25     try:
     26         return repr(obj)
     27     except Exception as ex:
     28         expressedobj = _expressyourself(obj)
     29         log.warn('Error converting to str. Type: %s Error: %r', expressedobj, ex)
     30         return '<REPR ERROR> (%s)' % expressedobj
     31 
     32 
     33 def xreload(mod, code = None):
     34     modns = mod.__dict__
     35     if not code:
     36         modname = mod.__name__
     37         i = modname.rfind('.')
     38         if i >= 0:
     39             pkgname, modname = modname[:i], modname[i + 1:]
     40         else:
     41             pkgname = None
     42         if pkgname:
     43             pkg = sys.modules[pkgname]
     44             path = pkg.__path__
     45         else:
     46             pkg = None
     47             path = None
     48         stream, filename, (suffix, mode, kind) = imp.find_module(modname, path)
     49         try:
     50             if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
     51                 return reload(mod)
     52             if kind == imp.PY_SOURCE:
     53                 source = stream.read() + '\n'
     54                 code = compile(source, filename, 'exec')
     55             else:
     56                 code = marshal.load(stream)
     57         finally:
     58             if stream:
     59                 stream.close()
     60 
     61     tmpns = modns.copy()
     62     log.debug('Moving over the following objects: %s', tmpns.keys())
     63     modns.clear()
     64     preload = ['__name__',
     65      '__file__',
     66      '__path__',
     67      '__package__',
     68      '__loader__',
     69      '__doc__']
     70     for name in preload:
     71         if name in tmpns:
     72             modns[name] = tmpns[name]
     73 
     74     try:
     75         exec code in modns
     76     except Exception:
     77         log.exception('Failed to reload module')
     78         for name, value in tmpns.iteritems():
     79             modns[name] = value
     80 
     81         return mod
     82 
     83     for name, ob in tmpns.items():
     84         if isinstance(ob, types.ModuleType):
     85             modns[name] = ob
     86 
     87     oldnames = set(tmpns)
     88     newnames = set(modns)
     89     for name in oldnames & newnames:
     90         log.debug('Assigning over %s: %s', name, _safestr(modns[name])[:160])
     91         modns[name] = _update(tmpns[name], modns[name])
     92 
     93     log.debug('Module already had: %s', oldnames - newnames)
     94     log.debug('Module has now: %s', mod.__dict__.keys())
     95     process_deferred_reference_updates()
     96     if hasattr(mod, '__reload_update__'):
     97         mod.__reload_update__(tmpns)
     98     return mod
     99 
    100 
    101 def _update(oldobj, newobj):
    102     if oldobj is newobj:
    103         return newobj
    104     if type(oldobj) is not type(newobj):
    105         return newobj
    106     if hasattr(newobj, '__reload_update__'):
    107         return newobj.__reload_update__(oldobj)
    108     if isinstance(newobj, types.ClassType):
    109         return _update_class(oldobj, newobj)
    110     if isinstance(newobj, types.TypeType):
    111         return _update_class(oldobj, newobj)
    112     if isinstance(newobj, types.FunctionType):
    113         return _update_function(oldobj, newobj)
    114     if isinstance(newobj, types.MethodType):
    115         return _update_method(oldobj, newobj)
    116     if isinstance(newobj, classmethod):
    117         return _update_classmethod(oldobj, newobj)
    118     if isinstance(newobj, staticmethod):
    119         return _update_staticmethod(oldobj, newobj)
    120     return newobj
    121 
    122 
    123 def _update_function(oldfunc, newfunc):
    124     oldfunc.__doc__ = newfunc.__doc__
    125     oldfunc.__dict__.update(newfunc.__dict__)
    126     oldfunc.__defaults__ = newfunc.__defaults__
    127     if oldfunc.__closure__ != newfunc.__closure__:
    128         update_global_references(oldfunc, newfunc)
    129         return newfunc
    130     if oldfunc.__code__ != newfunc.__code__:
    131         try:
    132             oldfunc.__code__ = newfunc.__code__
    133         except ValueError:
    134             update_global_references(oldfunc, newfunc)
    135             return newfunc
    136 
    137     update_global_references(newfunc, oldfunc)
    138     return oldfunc
    139 
    140 
    141 def _update_method(oldmeth, newmeth):
    142     _update(oldmeth.__func__, newmeth.__func__)
    143     return oldmeth
    144 
    145 
    146 def _update_class(oldclass, newclass):
    147     olddict = oldclass.__dict__
    148     newdict = newclass.__dict__
    149     oldnames = set(olddict)
    150     newnames = set(newdict)
    151     modified_bases = []
    152     for new_base in newclass.__bases__:
    153         for old_base in oldclass.__bases__:
    154             if old_base is new_base or old_base.__name__ == new_base.__name__:
    155                 modified_bases.append(old_base)
    156                 break
    157         else:
    158             modified_bases.append(new_base)
    159 
    160     oldclass.__bases__ = tuple(modified_bases)
    161     restricted_names = set(['__dict__', '__doc__'])
    162     for name in newnames - oldnames - restricted_names:
    163         setattr(oldclass, name, newdict[name])
    164 
    165     for name in oldnames - newnames - restricted_names:
    166         delattr(oldclass, name)
    167 
    168     for name in oldnames & newnames - restricted_names:
    169         try:
    170             setattr(oldclass, name, _update(olddict[name], newdict[name]))
    171         except AttributeError:
    172             log.exception('Ignoring exception')
    173 
    174     deferred_update_global_references(newclass, oldclass)
    175     return oldclass
    176 
    177 
    178 def _update_classmethod(oldcm, newcm):
    179     _update(oldcm.__get__(0), newcm.__get__(0))
    180     return oldcm
    181 
    182 
    183 def _update_staticmethod(oldsm, newsm):
    184     _update(oldsm.__get__(0), newsm.__get__(0))
    185     return oldsm
    186 
    187 
    188 _deferred_reference_updates = {}
    189 
    190 def deferred_update_global_references(oldobj, newobj):
    191     global _deferred_reference_updates
    192     _deferred_reference_updates[oldobj] = newobj
    193 
    194 
    195 def process_deferred_reference_updates():
    196     while _deferred_reference_updates:
    197         oldobj, newobj = _deferred_reference_updates.popitem()
    198         update_global_references(oldobj, newobj, ignore=_deferred_reference_updates)
    199 
    200 
    201 def update_global_references(oldobj, newobj, ignore = None):
    202     _update_weak_references(oldobj, newobj)
    203     _update_references(oldobj, newobj, ignore=ignore)
    204 
    205 
    206 def _update_references(oldobj, newobj, ignore = None):
    207     referrers = gc.get_referrers(oldobj)
    208     for referrer in referrers:
    209         try:
    210             if ignore and referrer in ignore:
    211                 continue
    212         except TypeError:
    213             continue
    214 
    215         if isinstance(referrer, collections.MutableMapping):
    216             for k, v in referrer.items():
    217                 if v is oldobj:
    218                     referrer[k] = newobj
    219 
    220         elif isinstance(referrer, collections.MutableSequence):
    221             for i in xrange(len(referrer)):
    222                 if referrer[i] is oldobj:
    223                     referrer[i] = newobj
    224 
    225         elif isinstance(referrer, collections.MutableSet):
    226             referrer.remove(oldobj)
    227             referrer.add(newobj)
    228         elif isinstance(referrer, tuple):
    229             new_tuple = tuple(((x if x is not oldobj else newobj) for x in referrer))
    230             _update_references(referrer, new_tuple, ignore=[referrers])
    231             _update_weak_references(referrer, new_tuple)
    232 
    233 
    234 def _update_weak_references(old_obj, new_obj):
    235     weak_refs = list(weakref.getweakrefs(old_obj))
    236     if len(weak_refs) == 0:
    237         return
    238     old_ref = weak_refs.pop()
    239     while len(weak_refs) > 0:
    240         new_ref = weakref.ref(new_obj)
    241         _update_references(old_ref, new_ref, ignore=[weak_refs])
    242         try:
    243             old_ref = weak_refs.pop()
    244         except Exception:
    245             pass