Commits

Amaury Forgeot d'Arc committed 76f4a40 Merge

Rewrite most module specific exceptions at interp-level.
many applevel files were removed.

This also fixes the _socket issue on Windows, where it's important
that the _socket module is not imported during translation and stored
in the prebuilt sys.modules.

Comments (0)

Files changed (46)

pypy/interpreter/baseobjspace.py

 from pypy.interpreter.executioncontext import ExecutionContext, ActionFlag
 from pypy.interpreter.executioncontext import UserDelAction, FrameTraceAction
 from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import new_exception_class
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.miscutils import ThreadLocals
 from pypy.tool.cache import Cache
     def exception_issubclass_w(self, w_cls1, w_cls2):
         return self.is_true(self.issubtype(w_cls1, w_cls2))
 
+    def new_exception_class(self, *args, **kwargs):
+        "NOT_RPYTHON; convenience method to create excceptions in modules"
+        return new_exception_class(self, *args, **kwargs)
+
     # end of special support code
 
     def eval(self, expression, w_globals, w_locals, hidden_applevel=False):

pypy/interpreter/error.py

     msg = os.strerror(errno)
     w_error = space.call_function(w_type, space.wrap(errno), space.wrap(msg))
     return OperationError(w_type, w_error)
+
+def new_exception_class(space, name, w_bases=None, w_dict=None):
+    """Create a new exception type.
+    @param name: the name of the type.
+    @param w_bases: Either an exception type, or a wrapped tuple of
+                    exception types.  default is space.w_Exception.
+    @param w_dict: an optional dictionary to populate the class __dict__.
+    """
+    if '.' in name:
+        module, name = name.rsplit('.', 1)
+    else:
+        module = None
+    if w_bases is None:
+        w_bases = space.newtuple([space.w_Exception])
+    elif not space.isinstance_w(w_bases, space.w_tuple):
+        w_bases = space.newtuple([w_bases])
+    if w_dict is None:
+        w_dict = space.newdict()
+    w_exc = space.call_function(
+        space.w_type, space.wrap(name), w_bases, w_dict)
+    if module:
+        space.setattr(w_exc, space.wrap("__module__"), space.wrap(module))
+    return w_exc

pypy/interpreter/test/test_error.py

 import py, os, errno
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.error import decompose_valuefmt, get_operrcls2
-from pypy.interpreter.error import wrap_oserror
+from pypy.interpreter.error import wrap_oserror, new_exception_class
 
 
 def test_decompose_valuefmt():
     assert e.get_w_value(space) == ([SystemError], [errno.EBADF],
                                     [os.strerror(errno.EBADF)],
                                     ["test.py"])
+
+def test_new_exception(space):
+    w_error = new_exception_class(space, '_socket.error')
+    assert w_error.getname(space) == 'error'
+    assert space.str_w(space.repr(w_error)) == "<class '_socket.error'>"
+    operr = OperationError(w_error, space.wrap("message"))
+    assert operr.match(space, w_error)
+    assert operr.match(space, space.w_Exception)
+
+    # subclass of ValueError
+    w_error = new_exception_class(space, 'error', space.w_ValueError)
+    operr = OperationError(w_error, space.wrap("message"))
+    assert operr.match(space, w_error)
+    assert operr.match(space, space.w_ValueError)
+
+    # subclass of (ValueError, TypeError)
+    w_bases = space.newtuple([space.w_ValueError, space.w_TypeError])
+    w_error = new_exception_class(space, 'error', w_bases)
+    operr = OperationError(w_error, space.wrap("message"))
+    assert operr.match(space, w_error)
+    assert operr.match(space, space.w_ValueError)
+    assert operr.match(space, space.w_TypeError)
+

pypy/module/_rawffi/__init__.py

         'get_libc'           : 'interp_rawffi.get_libc',
         'get_errno'          : 'interp_rawffi.get_errno',
         'set_errno'          : 'interp_rawffi.set_errno',
+        'SegfaultException'  : 'space.new_exception_class("_rawffi.SegfaultException")',
     }
 
     if sys.platform == 'win32':
         interpleveldefs['set_last_error'] = 'interp_rawffi.set_last_error'
 
     appleveldefs = {
-        'SegfaultException'  : 'error.SegfaultException',
     }
 
     def buildloaders(cls):

pypy/module/_rawffi/error.py

-class SegfaultException(Exception):
-    pass

