Author: mattip <[email protected]> Branch: release-2.4.x Changeset: r73359:9f425c60afdf Date: 2014-09-07 14:38 +0300 http://bitbucket.org/pypy/pypy/changeset/9f425c60afdf/
Log: merge default into branch diff --git a/pypy/doc/release-2.4.0.rst b/pypy/doc/release-2.4.0.rst --- a/pypy/doc/release-2.4.0.rst +++ b/pypy/doc/release-2.4.0.rst @@ -2,12 +2,8 @@ PyPy 2.4 - ???????? ================================================= -We're pleased to announce PyPy 2.4, a significant milestone on it's own right -and the proud parent of our recent PyPy3 and STM releases. - -XXX this sentence is confusing, refactor - -This release contains several improvements and bugfixes. +We're pleased to announce PyPy 2.4, which contains significant performance +enhancements and bug fixes. You can download the PyPy 2.4 release here: @@ -15,20 +11,20 @@ We would like to thank our donors for the continued support of the PyPy project, and for those who donate to our three sub-projects. -We've shown quite a bit of progress -but we're slowly running out of funds. +We've shown quite a bit of progress, but we're slowly running out of funds. Please consider donating more, or even better convince your employer to donate, so we can finish those projects! We would like to also point out that in September, `the Python Software Foundation`_ will `match funds`_ for any donations up to $10k! The three sub-projects are: -* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatable version - we call PyPy3 2.3.1, and are working toward a Python 3.3 compatable version +* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatible version + we call PyPy3 2.3.1, and are working toward a Python 3.3 compatible version -* `STM`_ (software transactional memory): We have release a first working version, and -continue to try out new promising paths of acheiving a fast multithreaded python +* `STM`_ (software transactional memory): We have released a first working version, + and continue to try out new promising paths of achieving a fast multithreaded Python -* `NumPy`_ which requires installation of our fork of upstream numpy, available `on bitbucket`_ +* `NumPy`_ which requires installation of our fork of upstream numpy, + available `on bitbucket`_ .. _`Py3k`: http://pypy.org/py3donate.html .. _`STM`: http://pypy.org/tmdonate2.html @@ -41,15 +37,12 @@ ============= PyPy is a very compliant Python interpreter, almost a drop-in replacement for -CPython 2.7. It's fast (`pypy 2.4 and cpython 2.7.x`_ performance comparison; -note that cpython's speed has not changed since 2.7.2) +CPython 2.7. It's fast (`pypy 2.4 and cpython 2.7.x`_ performance comparison) due to its integrated tracing JIT compiler. -XXX confusing sentence, rewrite - -This release supports x86 machines running Linux 32/64, Mac OS X 64, Windows, -and OpenBSD, -as well as newer ARM hardware (ARMv6 or ARMv7, with VFPv3) running Linux. +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows, and OpenBSD), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. While we support 32 bit python on Windows, work on the native Windows 64 bit python is still stalling, we would welcome a volunteer @@ -61,19 +54,18 @@ Highlights ========== -Benchmarks improved after internal improvements in string and +Benchmarks improved after internal enhancements in string and bytearray handling, and a major rewrite of the GIL handling. This means that external calls are now a lot faster, especially the CFFI ones. It also -means that a lot of corner cases when handling strings or bytearrays have -better performance. +means better performance in a lot of corner cases with handling strings or +bytearrays. PyPy now uses Python 2.7.8 standard library. We welcomed more than 12 new contributors, and conducted two Google -Summer of Code as well as other student projects not directly related -to Summer of Code. +Summer of Code projects, as well as other student projects not +directly related to Summer of Code. -XXX mention the work is ongoing and did not make it to 2.4? Issues reported with our previous release were fixed after reports from users on our new issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at @@ -83,8 +75,8 @@ * Reduced internal copying of bytearray operations * Tweak the internal structure of StringBuilder to speed up large string -handling, which becomes advantageous on large programs at the cost of slightly -slower small *benchmark* type programs. + handling, which becomes advantageous on large programs at the cost of slightly + slower small *benchmark* type programs. * Boost performance of thread-local variables in both unjitted and jitted code, this mostly affects errno handling on linux, which makes external calls @@ -93,7 +85,7 @@ * Move to a mixed polling and mutex GIL model that make mutli-threaded jitted code run *much* faster -* Optimize errno handling in linux +* Optimize errno handling in linux (x86 and x86-64 only) * Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy @@ -110,6 +102,9 @@ .. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html .. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved +We have further improvements on the way: rpython file handling and +usable numpy linalg compatabiity should be merged soon. + Please try it out and let us know what you think. We especially welcome success stories, we know you are using PyPy, please tell us about it! diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -29,6 +29,17 @@ space.w_None) self.startup_called = False + def _cleanup_(self): + """Called by the annotator on prebuilt Module instances. + We don't have many such modules, but for the ones that + show up, remove their __file__ rather than translate it + statically inside the executable.""" + try: + space = self.space + space.delitem(self.w_dict, space.wrap('__file__')) + except OperationError: + pass + def install(self): """NOT_RPYTHON: installs this module into space.builtin_modules""" w_mod = self.space.wrap(self) diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py --- a/pypy/interpreter/test/test_module.py +++ b/pypy/interpreter/test/test_module.py @@ -1,4 +1,5 @@ - +import py +from pypy.interpreter.error import OperationError from pypy.interpreter.module import Module class TestModule: @@ -17,6 +18,18 @@ space.raises_w(space.w_AttributeError, space.delattr, w_m, w('x')) + def test___file__(self, space): + w = space.wrap + m = Module(space, space.wrap('m')) + py.test.raises(OperationError, space.getattr, w(m), w('__file__')) + m._cleanup_() + py.test.raises(OperationError, space.getattr, w(m), w('__file__')) + space.setattr(w(m), w('__file__'), w('m.py')) + space.getattr(w(m), w('__file__')) # does not raise + m._cleanup_() + py.test.raises(OperationError, space.getattr, w(m), w('__file__')) + + class AppTest_ModuleObject: def test_attr(self): m = __import__('__builtin__') diff --git a/pypy/module/thread/test/test_thread.py b/pypy/module/thread/test/test_thread.py --- a/pypy/module/thread/test/test_thread.py +++ b/pypy/module/thread/test/test_thread.py @@ -13,18 +13,26 @@ def f(): lock.acquire() lock.release() + start = thread._count() try: try: for i in range(1000): thread.start_new_thread(f, ()) finally: lock.release() - # wait a bit to allow most threads to finish now - time.sleep(0.5) except (thread.error, MemoryError): cls.w_can_start_many_threads = space.wrap(False) else: cls.w_can_start_many_threads = space.wrap(True) + # wait a bit to allow all threads to finish now + remaining = thread._count() + retries = 0 + while remaining > start: + retries += 1 + if retries == 200: + raise Exception("the test's threads don't stop!") + time.sleep(0.2) + remaining = thread._count() def test_start_new_thread(self): import thread @@ -227,7 +235,7 @@ import signal def f(): - for x in range(5): + for x in range(40): if waiting: thread.interrupt_main() return @@ -236,7 +244,7 @@ def busy_wait(): waiting.append(None) - for x in range(10): + for x in range(50): print 'tick...', x # <-force the GIL to be released, as time.sleep(0.1) # time.sleep doesn't do non-translated waiting.pop() @@ -245,6 +253,8 @@ signal.signal(signal.SIGINT, signal.default_int_handler) for i in range(100): + print + print "loop", i waiting = [] thread.start_new_thread(f, ()) raises(KeyboardInterrupt, busy_wait) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -671,6 +671,7 @@ left, right = specialnames errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % ( symbol.replace('%', '%%'),) + seq_bug_compat = (symbol == '+' or symbol == '*') def binop_impl(space, w_obj1, w_obj2): w_typ1 = space.type(w_obj1) @@ -686,20 +687,16 @@ # __xxx__ and __rxxx__ methods where found by identity. # Note that space.is_w() is potentially not happy if one of them # is None... - if w_left_src is not w_right_src: # XXX - # -- cpython bug compatibility: see objspace/std/test/ - # -- test_unicodeobject.test_str_unicode_concat_overrides. - # -- The following handles "unicode + string subclass" by - # -- pretending that the unicode is a superclass of the - # -- string, thus giving priority to the string subclass' - # -- __radd__() method. The case "string + unicode subclass" - # -- is handled directly by add__String_Unicode(). - if symbol == '+' and space.is_w(w_typ1, space.w_unicode): - w_typ1 = space.w_basestring - # -- end of bug compatibility - if space.is_true(space.issubtype(w_typ2, w_typ1)): - if (w_left_src and w_right_src and - not space.abstract_issubclass_w(w_left_src, w_right_src) and + if w_right_src and (w_left_src is not w_right_src) and w_left_src: + # 'seq_bug_compat' is for cpython bug-to-bug compatibility: + # see objspace/std/test/test_unicodeobject.*concat_overrides + # and objspace/test/test_descrobject.*rmul_overrides. + # For cases like "unicode + string subclass". + if ((seq_bug_compat and w_typ1.flag_sequence_bug_compat + and not w_typ2.flag_sequence_bug_compat) + # the non-bug-compat part is the following check: + or space.is_true(space.issubtype(w_typ2, w_typ1))): + if (not space.abstract_issubclass_w(w_left_src, w_right_src) and not space.abstract_issubclass_w(w_typ1, w_right_src)): w_obj1, w_obj2 = w_obj2, w_obj1 w_left_impl, w_right_impl = w_right_impl, w_left_impl diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -1131,6 +1131,7 @@ reverse = interp2app(W_BytearrayObject.descr_reverse, doc=BytearrayDocstrings.reverse.__doc__), ) +W_BytearrayObject.typedef.flag_sequence_bug_compat = True init_signature = Signature(['source', 'encoding', 'errors'], None, None) init_defaults = [None, None, None] diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -951,6 +951,7 @@ _formatter_field_name_split = interp2app(W_BytesObject.descr_formatter_field_name_split), ) +W_BytesObject.typedef.flag_sequence_bug_compat = True def string_escape_encode(s, quote): diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1874,3 +1874,4 @@ insert = interp2app(W_ListObject.descr_insert), remove = interp2app(W_ListObject.descr_remove), ) +W_ListObject.typedef.flag_sequence_bug_compat = True diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py --- a/pypy/objspace/std/stdtypedef.py +++ b/pypy/objspace/std/stdtypedef.py @@ -93,6 +93,8 @@ overridetypedef=overridetypedef) if typedef is not overridetypedef: w_type.w_doc = space.wrap(typedef.doc) + if hasattr(typedef, 'flag_sequence_bug_compat'): + w_type.flag_sequence_bug_compat = typedef.flag_sequence_bug_compat w_type.lazyloaders = lazyloaders return w_type diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -244,6 +244,7 @@ count = interp2app(W_AbstractTupleObject.descr_count), index = interp2app(W_AbstractTupleObject.descr_index) ) +W_AbstractTupleObject.typedef.flag_sequence_bug_compat = True class W_TupleObject(W_AbstractTupleObject): diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -67,6 +67,7 @@ _immutable_fields_ = ["flag_heaptype", "flag_cpytype", "flag_abstract?", + "flag_sequence_bug_compat", 'needsdel', 'weakrefable', 'hasdict', @@ -104,6 +105,7 @@ w_self.flag_heaptype = False w_self.flag_cpytype = False w_self.flag_abstract = False + w_self.flag_sequence_bug_compat = False w_self.instancetypedef = overridetypedef if overridetypedef is not None: diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -1068,6 +1068,7 @@ _formatter_field_name_split = interp2app(W_UnicodeObject.descr_formatter_field_name_split), ) +W_UnicodeObject.typedef.flag_sequence_bug_compat = True def _create_list_from_unicode(value): diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py --- a/pypy/objspace/test/test_descroperation.py +++ b/pypy/objspace/test/test_descroperation.py @@ -734,6 +734,44 @@ assert X() == 'hello' + def test_sequence_rmul_overrides(self): + class oops(object): + def __rmul__(self, other): + return 42 + def __index__(self): + return 3 + assert '2' * oops() == 42 + assert [2] * oops() == 42 + assert (2,) * oops() == 42 + assert u'2' * oops() == 42 + assert bytearray('2') * oops() == 42 + assert 1000 * oops() == 42 + assert '2'.__mul__(oops()) == '222' + + def test_sequence_rmul_overrides_oldstyle(self): + class oops: + def __rmul__(self, other): + return 42 + def __index__(self): + return 3 + assert '2' * oops() == 42 + assert [2] * oops() == 42 + assert (2,) * oops() == 42 + assert u'2' * oops() == 42 + assert bytearray('2') * oops() == 42 + assert 1000 * oops() == 42 + assert '2'.__mul__(oops()) == '222' + + def test_sequence_radd_overrides(self): + class A1(list): + pass + class A2(list): + def __radd__(self, other): + return 42 + assert [2] + A1([3]) == [2, 3] + assert type([2] + A1([3])) is list + assert [2] + A2([3]) == 42 + class AppTestWithBuiltinShortcut(AppTest_Descroperation): spaceconfig = {'objspace.std.builtinshortcut': True} diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py --- a/rpython/annotator/builtin.py +++ b/rpython/annotator/builtin.py @@ -255,8 +255,8 @@ BUILTIN_ANALYZERS[original] = value -@analyzer_for(getattr(OSError.__init__, 'im_func', OSError.__init__)) -def OSError_init(s_self, *args): +@analyzer_for(getattr(EnvironmentError.__init__, 'im_func', EnvironmentError.__init__)) +def EnvironmentError_init(s_self, *args): pass try: diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py --- a/rpython/annotator/classdef.py +++ b/rpython/annotator/classdef.py @@ -438,8 +438,8 @@ # ____________________________________________________________ FORCE_ATTRIBUTES_INTO_CLASSES = { - OSError: {'errno': SomeInteger()}, - } + EnvironmentError: {'errno': SomeInteger(), 'strerror': SomeString(can_be_None=True), 'filename': SomeString(can_be_None=True)}, +} try: WindowsError diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -127,6 +127,7 @@ JC_TRACING = 0x01 JC_DONT_TRACE_HERE = 0x02 JC_TEMPORARY = 0x04 +JC_TRACING_OCCURRED= 0x08 class BaseJitCell(object): """Subclasses of BaseJitCell are used in tandem with the single @@ -160,6 +161,8 @@ JC_TRACING: we are now tracing the loop from this greenkey. We'll likely end up with a wref_procedure_token, soonish. + JC_TRACING_OCCURRED: set if JC_TRACING was set at least once. + JC_TEMPORARY: a "temporary" wref_procedure_token. It's the procedure_token of a dummy loop that simply calls back the interpreter. Used for a CALL_ASSEMBLER where the @@ -206,7 +209,7 @@ # if we have this flag, and we *had* a procedure_token but # we no longer have one, then remove me. this prevents this # JitCell from being immortal. - return self.has_seen_a_procedure_token() + return self.has_seen_a_procedure_token() # i.e. dead weakref return True # Other JitCells can be removed. # ____________________________________________________________ @@ -374,7 +377,7 @@ if cell is None: cell = JitCell(*greenargs) jitcounter.install_new_cell(hash, cell) - cell.flags |= JC_TRACING + cell.flags |= JC_TRACING | JC_TRACING_OCCURRED try: metainterp.compile_and_run_once(jitdriver_sd, *args) finally: @@ -418,9 +421,15 @@ if procedure_token is None: if cell.flags & JC_DONT_TRACE_HERE: if not cell.has_seen_a_procedure_token(): - # we're seeing a fresh JC_DONT_TRACE_HERE with no - # procedure_token. Compile now. - bound_reached(hash, cell, *args) + # A JC_DONT_TRACE_HERE, i.e. a non-inlinable function. + # If we never tried to trace it, try it now immediately. + # Otherwise, count normally. + if cell.flags & JC_TRACING_OCCURRED: + tick = jitcounter.tick(hash, increment_threshold) + else: + tick = True + if tick: + bound_reached(hash, cell, *args) return # it was an aborted compilation, or maybe a weakref that # has been freed diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -517,6 +517,8 @@ "anywhere I know, bug in asmgcc") # fish the depth extra_stack_depth = (ebp_in_caller + STACK_DEPTH_OFS).signed[0] + ll_assert((extra_stack_depth & (rffi.sizeof(lltype.Signed) - 1)) + == 0, "asmgcc: misaligned extra_stack_depth") extra_stack_depth //= rffi.sizeof(lltype.Signed) self._shape_decompressor.setjitframe(extra_stack_depth) return diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py --- a/rpython/rlib/rfile.py +++ b/rpython/rlib/rfile.py @@ -93,7 +93,7 @@ def _error(ll_file): err = c_ferror(ll_file) c_clearerr(ll_file) - raise OSError(err, os.strerror(err)) + raise IOError(err, os.strerror(err)) def _dircheck(ll_file): @@ -104,7 +104,7 @@ else: if stat.S_ISDIR(st[0]): err = errno.EISDIR - raise OSError(err, os.strerror(err)) + raise IOError(err, os.strerror(err)) def _sanitize_mode(mode): @@ -136,7 +136,7 @@ ll_file = c_fopen(ll_name, ll_mode) if not ll_file: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) finally: lltype.free(ll_mode, flavor='raw') finally: @@ -223,7 +223,7 @@ res = do_close(ll_file) if res == -1: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) return res def _check_closed(self): @@ -341,7 +341,7 @@ bytes = c_fwrite(ll_value, 1, length, self._ll_file) if bytes != length: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) finally: rffi.free_nonmovingbuffer(value, ll_value) @@ -350,7 +350,7 @@ res = c_fflush(self._ll_file) if res != 0: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) def truncate(self, arg=-1): self._check_closed() @@ -360,21 +360,21 @@ res = c_ftruncate(self.fileno(), arg) if res == -1: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) def seek(self, pos, whence=0): self._check_closed() res = c_fseek(self._ll_file, pos, whence) if res == -1: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) def tell(self): self._check_closed() res = intmask(c_ftell(self._ll_file)) if res == -1: errno = rposix.get_errno() - raise OSError(errno, os.strerror(errno)) + raise IOError(errno, os.strerror(errno)) return res def fileno(self): diff --git a/rpython/rlib/streamio.py b/rpython/rlib/streamio.py --- a/rpython/rlib/streamio.py +++ b/rpython/rlib/streamio.py @@ -900,6 +900,13 @@ return '\n'.join(result) + def readline(self): + line = self.base.readline() + limit = len(line) - 2 + if limit >= 0 and line[limit] == '\r' and line[limit + 1] == '\n': + line = line[:limit] + '\n' + return line + def tell(self): pos = self.base.tell() return pos - len(self.lfbuffer) diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py --- a/rpython/rlib/test/test_rfile.py +++ b/rpython/rlib/test/test_rfile.py @@ -25,61 +25,67 @@ f.close() f() + assert open(fname, "r").read() == "dupa" self.interpret(f, []) assert open(fname, "r").read() == "dupa" def test_open_errors(self): - def f(exc): - def g(run): - try: - open('zzz', 'badmode') - except ValueError: - pass + def f(run): + try: + open('zzz', 'badmode') + except ValueError: + pass + else: + assert False + + try: + open('zzz') + except IOError as e: + assert e.errno == errno.ENOENT + else: + assert False + + try: + open('.') + except IOError as e: + if os.name == 'posix': + assert e.errno == errno.EISDIR else: - assert False + assert e.errno == errno.EACCES + else: + assert False - try: - open('zzz') - except exc as e: - assert e.errno == errno.ENOENT - else: - assert False + try: + os.fdopen(42, "badmode") + except ValueError: + pass + else: + assert False - try: - open('.') - except exc as e: - if os.name == 'posix': + try: + fd = os.open('.', os.O_RDONLY, 0777) + except OSError as e: + assert os.name == 'nt' and e.errno == errno.EACCES + else: + assert os.name != 'nt' + if run: + try: + os.fdopen(fd) + except IOError as e: assert e.errno == errno.EISDIR else: - assert e.errno == errno.EACCES - else: - assert False + assert False + os.close(fd) - try: - os.fdopen(42, "badmode") - except ValueError: - pass - else: - assert False + try: + os.fdopen(12345) + except OSError as e: + assert e.errno == errno.EBADF + else: + assert False - try: - fd = os.open('.', os.O_RDONLY, 0777) - except OSError as e: - assert os.name == 'nt' and e.errno == errno.EACCES - else: - assert os.name != 'nt' - if run: - try: - os.fdopen(fd) - except exc as e: - assert e.errno == errno.EISDIR - else: - assert False - os.close(fd) - return g - - f(IOError)(sys.version_info >= (2, 7, 9)) - self.interpret(f(OSError), [True]) + f(sys.version_info >= (2, 7, 9)) + self.interpret(f, [True]) @py.test.mark.skipif("sys.platform == 'win32'") # http://msdn.microsoft.com/en-us/library/86cebhfs.aspx @@ -120,6 +126,12 @@ def f(): f = open(fname, "w") + try: + f.read() + except IOError as e: + pass + else: + assert False f.write("dupa\x00dupb") f.close() for mode in ['r', 'U']: @@ -162,6 +174,7 @@ assert d == "a" assert e == "" + f() self.interpret(f, []) def test_seek(self): @@ -172,6 +185,12 @@ f.write("xxx") f.seek(0) assert f.read() == "xxx" + try: + f.seek(0, 42) + except IOError as e: + assert e.errno == errno.EINVAL + else: + assert False f.close() f() @@ -214,6 +233,8 @@ finally: f.close() + res = f() + assert res > 2 res = self.interpret(f, []) assert res > 2 @@ -228,6 +249,8 @@ finally: f.close() + res = f() + assert res == 3 res = self.interpret(f, []) assert res == 3 @@ -243,6 +266,7 @@ f2.close() f.close() + f() self.interpret(f, []) def test_truncate(self): diff --git a/rpython/rtyper/exceptiondata.py b/rpython/rtyper/exceptiondata.py --- a/rpython/rtyper/exceptiondata.py +++ b/rpython/rtyper/exceptiondata.py @@ -44,13 +44,6 @@ classdef = bk.getuniqueclassdef(cls) rclass.getclassrepr(rtyper, classdef).setup() - def make_raise_OSError(self, rtyper): - # ll_raise_OSError(errno) - def ll_raise_OSError(errno): - raise OSError(errno, None) - helper_fn = rtyper.annotate_helper_fn(ll_raise_OSError, [annmodel.SomeInteger()]) - return helper_fn - def get_standard_ll_exc_instance(self, rtyper, clsdef): from rpython.rtyper.lltypesystem.rclass import getinstancerepr r_inst = getinstancerepr(rtyper, clsdef) @@ -69,7 +62,6 @@ # create helper functionptrs self.fn_exception_match = self.make_exception_matcher(rtyper) self.fn_type_of_exc_inst = self.make_type_of_exc_inst(rtyper) - self.fn_raise_OSError = self.make_raise_OSError(rtyper) def make_exception_matcher(self, rtyper): # ll_exception_matcher(real_exception_vtable, match_exception_vtable) diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -441,12 +441,8 @@ extraargs = () typer = self.llinterpreter.typer exdata = typer.exceptiondata - if isinstance(exc, OSError): - self.op_direct_call(exdata.fn_raise_OSError, exc.errno) - assert False, "op_direct_call above should have raised" - else: - evalue = exdata.get_standard_ll_exc_instance_by_class(exc.__class__) - etype = self.op_direct_call(exdata.fn_type_of_exc_inst, evalue) + evalue = exdata.get_standard_ll_exc_instance_by_class(exc.__class__) + etype = self.op_direct_call(exdata.fn_type_of_exc_inst, evalue) raise LLException(etype, evalue, *extraargs) def invoke_callable_with_pyexceptions(self, fptr, *args): diff --git a/rpython/rtyper/rbuiltin.py b/rpython/rtyper/rbuiltin.py --- a/rpython/rtyper/rbuiltin.py +++ b/rpython/rtyper/rbuiltin.py @@ -3,9 +3,10 @@ from rpython.rlib import rarithmetic, objectmodel from rpython.rtyper import raddress, rptr, extregistry, rrange from rpython.rtyper.error import TyperError -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass +from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rstr from rpython.rtyper.lltypesystem.rdict import rtype_r_dict from rpython.rtyper.rmodel import Repr +from rpython.rtyper.rstr import AbstractStringRepr from rpython.tool.pairtype import pairtype @@ -264,16 +265,21 @@ def rtype_object__init__(hop): hop.exception_cannot_occur() -def rtype_OSError__init__(hop): +def rtype_EnvironmentError__init__(hop): hop.exception_cannot_occur() - if hop.nb_args == 2: - raise TyperError("OSError() should not be called with " - "a single argument") + v_self = hop.args_v[0] + r_self = hop.args_r[0] + if hop.nb_args >= 2: + v_errno = hop.inputarg(lltype.Signed, arg=1) + else: + v_errno = hop.inputconst(lltype.Signed, 0) + r_self.setfield(v_self, 'errno', v_errno, hop.llops) if hop.nb_args >= 3: - v_self = hop.args_v[0] - r_self = hop.args_r[0] - v_errno = hop.inputarg(lltype.Signed, arg=1) - r_self.setfield(v_self, 'errno', v_errno, hop.llops) + v_strerror = hop.inputarg(rstr.string_repr, arg=2) + r_self.setfield(v_self, 'strerror', v_strerror, hop.llops) + if hop.nb_args >= 4: + v_filename = hop.inputarg(rstr.string_repr, arg=3) + r_self.setfield(v_self, 'filename', v_filename, hop.llops) def rtype_WindowsError__init__(hop): hop.exception_cannot_occur() @@ -333,8 +339,8 @@ original = getattr(__builtin__, name[14:]) BUILTIN_TYPER[original] = value -BUILTIN_TYPER[getattr(OSError.__init__, 'im_func', OSError.__init__)] = ( - rtype_OSError__init__) +BUILTIN_TYPER[getattr(EnvironmentError.__init__, 'im_func', EnvironmentError.__init__)] = ( + rtype_EnvironmentError__init__) try: WindowsError diff --git a/rpython/rtyper/test/test_exception.py b/rpython/rtyper/test/test_exception.py --- a/rpython/rtyper/test/test_exception.py +++ b/rpython/rtyper/test/test_exception.py @@ -36,14 +36,53 @@ class TestException(BaseRtypingTest): def test_exception_with_arg(self): def g(n): - raise OSError(n, "?") + raise IOError(n) + def h(n): + raise OSError(n, "?", None) + def i(n): + raise EnvironmentError(n, "?", "test") + def j(n): + raise IOError(0, "test") + def k(n): + raise OSError def f(n): try: g(n) + except IOError, e: + assert e.errno == 42 + assert e.strerror is None + assert e.filename is None + else: + assert False + try: + h(n) except OSError, e: - return e.errno - res = self.interpret(f, [42]) - assert res == 42 + assert e.errno == 42 + assert e.strerror == "?" + assert e.filename is None + else: + assert False + try: + i(n) + except EnvironmentError as e: + assert e.errno == 42 + assert e.strerror == "?" + assert e.filename == "test" + else: + assert False + try: + j(n) + except (IOError, OSError) as e: + assert e.errno == 0 + assert e.strerror == "test" + assert e.filename is None + try: + k(n) + except EnvironmentError as e: + assert e.errno == 0 + assert e.strerror is None + assert e.filename is None + self.interpret(f, [42]) def test_catch_incompatible_class(self): class MyError(Exception): diff --git a/rpython/translator/c/extfunc.py b/rpython/translator/c/extfunc.py --- a/rpython/translator/c/extfunc.py +++ b/rpython/translator/c/extfunc.py @@ -90,7 +90,6 @@ yield ('RPYTHON_EXCEPTION_MATCH', exceptiondata.fn_exception_match) yield ('RPYTHON_TYPE_OF_EXC_INST', exceptiondata.fn_type_of_exc_inst) - yield ('RPYTHON_RAISE_OSERROR', exceptiondata.fn_raise_OSError) yield ('RPyExceptionOccurred1', exctransformer.rpyexc_occured_ptr.value) yield ('RPyFetchExceptionType', exctransformer.rpyexc_fetch_type_ptr.value) _______________________________________________ pypy-commit mailing list [email protected] https://mail.python.org/mailman/listinfo/pypy-commit
