Commits

Amaury Forgeot d'Arc committed fac7600

The atexit module now replaces sys.exitfunc.

Comments (0)

Files changed (7)

pypy/config/pypyoption.py

 
 default_modules = essential_modules.copy()
 default_modules.update(dict.fromkeys(
-    ["_codecs", "gc", "_weakref", "marshal", "errno", "imp",
+    ["_codecs", "atexit", "gc", "_weakref", "marshal", "errno", "imp",
      "math", "cmath", "_sre", "_pickle_support", "operator",
      "parser", "symbol", "token", "_ast",  "_io", "_random", "__pypy__",
      "_string", "_testing"]))

pypy/interpreter/baseobjspace.py

 
     def finish(self):
         self.wait_for_thread_shutdown()
-        w_exitfunc = self.sys.getdictvalue(self, 'exitfunc')
-        if w_exitfunc is not None:
-            self.call_function(w_exitfunc)
+        w_atexit = self.getbuiltinmodule('atexit')
+        self.call_method(w_atexit, '_run_exitfuncs')
         from pypy.interpreter.module import Module
         for w_mod in self.builtin_modules.values():
             mod = self.interpclass_w(w_mod)

pypy/interpreter/module.py

 
     def shutdown(self, space):
         """This is called when the space is shut down, just after
-        sys.exitfunc(), if the module has been imported.
+        atexit functions, if the module has been imported.
         """
 
     def getdict(self, space):

pypy/module/atexit/__init__.py

+"""A _string module, to export formatter_parser and
+   formatter_field_name_split to the string.Formatter class
+   implemented in Python."""
+
+
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+    """Allow programmer to define multiple exit functions to be
+    executed upon normal program termination.
+
+    Two public functions, register and unregister, are defined.
+    """
+
+    interpleveldefs = {
+        }
+
+    appleveldefs = {
+        'register': 'app_atexit.register',
+        'unregister': 'app_atexit.unregister',
+        '_clear': 'app_atexit.clear',
+        '_run_exitfuncs': 'app_atexit.run_exitfuncs',
+        }
+

pypy/module/atexit/app_atexit.py

+atexit_callbacks = []
+
+def register(func, *args, **kwargs):
+    """Register a function to be executed upon normal program termination.
+
+    func - function to be called at exit
+    args - optional arguments to pass to func
+    kwargs - optional keyword arguments to pass to func
+
+    func is returned to facilitate usage as a decorator."""
+    
+    if not callable(func):
+        raise TypeError("func must be callable")
+
+    atexit_callbacks.append((func, args, kwargs))
+    return func
+    
+def run_exitfuncs():
+    "Run all registered exit functions."
+    # Maintain the last exception
+    last_exc, last_tb = None, None
+    for (func, args, kwargs) in atexit_callbacks:
+        if func is None:
+            # unregistered slot
+            continue
+        try:
+            func(*args, **kwargs)
+        except BaseException, e:
+            if not isinstance(e, SystemExit):
+                import traceback
+                last_type, last_exc, last_tb = sys.exc_info()
+                traceback.print_exception(last_type, last_exc, last_tb)
+
+    clear()
+
+    if last_exc is not None:
+        raise last_exc.with_traceback(last_tb)
+
+def clear():
+    "Clear the list of previously registered exit functions."
+    del atexit_callbacks[:]
+
+def unregister(func):
+    """Unregister a exit function which was previously registered using
+    atexit.register"""
+    for i, (f, _, _) in enumerate(atexit_callbacks):
+        if f == func:
+            atexit_callbacks[i] = (None, None, None)

pypy/module/sys/__init__.py

         'excepthook'            : 'app.excepthook', 
         '__excepthook__'        : 'app.excepthook', 
         'exit'                  : 'app.exit', 
-        'exitfunc'              : 'app.exitfunc',
         'callstats'             : 'app.callstats',
         'copyright'             : 'app.copyright_str',
         'flags'                 : 'app.null_sysflags',

pypy/module/sys/app.py

     # in normalize_exception, which is exactly like CPython's.
     raise SystemExit, exitcode
 
-def exitfunc():
-    """Placeholder for sys.exitfunc(), which is called when PyPy exits."""
-
 #import __builtin__
 
 def callstats():