Author: Richard Plangger <[email protected]> Branch: py3.5-memoryview Changeset: r86725:d3b1d21c38e2 Date: 2016-08-30 10:13 +0200 http://bitbucket.org/pypy/pypy/changeset/d3b1d21c38e2/
Log: merge py3.5 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -28,3 +28,5 @@ c09c19272c990a0611b17569a0085ad1ab00c8ff release-pypy2.7-v5.3 7e8df3df96417c16c2d55b41352ec82c9c69c978 release-pypy2.7-v5.3.1 68bb3510d8212ae9efb687e12e58c09d29e74f87 release-pypy2.7-v5.4.0 +68bb3510d8212ae9efb687e12e58c09d29e74f87 release-pypy2.7-v5.4.0 +77392ad263504df011ccfcabf6a62e21d04086d0 release-pypy2.7-v5.4.0 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -74,6 +74,7 @@ Seo Sanghyeon Ronny Pfannschmidt Justin Peel + Raffael Tfirst David Edelsohn Anders Hammarquist Jakub Gustak @@ -117,7 +118,6 @@ Wenzhu Man John Witulski Laurence Tratt - Raffael Tfirst Ivan Sichmann Freitas Greg Price Dario Bertini @@ -141,6 +141,7 @@ tav Taavi Burns Georg Brandl + Nicolas Truessel Bert Freudenberg Stian Andreassen Wanja Saatkamp @@ -211,6 +212,7 @@ Vaibhav Sood Alan McIntyre Alexander Sedov + [email protected] Attila Gobi Jasper.Schulz Christopher Pope @@ -221,6 +223,7 @@ Arjun Naik Valentina Mukhamedzhanova Stefano Parmesan + touilleMan Alexis Daboville Jens-Uwe Mager Carl Meyer @@ -229,12 +232,14 @@ Gabriel Lukas Vacek Kunal Grover + Aaron Gallagher Andrew Dalke Sylvain Thenault Jakub Stasiak Nathan Taylor Vladimir Kryachko Omer Katz + Mark Williams Jacek Generowicz Alejandro J. Cura Jacob Oscarson @@ -355,12 +360,15 @@ yasirs Michael Chermside Anna Ravencroft + pizi Andrey Churin Dan Crosta + Eli Stevens Tobias Diaz Julien Phalip Roman Podoliaka Dan Loewenherz + werat Heinrich-Heine University, Germany Open End AB (formerly AB Strakt), Sweden @@ -468,15 +476,3 @@ https://github.com/gperftools/gperftools/blob/master/COPYING -License for 'liblzma and 'lzmaffi' ----------------------------------- - -This copy of PyPy may be linked (dynamically or statically) with the -liblzma library, which was put in the "public domain": - - http://tukaani.org/xz/ - -The cffi bindings to liblzma (in lib_pypy/_lzma.py) are derived from -the lzmaffi project which is distributed under a BSD license: - - https://pypi.python.org/pypi/lzmaffi/0.3.0 diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -342,7 +342,7 @@ thisarg = cast(thisvalue, POINTER(POINTER(c_void_p))) keepalives, newargs, argtypes, outargs, errcheckargs = ( self._convert_args(argtypes, args[1:], kwargs)) - newargs.insert(0, thisvalue.value) + newargs.insert(0, thisarg) argtypes.insert(0, c_void_p) else: thisarg = None diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -44,6 +44,7 @@ Seo Sanghyeon Ronny Pfannschmidt Justin Peel + Raffael Tfirst David Edelsohn Anders Hammarquist Jakub Gustak @@ -87,7 +88,6 @@ Wenzhu Man John Witulski Laurence Tratt - Raffael Tfirst Ivan Sichmann Freitas Greg Price Dario Bertini @@ -111,6 +111,7 @@ tav Taavi Burns Georg Brandl + Nicolas Truessel Bert Freudenberg Stian Andreassen Wanja Saatkamp @@ -181,6 +182,7 @@ Vaibhav Sood Alan McIntyre Alexander Sedov + [email protected] Attila Gobi Jasper.Schulz Christopher Pope @@ -191,6 +193,7 @@ Arjun Naik Valentina Mukhamedzhanova Stefano Parmesan + touilleMan Alexis Daboville Jens-Uwe Mager Carl Meyer @@ -199,12 +202,14 @@ Gabriel Lukas Vacek Kunal Grover + Aaron Gallagher Andrew Dalke Sylvain Thenault Jakub Stasiak Nathan Taylor Vladimir Kryachko Omer Katz + Mark Williams Jacek Generowicz Alejandro J. Cura Jacob Oscarson @@ -325,9 +330,12 @@ yasirs Michael Chermside Anna Ravencroft + pizi Andrey Churin Dan Crosta + Eli Stevens Tobias Diaz Julien Phalip Roman Podoliaka Dan Loewenherz + werat diff --git a/pypy/doc/release-pypy2.7-v5.4.0.rst b/pypy/doc/release-pypy2.7-v5.4.0.rst --- a/pypy/doc/release-pypy2.7-v5.4.0.rst +++ b/pypy/doc/release-pypy2.7-v5.4.0.rst @@ -3,7 +3,8 @@ ============ We have released PyPy2.7 v5.4, a little under two months after PyPy2.7 v5.3. -This new PyPy2.7 release includes further improvements to our C-API compatability layer (cpyext), enabling us to pass over 99% of the upstream +This new PyPy2.7 release includes incremental improvements to our C-API +compatability layer (cpyext), enabling us to pass over 99% of the upstream numpy `test suite`_. We updated built-in cffi_ support to version 1.8, which now supports the "limited API" mode for c-extensions on CPython >=3.2. @@ -12,9 +13,7 @@ support to OpenBSD and Dragon Fly BSD As always, this release fixed many issues and bugs raised by the -growing community of PyPy users. - -XXXXX MORE ??? +growing community of PyPy users. We strongly recommend updating. You can download the PyPy2.7 v5.4 release here: @@ -110,8 +109,8 @@ * (RPython) add `rposix_scandir` portably, needed for Python 3.5 - * Support for memoryview attributes (format, itemsize, ...) which also - adds support for `PyMemoryView_FromObject` + * Increased but incomplete support for memoryview attributes (format, + itemsize, ...) which also adds support for `PyMemoryView_FromObject` * Bug Fixes @@ -153,10 +152,6 @@ * Make `hash(-1)` return -2, as CPython does, and fix all the ancilary places this matters - * Issues reported with our previous release were resolved_ after - reports from users on our issue tracker at - https://bitbucket.org/pypy/pypy/issues or on IRC at #pypy - * Fix `PyNumber_Check()` to behave more like CPython * (VMProf) Try hard to not miss any Python-level frame in the @@ -169,6 +164,10 @@ * Fix the mapdict cache for subclasses of builtin types that provide a dict + * Issues reported with our previous release were resolved_ after + reports from users on our issue tracker at + https://bitbucket.org/pypy/pypy/issues or on IRC at #pypy + * Performance improvements: * Add a before_call()-like equivalent before a few operations like diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -5,4 +5,5 @@ .. this is a revision shortly after release-pypy2.7-v5.4 .. startrev: 522736f816dc - +.. branch: rpython-resync +Backport rpython changes made directly on the py3k and py3.5 branches. diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py --- a/pypy/module/_sre/interp_sre.py +++ b/pypy/module/_sre/interp_sre.py @@ -13,7 +13,7 @@ # # Constants and exposed functions -from rpython.rlib.rsre import rsre_core +from rpython.rlib.rsre import rsre_core, rsre_char from rpython.rlib.rsre.rsre_char import CODESIZE, MAXREPEAT, MAXGROUPS, getlower, set_unicode_db @@ -92,6 +92,10 @@ # # SRE_Pattern class +FLAG_NAMES = ["re.TEMPLATE", "re.IGNORECASE", "re.LOCALE", "re.MULTILINE", + "re.DOTALL", "re.UNICODE", "re.VERBOSE", "re.DEBUG", + "re.ASCII"] + class W_SRE_Pattern(W_Root): _immutable_fields_ = ["code", "flags", "num_groups", "w_groupindex"] @@ -99,7 +103,44 @@ space = self.space raise oefmt(space.w_TypeError, "cannot copy this pattern object") - def make_ctx(self, w_string, pos=0, endpos=sys.maxint): + def repr_w(self): + space = self.space + u = space.unicode_w(space.repr(self.w_pattern)) + flag_items = [] + flags = self.flags + if self.is_known_unicode(): + if ((flags & (rsre_char.SRE_FLAG_LOCALE | + rsre_char.SRE_FLAG_UNICODE | + 256)) # rsre_char.SRE_FLAG_ASCII + == rsre_char.SRE_FLAG_UNICODE): + flags &= ~rsre_char.SRE_FLAG_UNICODE + for i, name in enumerate(FLAG_NAMES): + if flags & (1 << i): + flags -= (1 << i) + flag_items.append(name) + if flags != 0: + flag_items.append('0x%x' % flags) + if len(flag_items) == 0: + usep = u'' + uflags = u'' + else: + usep = u', ' + uflags = u'|'.join([item.decode('latin-1') for item in flag_items]) + return space.wrap(u're.compile(%s%s%s)' % (u, usep, uflags)) + + def is_known_bytes(self): + space = self.space + if space.is_none(self.w_pattern): + return False + return not space.isinstance_w(self.w_pattern, space.w_unicode) + + def is_known_unicode(self): + space = self.space + if space.is_none(self.w_pattern): + return False + return space.isinstance_w(self.w_pattern, space.w_unicode) + + def make_ctx(self, w_string, pos=0, endpos=sys.maxint, flags=0): """Make a StrMatchContext, BufMatchContext or a UnicodeMatchContext for searching in the given w_string object.""" space = self.space @@ -107,10 +148,10 @@ pos = 0 if endpos < pos: endpos = pos + flags = self.flags | flags if space.isinstance_w(w_string, space.w_unicode): unicodestr = space.unicode_w(w_string) - if not (space.is_none(self.w_pattern) or - space.isinstance_w(self.w_pattern, space.w_unicode)): + if self.is_known_bytes(): raise oefmt(space.w_TypeError, "can't use a bytes pattern on a string-like " "object") @@ -119,10 +160,9 @@ if endpos > len(unicodestr): endpos = len(unicodestr) return rsre_core.UnicodeMatchContext(self.code, unicodestr, - pos, endpos, self.flags) + pos, endpos, flags) elif space.isinstance_w(w_string, space.w_str): - if (not space.is_none(self.w_pattern) and - space.isinstance_w(self.w_pattern, space.w_unicode)): + if self.is_known_unicode(): raise oefmt(space.w_TypeError, "can't use a string pattern on a bytes-like " "object") @@ -132,11 +172,10 @@ if endpos > len(str): endpos = len(str) return rsre_core.StrMatchContext(self.code, str, - pos, endpos, self.flags) + pos, endpos, flags) else: buf = space.readbuf_w(w_string) - if (not space.is_none(self.w_pattern) and - space.isinstance_w(self.w_pattern, space.w_unicode)): + if self.is_known_unicode(): raise oefmt(space.w_TypeError, "can't use a string pattern on a bytes-like " "object") @@ -147,7 +186,7 @@ if endpos > size: endpos = size return rsre_core.BufMatchContext(self.code, buf, - pos, endpos, self.flags) + pos, endpos, flags) def getmatch(self, ctx, found): if found: @@ -161,6 +200,12 @@ return self.getmatch(ctx, matchcontext(self.space, ctx)) @unwrap_spec(pos=int, endpos=int) + def fullmatch_w(self, w_string, pos=0, endpos=sys.maxint): + ctx = self.make_ctx(w_string, pos, endpos) + ctx.fullmatch_only = True + return self.getmatch(ctx, matchcontext(self.space, ctx)) + + @unwrap_spec(pos=int, endpos=int) def search_w(self, w_string, pos=0, endpos=sys.maxint): ctx = self.make_ctx(w_string, pos, endpos) return self.getmatch(ctx, searchcontext(self.space, ctx)) @@ -415,10 +460,12 @@ __new__ = interp2app(SRE_Pattern__new__), __copy__ = interp2app(W_SRE_Pattern.cannot_copy_w), __deepcopy__ = interp2app(W_SRE_Pattern.cannot_copy_w), + __repr__ = interp2app(W_SRE_Pattern.repr_w), __weakref__ = make_weakref_descr(W_SRE_Pattern), findall = interp2app(W_SRE_Pattern.findall_w), finditer = interp2app(W_SRE_Pattern.finditer_w), match = interp2app(W_SRE_Pattern.match_w), + fullmatch = interp2app(W_SRE_Pattern.fullmatch_w), scanner = interp2app(W_SRE_Pattern.finditer_w), # reuse finditer() search = interp2app(W_SRE_Pattern.search_w), split = interp2app(W_SRE_Pattern.split_w), diff --git a/pypy/module/_sre/test/test_app_sre.py b/pypy/module/_sre/test/test_app_sre.py --- a/pypy/module/_sre/test/test_app_sre.py +++ b/pypy/module/_sre/test/test_app_sre.py @@ -116,6 +116,22 @@ import _sre raises(TypeError, _sre.compile, {}, 0, []) + def test_fullmatch(self): + import re + assert re.compile(r"ab*c").fullmatch("abbcdef") is None + assert re.compile(r"ab*c").fullmatch("abbc") is not None + assert re.fullmatch(r"ab*c", "abbbcdef") is None + assert re.fullmatch(r"ab*c", "abbbc") is not None + + def test_repr(self): + import re + r = re.compile(r'f(o"\d)', 0) + assert repr(r) == ( + r"""re.compile('f(o"\\d)')""") + r = re.compile(r'f(o"\d)', re.IGNORECASE|re.DOTALL|re.VERBOSE) + assert repr(r) == ( + r"""re.compile('f(o"\\d)', re.IGNORECASE|re.DOTALL|re.VERBOSE)""") + class AppTestSreMatch: spaceconfig = dict(usemodules=('array', )) diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -92,10 +92,20 @@ link_extra=link_extra, libraries=libraries) from pypy.module.imp.importing import get_so_extension - pydname = soname.new(purebasename=modname, ext=get_so_extension(space)) + ext = get_so_extension(space) + pydname = soname.new(purebasename=modname, ext=ext) soname.rename(pydname) return str(pydname) +def get_so_suffix(): + from imp import get_suffixes, C_EXTENSION + for suffix, mode, typ in get_suffixes(): + if typ == C_EXTENSION: + return suffix + else: + raise RuntimeError("This interpreter does not define a filename " + "suffix for C extensions!") + def compile_extension_module_applevel(space, modname, include_dirs=[], source_files=None, source_strings=None): """ @@ -126,13 +136,9 @@ source_strings=source_strings, compile_extra=compile_extra, link_extra=link_extra) - from imp import get_suffixes, C_EXTENSION - pydname = soname - for suffix, mode, typ in get_suffixes(): - if typ == C_EXTENSION: - pydname = soname.new(purebasename=modname, ext=suffix) - soname.rename(pydname) - break + ext = get_so_suffix() + pydname = soname.new(purebasename=modname, ext=ext) + soname.rename(pydname) return str(pydname) def freeze_refcnts(self): @@ -145,6 +151,24 @@ #state.print_refcounts() self.frozen_ll2callocations = set(ll2ctypes.ALLOCATED.values()) +class FakeSpace(object): + """Like TinyObjSpace, but different""" + def __init__(self, config): + from distutils.sysconfig import get_python_inc + self.config = config + self.include_dir = get_python_inc() + + def passthrough(self, arg): + return arg + listview = passthrough + str_w = passthrough + + def unwrap(self, args): + try: + return args.str_w(None) + except: + return args + class LeakCheckingTest(object): """Base class for all cpyext tests.""" spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array', @@ -440,21 +464,8 @@ self.imported_module_names = [] if self.runappdirect: + fake = FakeSpace(self.space.config) def interp2app(func): - from distutils.sysconfig import get_python_inc - class FakeSpace(object): - def passthrough(self, arg): - return arg - listview = passthrough - str_w = passthrough - def unwrap(self, args): - try: - return args.str_w(None) - except: - return args - fake = FakeSpace() - fake.include_dir = get_python_inc() - fake.config = self.space.config def run(*args, **kwargs): for k in kwargs.keys(): if k not in func.unwrap_spec and not k.startswith('w_'): diff --git a/pypy/module/posix/interp_scandir.py b/pypy/module/posix/interp_scandir.py --- a/pypy/module/posix/interp_scandir.py +++ b/pypy/module/posix/interp_scandir.py @@ -94,9 +94,10 @@ break # known_type = rposix_scandir.get_known_type(entry) + inode = rposix_scandir.get_inode(entry) finally: self._in_next = False - direntry = W_DirEntry(self, name, known_type) + direntry = W_DirEntry(self, name, known_type, inode) return space.wrap(direntry) @@ -122,10 +123,11 @@ class W_DirEntry(W_Root): w_path = None - def __init__(self, scandir_iterator, name, known_type): + def __init__(self, scandir_iterator, name, known_type, inode): self.space = scandir_iterator.space self.scandir_iterator = scandir_iterator self.name = name # always bytes on Posix + self.inode = inode self.flags = known_type assert known_type == (known_type & 255) # @@ -134,6 +136,10 @@ w_name = self.space.fsdecode(w_name) self.w_name = w_name + def descr_repr(self, space): + u = space.unicode_w(space.repr(self.w_name)) + return space.wrap(u"<DirEntry %s>" % u) + def fget_name(self, space): return self.w_name @@ -281,9 +287,13 @@ st = self.get_stat_or_lstat(follow_symlinks) return build_stat_result(self.space, st) + def descr_inode(self, space): + return space.wrap(self.inode) + W_DirEntry.typedef = TypeDef( 'posix.DirEntry', + __repr__ = interp2app(W_DirEntry.descr_repr), name = GetSetProperty(W_DirEntry.fget_name, doc="the entry's base filename, relative to " 'scandir() "path" argument'), @@ -294,5 +304,6 @@ is_file = interp2app(W_DirEntry.descr_is_file), is_symlink = interp2app(W_DirEntry.descr_is_symlink), stat = interp2app(W_DirEntry.descr_stat), + inode = interp2app(W_DirEntry.descr_inode), ) W_DirEntry.typedef.acceptable_as_base_class = False diff --git a/pypy/module/posix/test/test_scandir.py b/pypy/module/posix/test/test_scandir.py --- a/pypy/module/posix/test/test_scandir.py +++ b/pypy/module/posix/test/test_scandir.py @@ -157,3 +157,15 @@ def test_fdopendir_unsupported(self): posix = self.posix raises(TypeError, posix.scandir, 1234) + + def test_inode(self): + posix = self.posix + d = next(posix.scandir(self.dir1)) + assert d.name == 'file1' + ino = d.inode() + assert ino == d.stat().st_ino + + def test_repr(self): + posix = self.posix + d = next(posix.scandir(self.dir1)) + assert repr(d) == "<DirEntry 'file1'>" diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -114,6 +114,31 @@ return w_item +class W_StringIterObject(W_AbstractSeqIterObject): + """Sequence iterator specialized for string-like objects, used + for bytes.__iter__() or str.__iter__() or bytearray.__iter__(). + Needed because otherwise these methods would call the possibly + overridden __getitem__() method, which they must not. + """ + def __init__(self, w_seq, getitem_fn): + W_AbstractSeqIterObject.__init__(self, w_seq) + self.getitem_fn = getitem_fn + + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.getitem_fn(self.w_seq, space, index) + except OperationError as e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + + class W_ReverseSeqIterObject(W_Root): def __init__(self, space, w_seq, index=-1): self.w_seq = w_seq diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -75,7 +75,8 @@ return space.wrap(self._len()) def descr_iter(self, space): - return space.newseqiter(self) + from pypy.objspace.std.iterobject import W_StringIterObject + return W_StringIterObject(self, self.__class__._getitem_result) def descr_contains(self, space, w_sub): value = self._val(space) @@ -133,14 +134,15 @@ return self._getitem_result(space, index) def _getitem_result(self, space, index): + # Returns the result of 'self[index]', where index is an unwrapped int. + # Used by descr_getitem() and by descr_iter(). selfvalue = self._val(space) try: character = selfvalue[index] except IndexError: raise oefmt(space.w_IndexError, "string index out of range") from pypy.objspace.std.bytesobject import W_BytesObject - from pypy.objspace.std.bytearrayobject import W_BytearrayObject - if isinstance(self, W_BytesObject) or isinstance(self, W_BytearrayObject): + if isinstance(self, W_BytesObject): return space.wrap(ord(character)) return self._new(character) diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -432,7 +432,7 @@ class AppTestListObject(object): - spaceconfig = {"objspace.std.withliststrategies": True} # it's the default + #spaceconfig = {"objspace.std.withliststrategies": True} # it's the default def setup_class(cls): import platform @@ -1524,6 +1524,16 @@ def __iter__(self): yield "ok" assert list(U("don't see me")) == ["ok"] + # + class S(bytes): + def __getitem__(self, index): + never_called + assert list(S(b"abc")) == list(b"abc") # __getitem__ ignored + # + class U(str): + def __getitem__(self, index): + never_called + assert list(U("abc")) == list("abc") # __getitem__ ignored def test_extend_from_nonempty_list_with_subclasses(self): l = ["hi!"] @@ -1549,6 +1559,20 @@ l.extend(U("don't see me")) # assert l == ["hi!", "okT", "okL", "okL", "okS", "okU"] + # + class S(bytes): + def __getitem__(self, index): + never_called + l = [] + l.extend(S(b"abc")) + assert l == list(b"abc") # __getitem__ ignored + # + class U(str): + def __getitem__(self, index): + never_called + l = [] + l.extend(U("abc")) + assert l == list("abc") # __getitem__ ignored def test_issue1266(self): l = list(range(1)) diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py --- a/rpython/rlib/rjitlog/rjitlog.py +++ b/rpython/rlib/rjitlog/rjitlog.py @@ -430,9 +430,8 @@ def encode_merge_point(log, compressor, values): line = [] - unrolled = unrolling_iterable(values) i = 0 - for value in unrolled: + for value in values: line.append(value.encode(log,i,compressor)) i += 1 return ''.join(line) diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -623,7 +623,8 @@ class CConfig: _compilation_info_ = eci DIRENT = rffi_platform.Struct('struct dirent', - [('d_name', lltype.FixedSizeArray(rffi.CHAR, 1))] + [('d_name', lltype.FixedSizeArray(rffi.CHAR, 1)), + ('d_ino', lltype.Signed)] + [('d_type', rffi.INT)] if HAVE_D_TYPE else []) if HAVE_D_TYPE: DT_UNKNOWN = rffi_platform.ConstantInteger('DT_UNKNOWN') @@ -1159,23 +1160,18 @@ # 'flags' might be ignored. Check the result. if _WIN32: # 'flags' ignored - pread = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') - pwrite = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw') - try: - ok = CreatePipe( - pread, pwrite, lltype.nullptr(rffi.VOIDP.TO), 0) - hread = rffi.cast(rffi.INTPTR_T, pread[0]) - hwrite = rffi.cast(rffi.INTPTR_T, pwrite[0]) - finally: - lltype.free(pwrite, flavor='raw') - lltype.free(pread, flavor='raw') - if ok: - fdread = c_open_osfhandle(hread, 0) - fdwrite = c_open_osfhandle(hwrite, 1) - if not (fdread == -1 or fdwrite == -1): - return (fdread, fdwrite) - rwin32.CloseHandle(pread) - rwin32.CloseHandle(pwrite) + ralloc = lltype.scoped_alloc(rwin32.LPHANDLE.TO, 1) + walloc = lltype.scoped_alloc(rwin32.LPHANDLE.TO, 1) + with ralloc as pread, walloc as pwrite: + if CreatePipe(pread, pwrite, lltype.nullptr(rffi.VOIDP.TO), 0): + hread = pread[0] + hwrite = pwrite[0] + fdread = c_open_osfhandle(rffi.cast(rffi.INTPTR_T, hread), 0) + fdwrite = c_open_osfhandle(rffi.cast(rffi.INTPTR_T, hwrite), 1) + if not (fdread == -1 or fdwrite == -1): + return (fdread, fdwrite) + rwin32.CloseHandle(hread) + rwin32.CloseHandle(hwrite) raise WindowsError(rwin32.GetLastError_saved(), "CreatePipe failed") else: filedes = lltype.malloc(INT_ARRAY_P.TO, 2, flavor='raw') diff --git a/rpython/rlib/rposix_scandir.py b/rpython/rlib/rposix_scandir.py --- a/rpython/rlib/rposix_scandir.py +++ b/rpython/rlib/rposix_scandir.py @@ -50,3 +50,6 @@ if rposix.HAVE_D_TYPE: return rffi.getintfield(direntp, 'c_d_type') return DT_UNKNOWN + +def get_inode(direntp): + return rffi.getintfield(direntp, 'c_d_ino') diff --git a/rpython/rlib/rsre/rsre_core.py b/rpython/rlib/rsre/rsre_core.py --- a/rpython/rlib/rsre/rsre_core.py +++ b/rpython/rlib/rsre/rsre_core.py @@ -89,6 +89,7 @@ match_end = 0 match_marks = None match_marks_flat = None + fullmatch_only = False def __init__(self, pattern, match_start, end, flags): # 'match_start' and 'end' must be known to be non-negative @@ -526,9 +527,16 @@ if op == OPCODE_FAILURE: return - if (op == OPCODE_SUCCESS or - op == OPCODE_MAX_UNTIL or - op == OPCODE_MIN_UNTIL): + elif op == OPCODE_SUCCESS: + if ctx.fullmatch_only: + if ptr != ctx.end: + return # not a full match + ctx.match_end = ptr + ctx.match_marks = marks + return MATCHED_OK + + elif (op == OPCODE_MAX_UNTIL or + op == OPCODE_MIN_UNTIL): ctx.match_end = ptr ctx.match_marks = marks return MATCHED_OK @@ -551,7 +559,11 @@ # assert subpattern # <ASSERT> <0=skip> <1=back> <pattern> ptr1 = ptr - ctx.pat(ppos+1) - if ptr1 < 0 or sre_match(ctx, ppos + 2, ptr1, marks) is None: + saved = ctx.fullmatch_only + ctx.fullmatch_only = False + stop = ptr1 < 0 or sre_match(ctx, ppos + 2, ptr1, marks) is None + ctx.fullmatch_only = saved + if stop: return marks = ctx.match_marks ppos += ctx.pat(ppos) @@ -560,7 +572,12 @@ # assert not subpattern # <ASSERT_NOT> <0=skip> <1=back> <pattern> ptr1 = ptr - ctx.pat(ppos+1) - if ptr1 >= 0 and sre_match(ctx, ppos + 2, ptr1, marks) is not None: + saved = ctx.fullmatch_only + ctx.fullmatch_only = False + stop = (ptr1 >= 0 and sre_match(ctx, ppos + 2, ptr1, marks) + is not None) + ctx.fullmatch_only = saved + if stop: return ppos += ctx.pat(ppos) @@ -999,14 +1016,18 @@ elif end > length: end = length return start, end -def match(pattern, string, start=0, end=sys.maxint, flags=0): +def match(pattern, string, start=0, end=sys.maxint, flags=0, fullmatch=False): start, end = _adjust(start, end, len(string)) ctx = StrMatchContext(pattern, string, start, end, flags) + ctx.fullmatch_only = fullmatch if match_context(ctx): return ctx else: return None +def fullmatch(pattern, string, start=0, end=sys.maxint, flags=0): + return match(pattern, string, start, end, flags, fullmatch=True) + def search(pattern, string, start=0, end=sys.maxint, flags=0): start, end = _adjust(start, end, len(string)) ctx = StrMatchContext(pattern, string, start, end, flags) diff --git a/rpython/rlib/rsre/test/test_match.py b/rpython/rlib/rsre/test/test_match.py --- a/rpython/rlib/rsre/test/test_match.py +++ b/rpython/rlib/rsre/test/test_match.py @@ -272,3 +272,30 @@ r = get_code("\\{\\{((?:.*?)+)\\}\\}") match = rsre_core.match(r, "{{a}}{{b}}") assert match.group(1) == "a" + + def test_fullmatch_1(self): + r = get_code(r"ab*c") + assert not rsre_core.fullmatch(r, "abbbcdef") + assert rsre_core.fullmatch(r, "abbbc") + + def test_fullmatch_2(self): + r = get_code(r"a(b*?)") + match = rsre_core.fullmatch(r, "abbb") + assert match.group(1) == "bbb" + assert not rsre_core.fullmatch(r, "abbbc") + + def test_fullmatch_3(self): + r = get_code(r"a((bp)*?)c") + match = rsre_core.fullmatch(r, "abpbpbpc") + assert match.group(1) == "bpbpbp" + + def test_fullmatch_4(self): + r = get_code(r"a((bp)*)c") + match = rsre_core.fullmatch(r, "abpbpbpc") + assert match.group(1) == "bpbpbp" + + def test_fullmatch_assertion(self): + r = get_code(r"(?=a).b") + assert rsre_core.fullmatch(r, "ab") + r = get_code(r"(?!a)..") + assert not rsre_core.fullmatch(r, "ab") _______________________________________________ pypy-commit mailing list [email protected] https://mail.python.org/mailman/listinfo/pypy-commit