pypy/module/_socket/__init__.py

 class Module(MixedModule):
 
     appleveldefs = {
-        'error'      : 'app_socket.error',
-        'herror'     : 'app_socket.herror',
-        'gaierror'   : 'app_socket.gaierror',
-        'timeout'    : 'app_socket.timeout',
     }
 
     interpleveldefs = {
         'SocketType':  'interp_socket.W_RSocket',
         'socket'    :  'interp_socket.W_RSocket',
+        'error'     :  'interp_socket.get_error(space, "error")',
+        'herror'    :  'interp_socket.get_error(space, "herror")',
+        'gaierror'  :  'interp_socket.get_error(space, "gaierror")',
+        'timeout'   :  'interp_socket.get_error(space, "timeout")',
     }
 
     def startup(self, space):

pypy/module/_socket/app_socket.py

-"""Implementation module for socket operations.
-
-See the socket module for documentation."""
-
-class error(IOError):
-    pass
-
-class herror(error):
-    pass
-
-class gaierror(error):
-    pass
-
-class timeout(error):
-    pass

pypy/module/_socket/interp_socket.py

 # ____________________________________________________________
 # Error handling
 
+class SocketAPI:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class(
+            "_socket.error", space.w_IOError)
+        self.w_herror = space.new_exception_class(
+            "_socket.herror", self.w_error)
+        self.w_gaierror = space.new_exception_class(
+            "_socket.gaierror", self.w_error)
+        self.w_timeout = space.new_exception_class(
+            "_socket.timeout", self.w_error)
+
+        self.errors_w = {'error': self.w_error,
+                         'herror': self.w_herror,
+                         'gaierror': self.w_gaierror,
+                         'timeout': self.w_timeout,
+                         }
+
+    def get_exception(self, applevelerrcls):
+        return self.errors_w[applevelerrcls]
+
+def get_error(space, name):
+    return space.fromcache(SocketAPI).get_exception(name)
+
 def converted_error(space, e):
     message = e.get_msg()
-    w_module = space.getbuiltinmodule('_socket')
-    w_exception_class = space.getattr(w_module, space.wrap(e.applevelerrcls))
+    w_exception_class = get_error(space, e.applevelerrcls)
     if isinstance(e, SocketErrorWithErrno):
         w_exception = space.call_function(w_exception_class, space.wrap(e.errno),
                                       space.wrap(message))

pypy/module/_ssl/__init__.py

 from pypy.interpreter.mixedmodule import MixedModule
 
 class Module(MixedModule):
+    """Implementation module for SSL socket operations.
+    See the socket module for documentation."""
+
     interpleveldefs = {
         'sslwrap': 'interp_ssl.sslwrap',
+        'SSLError': 'interp_ssl.get_error(space)',
     }
 
     appleveldefs = {
-        '__doc__': 'app_ssl.__doc__',
-        'SSLError': 'app_ssl.SSLError',
     }
 
     @classmethod

pypy/module/_ssl/app_ssl.py

-import _socket
-
-class SSLError(_socket.error):
-    pass
-
-__doc__ = """Implementation module for SSL socket operations. 
-See the socket module for documentation."""

pypy/module/_ssl/interp_ssl.py

 constants["OPENSSL_VERSION"] = SSLEAY_VERSION
 
 def ssl_error(space, msg, errno=0):
-    w_module = space.getbuiltinmodule('_ssl')
-    w_exception_class = space.getattr(w_module, space.wrap('SSLError'))
+    w_exception_class = get_error(space)
     if errno:
         w_exception = space.call_function(w_exception_class,
                                           space.wrap(errno), space.wrap(msg))
     return space.wrap(new_sslobject(
         space, w_socket, side, w_key_file, w_cert_file))
 
+class Cache:
+    def __init__(self, space):
+        w_socketerror = interp_socket.get_error(space, "error")
+        self.w_error = space.new_exception_class(
+            "_ssl.SSLError", w_socketerror)
+
+def get_error(space):
+    return space.fromcache(Cache).w_error

pypy/module/_ssl/test/test_ssl.py

         import _ssl
     
     def test_sslerror(self):
-        import _ssl
+        import _ssl, _socket
         assert issubclass(_ssl.SSLError, Exception)
+        assert issubclass(_ssl.SSLError, IOError)
+        assert issubclass(_ssl.SSLError, _socket.error)
 
     def test_constants(self):
         import _ssl

