Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3k
Changeset: r48022:fac760084b0d
Date: 2011-10-13 22:38 +0200
http://bitbucket.org/pypy/pypy/changeset/fac760084b0d/

Log:    The atexit module now replaces sys.exitfunc.

diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -18,7 +18,7 @@
 
 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"]))
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -330,9 +330,8 @@
 
     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)
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -57,7 +57,7 @@
 
     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):
diff --git a/pypy/module/atexit/__init__.py b/pypy/module/atexit/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/atexit/__init__.py
@@ -0,0 +1,24 @@
+"""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',
+        }
+
diff --git a/pypy/module/atexit/app_atexit.py b/pypy/module/atexit/app_atexit.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/atexit/app_atexit.py
@@ -0,0 +1,48 @@
+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)
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -94,7 +94,6 @@
         'excepthook'            : 'app.excepthook', 
         '__excepthook__'        : 'app.excepthook', 
         'exit'                  : 'app.exit', 
-        'exitfunc'              : 'app.exitfunc',
         'callstats'             : 'app.callstats',
         'copyright'             : 'app.copyright_str',
         'flags'                 : 'app.null_sysflags',
diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py
--- a/pypy/module/sys/app.py
+++ b/pypy/module/sys/app.py
@@ -56,9 +56,6 @@
     # 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():
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to