pypy/module/binascii/__init__.py

     """binascii - Conversion between binary data and ASCII"""
 
     appleveldefs = {
-        'Error': 'app_binascii.Error',
-        'Incomplete': 'app_binascii.Incomplete',
         }
 
     interpleveldefs = {
         'hexlify': 'interp_hexlify.hexlify',
         'a2b_hex': 'interp_hexlify.unhexlify',
         'unhexlify': 'interp_hexlify.unhexlify',
+        'Error'     : 'space.fromcache(interp_binascii.Cache).w_error',
+        'Incomplete': 'space.fromcache(interp_binascii.Cache).w_incomplete',
         }

pypy/module/binascii/app_binascii.py

-
-class Error(Exception):
-    pass
-
-class Incomplete(Exception):
-    pass

pypy/module/binascii/interp_binascii.py

 from pypy.interpreter.error import OperationError
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("binascii.Error")
+        self.w_incomplete = space.new_exception_class("binascii.Incomplete")
+
 def raise_Error(space, msg):
-    w_module = space.getbuiltinmodule('binascii')
-    w_Error = space.getattr(w_module, space.wrap('Error'))
-    raise OperationError(w_Error, space.wrap(msg))
+    w_error = space.fromcache(Cache).w_error
+    raise OperationError(w_error, space.wrap(msg))
 
 def raise_Incomplete(space, msg):
-    w_module = space.getbuiltinmodule('binascii')
-    w_Error = space.getattr(w_module, space.wrap('Incomplete'))
-    raise OperationError(w_Error, space.wrap(msg))
+    w_error = space.fromcache(Cache).w_incomplete
+    raise OperationError(w_error, space.wrap(msg))

pypy/module/mmap/__init__.py

         'ACCESS_READ' : 'space.wrap(interp_mmap.ACCESS_READ)',
         'ACCESS_WRITE': 'space.wrap(interp_mmap.ACCESS_WRITE)',
         'ACCESS_COPY' : 'space.wrap(interp_mmap.ACCESS_COPY)',
-        'mmap': 'interp_mmap.W_MMap'
+        'mmap': 'interp_mmap.W_MMap',
+        'error': 'space.fromcache(interp_mmap.Cache).w_error',
     }
 
     appleveldefs = {
-        'error': 'app_mmap.error'
     }
     
     def buildloaders(cls):

pypy/module/mmap/app_mmap.py

-class error(EnvironmentError):
-    pass

pypy/module/mmap/interp_mmap.py

 ACCESS_WRITE = rmmap.ACCESS_WRITE
 ACCESS_COPY  = rmmap.ACCESS_COPY
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("mmap.error",
+                                                 space.w_EnvironmentError)
+
 def mmap_error(space, e):
-    w_module = space.getbuiltinmodule('mmap')
-    w_error = space.getattr(w_module, space.wrap('error'))
+    w_error = space.fromcache(Cache).w_error
     return wrap_oserror(space, e, w_exception_class=w_error)

pypy/module/parser/__init__.py

      applevel_name = 'parser'
 
      appleveldefs = {
-         'ParserError' : 'app_helpers.ParserError'
          }
 
      interpleveldefs = {
          'ast2tuple'    : 'pyparser.st2tuple',
          'ASTType'      : 'pyparser.STType',
          'compilest'    : 'pyparser.compilest',
-         'compileast'   : 'pyparser.compilest'
+         'compileast'   : 'pyparser.compilest',
+         'ParserError'  : 'space.new_exception_class("parser.ParserError")',
          }

pypy/module/parser/app_helpers.py

-class ParserError(Exception):
-    pass

pypy/module/parser/test/test_parser.py

                      self.m.compilest(self.m.suite("x = 4"))):
             assert isinstance(code, types.CodeType)
             assert code.co_filename == "<syntax-tree>"
+
+    def test_error(self):
+        assert repr(self.m.ParserError) == "<class 'parser.ParserError'>"

pypy/module/pyexpat/__init__.py

     "Python wrapper for Expat parser."
 
     appleveldefs = {
-        'ExpatError' : 'app_pyexpat.ExpatError',
-        'error'      : 'app_pyexpat.ExpatError',
         }
 
     interpleveldefs = {
         'XMLParserType': 'interp_pyexpat.W_XMLParserType',
         'ErrorString':   'interp_pyexpat.ErrorString',
 
+        'ExpatError':    'space.fromcache(interp_pyexpat.Cache).w_error',
+        'error':         'space.fromcache(interp_pyexpat.Cache).w_error',
+
         '__version__':   'space.wrap("85819")',
         'EXPAT_VERSION': 'interp_pyexpat.get_expat_version(space)',
         'version_info':  'interp_pyexpat.get_expat_version_info(space)',

pypy/module/pyexpat/app_pyexpat.py

-class ExpatError(Exception):
-    pass

pypy/module/pyexpat/interp_pyexpat.py

         space.wrap(XML_MINOR_VERSION),
         space.wrap(XML_MICRO_VERSION)])
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("pyexpat.ExpatError")
+
 class W_XMLParserType(Wrappable):
 
     def __init__(self, space, parser, w_intern):
         lineno = XML_GetCurrentLineNumber(self.itself)
         colno = XML_GetCurrentColumnNumber(self.itself)
         msg = "%s: line %d, column %d" % (err, lineno, colno)
-        w_module = space.getbuiltinmodule('pyexpat')
-        w_errorcls = space.getattr(w_module, space.wrap('error'))
+        w_errorcls = space.fromcache(Cache).w_error
         w_error = space.call_function(w_errorcls, space.wrap(msg))
         space.setattr(w_error, space.wrap("code"), space.wrap(code))
         space.setattr(w_error, space.wrap("offset"), space.wrap(colno))

pypy/module/select/__init__.py

 
 class Module(MixedModule):
     appleveldefs = {
-        'error': 'app_select.error',
     }
 
     interpleveldefs = {
         'poll'  : 'interp_select.poll',
         'select': 'interp_select.select',
+        'error' : 'space.fromcache(interp_select.Cache).w_error'
     }
 
     # TODO: this doesn't feel right...

pypy/module/select/app_select.py

-class error(Exception):
-    pass

pypy/module/select/interp_select.py

 
 defaultevents = rpoll.POLLIN | rpoll.POLLOUT | rpoll.POLLPRI
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("select.error")
+
 def poll(space):
     """Returns a polling object, which supports registering and
 unregistering file descriptors, and then polling them for I/O events."""
         try:
             retval = rpoll.poll(self.fddict, timeout)
         except rpoll.PollError, e:
-            w_module = space.getbuiltinmodule('select')
-            w_errortype = space.getattr(w_module, space.wrap('error'))
+            w_errortype = space.fromcache(Cache).w_error
             message = e.get_msg()
             raise OperationError(w_errortype,
                                  space.newtuple([space.wrap(e.errno),
         else:
             iwtd, owtd, ewtd = rpoll.select(iwtd, owtd, ewtd, space.float_w(w_timeout))
     except rpoll.SelectError, s:
-        w_module = space.getbuiltinmodule('select')
-        w_errortype = space.getattr(w_module, space.wrap('error'))
+        w_errortype = space.fromcache(Cache).w_error
         raise OperationError(w_errortype, space.newtuple([
             space.wrap(s.errno), space.wrap(s.get_msg())]))
     

pypy/module/signal/__init__.py

         'NSIG':                'space.wrap(interp_signal.NSIG)',
         'SIG_DFL':             'space.wrap(interp_signal.SIG_DFL)',
         'SIG_IGN':             'space.wrap(interp_signal.SIG_IGN)',
+        'default_int_handler': 'interp_signal.default_int_handler',
+        'ItimerError':         'interp_signal.get_itimer_error(space)',
     }
 
     if os.name == 'posix':
             interpleveldefs[name] = 'space.wrap(interp_signal.%s)' % (name,)
 
     appleveldefs = {
-        'default_int_handler': 'app_signal.default_int_handler',
-        'ItimerError': 'app_signal.ItimerError',
     }
 
     def buildloaders(cls):

pypy/module/signal/app_signal.py

-
-
-def default_int_handler(signum, frame):
-    """
-    default_int_handler(...)
-
-    The default handler for SIGINT installed by Python.
-    It raises KeyboardInterrupt.
-    """
-    raise KeyboardInterrupt()
-
-
-class ItimerError(IOError):
-    pass

pypy/module/signal/interp_signal.py

         return action.handlers_w[signum]
     return space.wrap(SIG_DFL)
 
+def default_int_handler(space, w_signum, w_frame):
+    """
+    default_int_handler(...)
+
+    The default handler for SIGINT installed by Python.
+    It raises KeyboardInterrupt.
+    """
+    raise OperationError(space.w_KeyboardInterrupt,
+                         space.w_None)
+
 @jit.dont_look_inside
 @unwrap_spec(timeout=int)
 def alarm(space, timeout):
     w_interval = space.wrap(double_from_timeval(val.c_it_interval))
     return space.newtuple([w_value, w_interval])
 
+class Cache:
+    def __init__(self, space):
+        self.w_itimererror = space.new_exception_class("signal.ItimerError",
+                                                       space.w_IOError)
+
 def get_itimer_error(space):
-    mod = space.getbuiltinmodule("signal")
-    return space.getattr(mod, space.wrap("ItimerError"))
+    return space.fromcache(Cache).w_itimererror
 
 @jit.dont_look_inside
 @unwrap_spec(which=int, first=float, interval=float)

pypy/module/termios/__init__.py

     sys.stdin.fileno(), or a file object, such as sys.stdin itself."
 
     appleveldefs = {
-        'error'       : 'app_termios.error',
     }
     
     interpleveldefs = {
         'tcgetattr'   : 'interp_termios.tcgetattr',
         'tcsendbreak' : 'interp_termios.tcsendbreak',
         'tcsetattr'   : 'interp_termios.tcsetattr',
+        'error'       : 'space.fromcache(interp_termios.Cache).w_error',
     }
 
 import termios

pypy/module/termios/app_termios.py

-
-class error(Exception):
-    pass

pypy/module/termios/interp_termios.py

 from pypy.rlib import rtermios
 import termios
 
-# proper semantics are to have termios.error, but since it's not documented
-# anyway, let's have it as OSError on interplevel. We need to have
-# some details what is missing in RPython modules though
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("termios.error")
 
 def convert_error(space, error):
-    w_module = space.getbuiltinmodule('termios')
-    w_exception_class = space.getattr(w_module, space.wrap('error'))
+    w_exception_class = space.fromcache(Cache).w_error
     return wrap_oserror(space, error, w_exception_class=w_exception_class)
 
 @unwrap_spec(fd=int, when=int)

pypy/module/thread/__init__.py

 
 class Module(MixedModule):
     appleveldefs = {
-        'exit':                   'app_thread.exit',
-        'exit_thread':            'app_thread.exit',   # obsolete synonym
-        'error':                  'app_thread.error',
     }
 
     interpleveldefs = {
         'start_new_thread':       'os_thread.start_new_thread',
         'start_new':              'os_thread.start_new_thread', # obsolete syn.
         'get_ident':              'os_thread.get_ident',
+        'exit':                   'os_thread.exit',
+        'exit_thread':            'os_thread.exit', # obsolete synonym
         'stack_size':             'os_thread.stack_size',
         '_count':                 'os_thread._count',
         'allocate_lock':          'os_lock.allocate_lock',
         'allocate':               'os_lock.allocate_lock',  # obsolete synonym
         'LockType':               'os_lock.getlocktype(space)',
         '_local':                 'os_local.getlocaltype(space)',
+        'error':                  'space.fromcache(error.Cache).w_error',
     }
 
     def __init__(self, space, *args):

pypy/module/thread/app_thread.py

-class error(Exception):
-    pass
-
-def exit():
-    """This is synonymous to ``raise SystemExit''.  It will cause the current
-thread to exit silently unless the exception is caught."""
-    raise SystemExit

pypy/module/thread/error.py

 from pypy.interpreter.error import OperationError
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("thread.error")
+
 def wrap_thread_error(space, msg):
-    w_module = space.getbuiltinmodule('thread')
-    w_error = space.getattr(w_module, space.wrap('error'))
+    w_error = space.fromcache(Cache).w_error
     return OperationError(w_error, space.wrap(msg))

pypy/module/thread/os_thread.py

 In most applications `threading.enumerate()` should be used instead."""
     return space.wrap(bootstrapper.nbthreads)
 
+def exit(space):
+    """This is synonymous to ``raise SystemExit''.  It will cause the current
+thread to exit silently unless the exception is caught."""
+    raise OperationError(space.w_SystemExit, space.w_None)

pypy/module/thread/test/test_fork.py

         "Checks that a forked interpreter can start a thread"
         import os, thread, time
 
+        if not hasattr(os, 'fork'):
+            skip("No fork on this platform")
+
         # pre-allocate some locks
         thread.start_new_thread(lambda: None, ())
 

pypy/module/thread/test/test_gil.py

         return True
     def getexecutioncontext(self):
         return FakeEC()
-    def getbuiltinmodule(self, name):
+    def fromcache(self, key):
         raise NotImplementedError
 
 

pypy/module/thread/test/test_thread.py

             result = sys.stderr.getvalue()
             assert "ValueError" in result
             assert "hello world" in result
+            assert len(result.splitlines()) == 1
         finally:
             sys.stderr = prev
 

pypy/module/zipimport/__init__.py

 
     interpleveldefs = {
         'zipimporter':'interp_zipimport.W_ZipImporter',
-        '_zip_directory_cache' : 'space.wrap(interp_zipimport.zip_cache)'
+        '_zip_directory_cache' : 'space.wrap(interp_zipimport.zip_cache)',
+        'ZipImportError': 'space.fromcache(interp_zipimport.Cache).w_error',
     }
 
     appleveldefs = {
-        'ZipImportError'      : 'app_zipimport.ZipImportError',
     }
 
     def setup_after_space_initialization(self):

pypy/module/zipimport/app_zipimport.py

-
-class ZipImportError(ImportError):
-    pass
-

pypy/module/zipimport/interp_zipimport.py

      (True, False, '.pyo'),
      (False, False, '.py')])
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("zipimport.ZipImportError",
+                                                 space.w_ImportError)
+
+def get_error(space):
+    return space.fromcache(Cache).w_error
+
 class W_ZipCache(Wrappable):
     def __init__(self):
         self.cache = {}
         self.filename = filename
         self.dir = dir
         self.prefix = prefix
-        self.w_ZipImportError = space.getattr(
-            space.getbuiltinmodule('zipimport'),
-            space.wrap('ZipImportError'))
 
     def getprefix(self, space):
         return space.wrap(self.prefix)
                     w_mods = space.sys.get('modules')
                 space.call_method(w_mods, 'pop', w(fullname), space.w_None)
         if last_exc:
-            raise OperationError(self.w_ZipImportError, last_exc.get_w_value(space))
+            raise OperationError(get_error(space), last_exc.get_w_value(space))
         # should never happen I think
         return space.w_None
 
                     code_w = importing.parse_source_module(
                         space, co_filename, source)
                 return space.wrap(code_w)
-        raise operationerrfmt(self.w_ZipImportError,
+        raise operationerrfmt(get_error(space),
             "Cannot find source or code for %s in %s", filename, self.name)
 
     @unwrap_spec(fullname=str)
                     found = True
         if found:
             return space.w_None
-        raise operationerrfmt(self.w_ZipImportError,
+        raise operationerrfmt(get_error(space),
             "Cannot find source for %s in %s", filename, self.name)
 
     @unwrap_spec(fullname=str)
             if self.have_modulefile(space, filename + ext):
                 return space.wrap(self.filename + os.path.sep +
                                   self.corr_zname(filename + ext))
-        raise operationerrfmt(self.w_ZipImportError,
+        raise operationerrfmt(get_error(space),
             "Cannot find module %s in %s", filename, self.name)
 
     @unwrap_spec(fullname=str)
         for _, is_package, ext in ENUMERATE_EXTS:
             if self.have_modulefile(space, filename + ext):
                 return space.wrap(is_package)
-        raise operationerrfmt(self.w_ZipImportError,
+        raise operationerrfmt(get_error(space),
             "Cannot find module %s in %s", filename, self.name)
 
     def getarchive(self, space):

pypy/module/zlib/__init__.py

         'compress': 'interp_zlib.compress',
         'decompress': 'interp_zlib.decompress',
         '__version__': 'space.wrap("1.0")',
+        'error': 'space.fromcache(interp_zlib.Cache).w_error',
         }
 
     appleveldefs = {
-        'error': 'app_zlib.error',
         }
 
 

pypy/module/zlib/app_zlib.py

-
-"""
-Application-level definitions for the zlib module.
-
-NOT_RPYTHON
-"""
-
-class error(Exception):
-    """
-    Raised by zlib operations.
-    """

pypy/module/zlib/interp_zlib.py

     return space.wrap(checksum)
 
 
+class Cache:
+    def __init__(self, space):
+        self.w_error = space.new_exception_class("zlib.error")
+
 def zlib_error(space, msg):
-    w_module = space.getbuiltinmodule('zlib')
-    w_error = space.getattr(w_module, space.wrap('error'))
+    w_error = space.fromcache(Cache).w_error
     return OperationError(w_error, space.wrap(msg))
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.