[pypy-commit] pypy release-pypy3.5-v5.9.x: merge py3.5
fijal
pypy.commits at gmail.com
Thu Dec 21 04:05:11 EST 2017
Author: fijal
Branch: release-pypy3.5-v5.9.x
Changeset: r93528:067f612e97ae
Date: 2017-12-21 11:04 +0200
http://bitbucket.org/pypy/pypy/changeset/067f612e97ae/
Log: merge py3.5
diff --git a/lib-python/3/ssl.py b/lib-python/3/ssl.py
--- a/lib-python/3/ssl.py
+++ b/lib-python/3/ssl.py
@@ -140,6 +140,23 @@
except NameError:
_SSLv2_IF_EXISTS = None
+
+
+
+import os
+class DirEntry:
+ def __init__(self, path, name):
+ self.path = os.path.join(path, name)
+ self.name = name
+ def is_dir(self):
+ return os.path.isdir(self.path)
+def myscandir(path='.'):
+ for name in os.listdir(path):
+ yield DirEntry(path, name)
+os.scandir = myscandir
+
+
+
if sys.platform == "win32":
from _ssl import enum_certificates, enum_crls
diff --git a/lib-python/3/subprocess.py b/lib-python/3/subprocess.py
--- a/lib-python/3/subprocess.py
+++ b/lib-python/3/subprocess.py
@@ -1560,7 +1560,7 @@
'copyfile' in caller.f_globals):
dest_dir = sys.pypy_resolvedirof(target_executable)
src_dir = sys.pypy_resolvedirof(sys.executable)
- for libname in ['libpypy3-c.so', 'libpypy3-c.dylib']:
+ for libname in ['libpypy3-c.so', 'libpypy3-c.dylib', 'libpypy3-c.dll']:
dest_library = os.path.join(dest_dir, libname)
src_library = os.path.join(src_dir, libname)
if os.path.exists(src_library):
diff --git a/lib_pypy/_cffi_ssl/_stdssl/__init__.py b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
--- a/lib_pypy/_cffi_ssl/_stdssl/__init__.py
+++ b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
@@ -20,9 +20,15 @@
SSL_ERROR_EOF, SSL_ERROR_NO_SOCKET, SSL_ERROR_INVALID_ERROR_CODE,
pyerr_write_unraisable)
from _cffi_ssl._stdssl import error
-from select import poll, POLLIN, POLLOUT, select
+from select import select
from enum import IntEnum as _IntEnum
+if sys.platform == 'win32':
+ HAVE_POLL = False
+else:
+ from select import poll, POLLIN, POLLOUT
+ HAVE_POLL = True
+
OPENSSL_VERSION = ffi.string(lib.OPENSSL_VERSION_TEXT).decode('utf-8')
OPENSSL_VERSION_NUMBER = lib.OPENSSL_VERSION_NUMBER
ver = OPENSSL_VERSION_NUMBER
@@ -158,8 +164,6 @@
def _monotonic_clock():
return time.clock_gettime(time.CLOCK_MONOTONIC)
-HAVE_POLL = True
-
def _ssl_select(sock, writing, timeout):
if HAVE_POLL:
p = poll()
diff --git a/lib_pypy/_ssl/__init__.py b/lib_pypy/_ssl/__init__.py
--- a/lib_pypy/_ssl/__init__.py
+++ b/lib_pypy/_ssl/__init__.py
@@ -14,3 +14,14 @@
# RAND_egd is optional and might not be available on e.g. libressl
if hasattr(_stdssl, 'RAND_egd'):
RAND_egd = builtinify(RAND_egd)
+
+import sys
+if sys.platform == "win32" and 'enum_certificates' not in globals():
+ def enum_certificates(*args, **kwds):
+ import warnings
+ warnings.warn("ssl.enum_certificates() is not implemented")
+ return []
+ def enum_crls(*args, **kwds):
+ import warnings
+ warnings.warn("ssl.enum_crls() is not implemented")
+ return []
diff --git a/lib_pypy/faulthandler.py b/lib_pypy/faulthandler.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/faulthandler.py
@@ -0,0 +1,3 @@
+# This is only imported for platforms where the built-in faulthandler module is not
+# available. It provides no function at all so far, but it is enough to start the
+# CPython test suite.
\ No newline at end of file
diff --git a/pypy/doc/whatsnew-pypy3-head.rst b/pypy/doc/whatsnew-pypy3-head.rst
--- a/pypy/doc/whatsnew-pypy3-head.rst
+++ b/pypy/doc/whatsnew-pypy3-head.rst
@@ -16,3 +16,6 @@
Download and patch dependencies when building cffi-based stdlib modules
.. branch: os_lockf
+
+.. branch: py3.5-xattr
+Add posix.*attr() functions
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -4,7 +4,7 @@
The bytecode interpreter itself is implemented by the PyFrame class.
"""
-import imp, struct, types, new, sys, os
+import imp, struct, types, sys, os
from pypy.interpreter import eval
from pypy.interpreter.signature import Signature
@@ -80,7 +80,7 @@
class PyCode(eval.Code):
"CPython-style code objects."
_immutable_fields_ = ["_signature", "co_argcount", "co_kwonlyargcount", "co_cellvars[*]",
- "co_code", "co_consts_w[*]", "co_filename",
+ "co_code", "co_consts_w[*]", "co_filename", "w_filename",
"co_firstlineno", "co_flags", "co_freevars[*]",
"co_lnotab", "co_names_w[*]", "co_nlocals",
"co_stacksize", "co_varnames[*]",
@@ -111,6 +111,7 @@
assert isinstance(filename, str)
rstring.check_str0(filename)
self.co_filename = filename
+ self.w_filename = space.newfilename(filename)
self.co_name = name
self.co_firstlineno = firstlineno
self.co_lnotab = lnotab
@@ -203,6 +204,7 @@
if lastdirname:
basename = '%s/%s' % (lastdirname, basename)
self.co_filename = '<builtin>/%s' % (basename,)
+ self.w_filename = self.space.newfilename(self.co_filename)
co_names = property(lambda self: [self.space.str_w(w_name) for w_name in self.co_names_w]) # for trace
@@ -427,7 +429,7 @@
space.newtuple(self.co_consts_w),
space.newtuple(self.co_names_w),
space.newtuple([space.newtext(v) for v in self.co_varnames]),
- space.newtext(self.co_filename),
+ self.w_filename,
space.newtext(self.co_name),
space.newint(self.co_firstlineno),
space.newbytes(self.co_lnotab),
@@ -451,7 +453,7 @@
space = self.space
# co_name should be an identifier
name = self.co_name.decode('utf-8')
- fn = space.fsdecode_w(space.newbytes(self.co_filename))
+ fn = space.unicode_w(self.w_filename)
return space.newunicode(u'<code object %s at 0x%s, file "%s", line %d>' % (
name, unicode(self.getaddrstring(space)), fn,
-1 if self.co_firstlineno == 0 else self.co_firstlineno))
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -625,7 +625,7 @@
co_varnames = GetSetProperty(PyCode.fget_co_varnames),
co_freevars = GetSetProperty(PyCode.fget_co_freevars),
co_cellvars = GetSetProperty(PyCode.fget_co_cellvars),
- co_filename = interp_attrproperty('co_filename', cls=PyCode, wrapfn="newfilename"),
+ co_filename = interp_attrproperty_w('w_filename', cls=PyCode),
co_name = interp_attrproperty('co_name', cls=PyCode, wrapfn="newtext"),
co_firstlineno = interp_attrproperty('co_firstlineno', cls=PyCode, wrapfn="newint"),
co_lnotab = interp_attrproperty('co_lnotab', cls=PyCode, wrapfn="newbytes"),
diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py
--- a/pypy/module/_io/interp_fileio.py
+++ b/pypy/module/_io/interp_fileio.py
@@ -8,6 +8,7 @@
from rpython.rlib.rstring import StringBuilder
from rpython.rlib import rposix
from rpython.rlib.rposix_stat import STAT_FIELD_TYPES
+from rpython.rlib.streamio import _setfd_binary
from rpython.rtyper.lltypesystem import lltype, rffi
from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_EXCL
import sys, os, stat, errno
@@ -239,6 +240,8 @@
if HAS_BLKSIZE and st.st_blksize > 1:
self.blksize = st.st_blksize
+ _setfd_binary(self.fd)
+
space.setattr(self, space.newtext("name"), w_name)
if self.appending:
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -70,7 +70,7 @@
py_code = rffi.cast(PyCodeObject, py_obj)
assert isinstance(w_obj, PyCode)
py_code.c_co_name = make_ref(space, space.newtext(w_obj.co_name))
- py_code.c_co_filename = make_ref(space, space.newtext(w_obj.co_filename))
+ py_code.c_co_filename = make_ref(space, w_obj.w_filename)
co_flags = 0
for name, value in ALL_CODE_FLAGS:
if w_obj.co_flags & getattr(pycode, name):
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -631,8 +631,9 @@
def test_decode(self, space):
b_text = rffi.str2charp('caf\x82xx')
b_encoding = rffi.str2charp('cp437')
- assert space.unicode_w(
- PyUnicode_Decode(space, b_text, 4, b_encoding, None)) == u'caf\xe9'
+ b_errors = rffi.str2charp('strict')
+ assert space.unicode_w(PyUnicode_Decode(
+ space, b_text, 4, b_encoding, b_errors)) == u'caf\xe9'
w_text = PyUnicode_FromEncodedObject(space, space.newbytes("test"), b_encoding, None)
assert space.isinstance_w(w_text, space.w_unicode)
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -492,7 +492,7 @@
w_str = space.newbytes(rffi.charpsize2str(s, size))
w_encoding = space.newtext(rffi.charp2str(encoding))
if errors:
- w_errors = space.newbytes(rffi.charp2str(errors))
+ w_errors = space.newtext(rffi.charp2str(errors))
else:
w_errors = None
return space.call_method(w_str, 'decode', w_encoding, w_errors)
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -2,7 +2,7 @@
Implementation of the interpreter-level default import logic.
"""
-import sys, os, stat, platform
+import sys, os, stat, re, platform
from pypy.interpreter.module import Module, init_extra_module_attrs
from pypy.interpreter.gateway import interp2app, unwrap_spec
@@ -44,18 +44,20 @@
soabi += 'i'
platform_name = sys.platform
- if platform_name == 'linux2':
- platform_name = 'linux'
+ if platform_name.startswith('linux'):
+ if re.match('(i[3-6]86|x86_64)$', platform.machine()):
+ if sys.maxsize < 2**32:
+ platform_name = 'i686-linux-gnu'
+ # xxx should detect if we are inside 'x32', but not for now
+ # because it's not supported anyway by PyPy. (Relying
+ # on platform.machine() does not work, it may return x86_64
+ # anyway)
+ else:
+ platform_name = 'x86_64-linux-gnu'
+ else:
+ platform_name = 'linux-gnu'
soabi += '-' + platform_name
- # xxx used to also include platform.machine(), but this is wrong
- # (might get AMD64 on a 32-bit python) and it is the source of a
- # importlib bug if we get uppercase characters from there...
-
- if platform_name == 'linux':
- soabi += '-gnu'
- if sys.maxsize == (2**31 - 1) and platform.machine() == 'x86_64':
- soabi += 'x32'
result = '.' + soabi + SO
assert result == result.lower() # this is an implicit requirement of importlib on Windows!
@@ -257,7 +259,7 @@
if pathname is not None:
w_pathname = get_sourcefile(space, pathname)
else:
- w_pathname = space.newfilename(code_w.co_filename)
+ w_pathname = code_w.w_filename
if cpathname is not None:
w_cpathname = space.newfilename(cpathname)
else:
@@ -351,6 +353,7 @@
return
code_w.co_filename = pathname
+ code_w.w_filename = space.newfilename(pathname)
constants = code_w.co_consts_w
for const in constants:
if const is not None and isinstance(const, PyCode):
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -769,9 +769,9 @@
class TestAbi:
def test_abi_tag(self):
- space1 = maketestobjspace(make_config(None, soabi='TEST'))
+ space1 = maketestobjspace(make_config(None, soabi='footest'))
space2 = maketestobjspace(make_config(None, soabi=''))
- assert importing.get_so_extension(space1).startswith('.TEST')
+ assert importing.get_so_extension(space1).startswith('.footest')
if sys.platform == 'win32':
assert importing.get_so_extension(space2) == '.pyd'
else:
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -80,6 +80,7 @@
'urandom': 'interp_posix.urandom',
'device_encoding': 'interp_posix.device_encoding',
'get_terminal_size': 'interp_posix.get_terminal_size',
+ 'symlink': 'interp_posix.symlink',
'scandir': 'interp_scandir.scandir',
'get_inheritable': 'interp_posix.get_inheritable',
@@ -111,8 +112,6 @@
interpleveldefs['killpg'] = 'interp_posix.killpg'
if hasattr(os, 'getpid'):
interpleveldefs['getpid'] = 'interp_posix.getpid'
- if hasattr(os, 'symlink'):
- interpleveldefs['symlink'] = 'interp_posix.symlink'
if hasattr(os, 'readlink'):
interpleveldefs['readlink'] = 'interp_posix.readlink'
if hasattr(os, 'fork'):
@@ -229,7 +228,7 @@
'POSIX_FADV_RANDOM', 'POSIX_FADV_NOREUSE', 'POSIX_FADV_DONTNEED']:
assert getattr(rposix, _name) is not None, "missing %r" % (_name,)
interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
-
+
if hasattr(rposix, 'sched_get_priority_max'):
interpleveldefs['sched_get_priority_max'] = 'interp_posix.sched_get_priority_max'
interpleveldefs['sched_get_priority_min'] = 'interp_posix.sched_get_priority_min'
@@ -246,11 +245,21 @@
if hasattr(rposix, 'sched_yield'):
interpleveldefs['sched_yield'] = 'interp_posix.sched_yield'
-
+
for _name in ["O_CLOEXEC"]:
if getattr(rposix, _name) is not None:
interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
+ if hasattr(rposix, 'getxattr'):
+ interpleveldefs['getxattr'] = 'interp_posix.getxattr'
+ interpleveldefs['setxattr'] = 'interp_posix.setxattr'
+ interpleveldefs['removexattr'] = 'interp_posix.removexattr'
+ interpleveldefs['listxattr'] = 'interp_posix.listxattr'
+ for _name in ['XATTR_SIZE_MAX', 'XATTR_CREATE', 'XATTR_REPLACE']:
+ if getattr(rposix, _name) is not None:
+ interpleveldefs[_name] = 'space.wrap(%d)' % getattr(rposix, _name)
+
+
def startup(self, space):
from pypy.module.posix import interp_posix
from pypy.module.imp import importing
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -122,7 +122,7 @@
else:
path_b = path.as_bytes
assert path_b is not None
- return func(path.as_bytes, *args)
+ return func(path_b, *args)
class Path(object):
@@ -1273,6 +1273,9 @@
and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError."""
+ if _WIN32:
+ raise oefmt(space.w_NotImplementedError,
+ "symlink() is not implemented for PyPy on Windows")
try:
if rposix.HAVE_SYMLINKAT and dir_fd != DEFAULT_DIR_FD:
src = space.fsencode_w(w_src)
@@ -2283,7 +2286,9 @@
This function will not follow symbolic links.
Equivalent to chflags(path, flags, follow_symlinks=False)."""
-def getxattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ follow_symlinks=bool)
+def getxattr(space, path, attribute, __kwonly__, follow_symlinks=True):
"""getxattr(path, attribute, *, follow_symlinks=True) -> value
Return the value of extended attribute attribute on path.
@@ -2292,8 +2297,27 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, getxattr will examine the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "getxattr: cannot use fd and follow_symlinks together")
+ try:
+ result = rposix.fgetxattr(path.as_fd, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
+ else:
+ try:
+ result = rposix.getxattr(path.as_bytes, attribute.as_bytes,
+ follow_symlinks=follow_symlinks)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
+ return space.newbytes(result)
-def setxattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ flags=c_int,
+ follow_symlinks=bool)
+def setxattr(space, path, attribute, w_value, flags=0,
+ __kwonly__=None, follow_symlinks=True):
"""setxattr(path, attribute, value, flags=0, *, follow_symlinks=True)
Set extended attribute attribute on path to value.
@@ -2301,9 +2325,26 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, setxattr will modify the symbolic link itself instead of the file
the link points to."""
+ value = space.charbuf_w(w_value)
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "setxattr: cannot use fd and follow_symlinks together")
+ try:
+ rposix.fsetxattr(path.as_fd, attribute.as_bytes, value)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
+ else:
+ try:
+ rposix.setxattr(path.as_bytes, attribute.as_bytes, value,
+ follow_symlinks=follow_symlinks)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
-def removexattr():
+ at unwrap_spec(path=path_or_fd(), attribute=path_or_fd(allow_fd=False),
+ follow_symlinks=bool)
+def removexattr(space, path, attribute, __kwonly__, follow_symlinks=True):
"""removexattr(path, attribute, *, follow_symlinks=True)
Remove extended attribute attribute on path.
@@ -2311,8 +2352,24 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, removexattr will modify the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "removexattr: cannot use fd and follow_symlinks together")
+ try:
+ rposix.fremovexattr(path.as_fd, attribute.as_bytes)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
+ else:
+ try:
+ rposix.removexattr(path.as_bytes, attribute.as_bytes,
+ follow_symlinks=follow_symlinks)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
-def listxattr():
+
+ at unwrap_spec(path=path_or_fd(), follow_symlinks=bool)
+def listxattr(space, path, __kwonly__, follow_symlinks=True):
"""listxattr(path='.', *, follow_symlinks=True)
Return a list of extended attributes on path.
@@ -2322,6 +2379,20 @@
If follow_symlinks is False, and the last element of the path is a symbolic
link, listxattr will examine the symbolic link itself instead of the file
the link points to."""
+ if path.as_fd != -1:
+ if not follow_symlinks:
+ raise oefmt(space.w_ValueError,
+ "listxattr: cannot use fd and follow_symlinks together")
+ try:
+ result = rposix.flistxattr(path.as_fd)
+ except OSError as e:
+ raise wrap_oserror(space, e, eintr_retry=False)
+ else:
+ try:
+ result = rposix.listxattr(path.as_bytes, follow_symlinks)
+ except OSError as e:
+ raise wrap_oserror(space, e, path.as_bytes)
+ return space.newlist([space.newfilename(attr) for attr in result])
have_functions = []
@@ -2449,8 +2520,8 @@
@unwrap_spec(policy=int)
def sched_get_priority_max(space, policy):
- """returns the maximum priority value that
- can be used with the scheduling algorithm
+ """returns the maximum priority value that
+ can be used with the scheduling algorithm
identified by policy
"""
while True:
@@ -2464,7 +2535,7 @@
@unwrap_spec(policy=int)
def sched_get_priority_min(space, policy):
"""returns the minimum priority value that
- can be used with the scheduling algorithm
+ can be used with the scheduling algorithm
identified by policy
"""
while True:
@@ -2477,7 +2548,7 @@
@unwrap_spec(fd=c_int, cmd=c_int, length=r_longlong)
def lockf(space, fd, cmd, length):
- """apply, test or remove a POSIX lock on an
+ """apply, test or remove a POSIX lock on an
open file.
"""
while True:
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
@@ -13,28 +13,39 @@
def scandir(space, w_path=None):
"scandir(path='.') -> iterator of DirEntry objects for given path"
- if _WIN32:
- raise NotImplementedError("XXX WIN32")
-
if space.is_none(w_path):
w_path = space.newunicode(u".")
- if space.isinstance_w(w_path, space.w_bytes):
- path_bytes = space.bytes0_w(w_path)
- result_is_bytes = True
+
+ if not _WIN32:
+ if space.isinstance_w(w_path, space.w_bytes):
+ path = space.bytes0_w(w_path)
+ result_is_bytes = True
+ else:
+ path = space.fsencode_w(w_path)
+ result_is_bytes = False
else:
- path_bytes = space.fsencode_w(w_path)
+ if space.isinstance_w(w_path, space.w_bytes):
+ raise oefmt(space.w_TypeError, "os.scandir() doesn't support bytes path"
+ " on Windows, use Unicode instead")
+ path = space.unicode_w(w_path)
result_is_bytes = False
+ # 'path' is always bytes on posix and always unicode on windows
try:
- dirp = rposix_scandir.opendir(path_bytes)
+ dirp = rposix_scandir.opendir(path)
except OSError as e:
raise wrap_oserror2(space, e, w_path, eintr_retry=False)
- path_prefix = path_bytes
- if len(path_prefix) > 0 and path_prefix[-1] != '/':
- path_prefix += '/'
- w_path_prefix = space.newbytes(path_prefix)
- if not result_is_bytes:
- w_path_prefix = space.fsdecode(w_path_prefix)
+ path_prefix = path
+ if not _WIN32:
+ if len(path_prefix) > 0 and path_prefix[-1] != '/':
+ path_prefix += '/'
+ w_path_prefix = space.newbytes(path_prefix)
+ if not result_is_bytes:
+ w_path_prefix = space.fsdecode(w_path_prefix)
+ else:
+ if len(path_prefix) > 0 and path_prefix[-1] not in (u'\\', u'/', u':'):
+ path_prefix += u'\\'
+ w_path_prefix = space.newunicode(path_prefix)
if rposix.HAVE_FSTATAT:
dirfd = rposix.c_dirfd(dirp)
else:
@@ -89,10 +100,14 @@
eintr_retry=False))
if not entry:
raise self.fail()
- assert rposix_scandir.has_name_bytes(entry)
- name = rposix_scandir.get_name_bytes(entry)
- if name != '.' and name != '..':
- break
+ if not _WIN32:
+ name = rposix_scandir.get_name_bytes(entry)
+ if name != '.' and name != '..':
+ break
+ else:
+ name = rposix_scandir.get_name_unicode(entry)
+ if name != u'.' and name != u'..':
+ break
#
known_type = rposix_scandir.get_known_type(entry)
inode = rposix_scandir.get_inode(entry)
@@ -113,12 +128,13 @@
class FileNotFound(Exception):
pass
-assert 0 <= rposix_scandir.DT_UNKNOWN <= 255
-assert 0 <= rposix_scandir.DT_REG <= 255
-assert 0 <= rposix_scandir.DT_DIR <= 255
-assert 0 <= rposix_scandir.DT_LNK <= 255
-FLAG_STAT = 256
-FLAG_LSTAT = 512
+if not _WIN32:
+ assert 0 <= rposix_scandir.DT_UNKNOWN <= 255
+ assert 0 <= rposix_scandir.DT_REG <= 255
+ assert 0 <= rposix_scandir.DT_DIR <= 255
+ assert 0 <= rposix_scandir.DT_LNK <= 255
+ FLAG_STAT = 256
+ FLAG_LSTAT = 512
class W_DirEntry(W_Root):
@@ -127,14 +143,17 @@
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.name = name # always bytes on Posix; always unicode on Windows
self.inode = inode
self.flags = known_type
- assert known_type == (known_type & 255)
#
- w_name = self.space.newbytes(name)
- if not scandir_iterator.result_is_bytes:
- w_name = self.space.fsdecode(w_name)
+ if not _WIN32:
+ assert known_type == (known_type & 255)
+ w_name = self.space.newbytes(name)
+ if not scandir_iterator.result_is_bytes:
+ w_name = self.space.fsdecode(w_name)
+ else:
+ w_name = self.space.newunicode(name)
self.w_name = w_name
def descr_repr(self, space):
@@ -156,93 +175,109 @@
# the end of the class. Every method only calls methods *before*
# it in program order, so there is no cycle.
- def get_lstat(self):
- """Get the lstat() of the direntry."""
- if (self.flags & FLAG_LSTAT) == 0:
- # Unlike CPython, try to use fstatat() if possible
- dirfd = self.scandir_iterator.dirfd
- if dirfd != -1 and rposix.HAVE_FSTATAT:
- st = rposix_stat.fstatat(self.name, dirfd,
- follow_symlinks=False)
- else:
- path = self.space.fsencode_w(self.fget_path(self.space))
- st = rposix_stat.lstat(path)
- self.d_lstat = st
- self.flags |= FLAG_LSTAT
- return self.d_lstat
-
- def get_stat(self):
- """Get the stat() of the direntry. This is implemented in
- such a way that it won't do both a stat() and a lstat().
- """
- if (self.flags & FLAG_STAT) == 0:
- # We don't have the 'd_stat'. If the known_type says the
- # direntry is not a DT_LNK, then try to get and cache the
- # 'd_lstat' instead. Then, or if we already have a
- # 'd_lstat' from before, *and* if the 'd_lstat' is not a
- # S_ISLNK, we can reuse it unchanged for 'd_stat'.
- #
- # Note how, in the common case where the known_type says
- # it is a DT_REG or DT_DIR, then we call and cache lstat()
- # and that's it. Also note that in a d_type-less OS or on
- # a filesystem that always answer DT_UNKNOWN, this method
- # will instead only call at most stat(), but not cache it
- # as 'd_lstat'.
- known_type = self.flags & 255
- if (known_type != rposix_scandir.DT_UNKNOWN and
- known_type != rposix_scandir.DT_LNK):
- self.get_lstat() # fill the 'd_lstat' cache
- have_lstat = True
- else:
- have_lstat = (self.flags & FLAG_LSTAT) != 0
-
- if have_lstat:
- # We have the lstat() but not the stat(). They are
- # the same, unless the 'd_lstat' is a S_IFLNK.
- must_call_stat = stat.S_ISLNK(self.d_lstat.st_mode)
- else:
- must_call_stat = True
-
- if must_call_stat:
- # Must call stat(). Try to use fstatat() if possible
+ if not _WIN32:
+ def get_lstat(self):
+ """Get the lstat() of the direntry."""
+ if (self.flags & FLAG_LSTAT) == 0:
+ # Unlike CPython, try to use fstatat() if possible
dirfd = self.scandir_iterator.dirfd
- if dirfd != -1 and rposix.HAVE_FSTATAT:
+ if rposix.HAVE_FSTATAT and dirfd != -1:
st = rposix_stat.fstatat(self.name, dirfd,
- follow_symlinks=True)
+ follow_symlinks=False)
else:
path = self.space.fsencode_w(self.fget_path(self.space))
- st = rposix_stat.stat(path)
+ st = rposix_stat.lstat(path)
+ self.d_lstat = st
+ self.flags |= FLAG_LSTAT
+ return self.d_lstat
+
+ def get_stat(self):
+ """Get the stat() of the direntry. This is implemented in
+ such a way that it won't do both a stat() and a lstat().
+ """
+ if (self.flags & FLAG_STAT) == 0:
+ # We don't have the 'd_stat'. If the known_type says the
+ # direntry is not a DT_LNK, then try to get and cache the
+ # 'd_lstat' instead. Then, or if we already have a
+ # 'd_lstat' from before, *and* if the 'd_lstat' is not a
+ # S_ISLNK, we can reuse it unchanged for 'd_stat'.
+ #
+ # Note how, in the common case where the known_type says
+ # it is a DT_REG or DT_DIR, then we call and cache lstat()
+ # and that's it. Also note that in a d_type-less OS or on
+ # a filesystem that always answer DT_UNKNOWN, this method
+ # will instead only call at most stat(), but not cache it
+ # as 'd_lstat'.
+ known_type = self.flags & 255
+ if (known_type != rposix_scandir.DT_UNKNOWN and
+ known_type != rposix_scandir.DT_LNK):
+ self.get_lstat() # fill the 'd_lstat' cache
+ have_lstat = True
+ else:
+ have_lstat = (self.flags & FLAG_LSTAT) != 0
+
+ if have_lstat:
+ # We have the lstat() but not the stat(). They are
+ # the same, unless the 'd_lstat' is a S_IFLNK.
+ must_call_stat = stat.S_ISLNK(self.d_lstat.st_mode)
+ else:
+ must_call_stat = True
+
+ if must_call_stat:
+ # Must call stat(). Try to use fstatat() if possible
+ dirfd = self.scandir_iterator.dirfd
+ if dirfd != -1 and rposix.HAVE_FSTATAT:
+ st = rposix_stat.fstatat(self.name, dirfd,
+ follow_symlinks=True)
+ else:
+ path = self.space.fsencode_w(self.fget_path(self.space))
+ st = rposix_stat.stat(path)
+ else:
+ st = self.d_lstat
+
+ self.d_stat = st
+ self.flags |= FLAG_STAT
+ return self.d_stat
+
+ def get_stat_or_lstat(self, follow_symlinks):
+ if follow_symlinks:
+ return self.get_stat()
else:
- st = self.d_lstat
+ return self.get_lstat()
- self.d_stat = st
- self.flags |= FLAG_STAT
- return self.d_stat
+ def check_mode(self, follow_symlinks):
+ """Get the stat() or lstat() of the direntry, and return the
+ S_IFMT. If calling stat()/lstat() gives us ENOENT, return -1
+ instead; it is better to give up and answer "no, not this type"
+ to requests, rather than propagate the error.
+ """
+ try:
+ st = self.get_stat_or_lstat(follow_symlinks)
+ except OSError as e:
+ if e.errno == ENOENT: # not found
+ return -1
+ raise wrap_oserror2(self.space, e, self.fget_path(self.space),
+ eintr_retry=False)
+ return stat.S_IFMT(st.st_mode)
- def get_stat_or_lstat(self, follow_symlinks):
- if follow_symlinks:
- return self.get_stat()
- else:
- return self.get_lstat()
+ else:
+ # Win32
+ stat_cached = False
- def check_mode(self, follow_symlinks):
- """Get the stat() or lstat() of the direntry, and return the
- S_IFMT. If calling stat()/lstat() gives us ENOENT, return -1
- instead; it is better to give up and answer "no, not this type"
- to requests, rather than propagate the error.
- """
- try:
- st = self.get_stat_or_lstat(follow_symlinks)
- except OSError as e:
- if e.errno == ENOENT: # not found
- return -1
- raise wrap_oserror2(self.space, e, self.fget_path(self.space),
- eintr_retry=False)
- return stat.S_IFMT(st.st_mode)
+ def check_mode(self, follow_symlinks):
+ return self.flags
+
+ def get_stat_or_lstat(self, follow_symlinks): # 'follow_symlinks' ignored
+ if not self.stat_cached:
+ path = self.space.unicode0_w(self.fget_path(self.space))
+ self.d_stat = rposix_stat.stat(path)
+ self.stat_cached = True
+ return self.d_stat
+
def is_dir(self, follow_symlinks):
known_type = self.flags & 255
- if known_type != rposix_scandir.DT_UNKNOWN:
+ if not _WIN32 and known_type != rposix_scandir.DT_UNKNOWN:
if known_type == rposix_scandir.DT_DIR:
return True
elif follow_symlinks and known_type == rposix_scandir.DT_LNK:
@@ -253,7 +288,7 @@
def is_file(self, follow_symlinks):
known_type = self.flags & 255
- if known_type != rposix_scandir.DT_UNKNOWN:
+ if not _WIN32 and known_type != rposix_scandir.DT_UNKNOWN:
if known_type == rposix_scandir.DT_REG:
return True
elif follow_symlinks and known_type == rposix_scandir.DT_LNK:
@@ -265,7 +300,7 @@
def is_symlink(self):
"""Check if the direntry is a symlink. May get the lstat()."""
known_type = self.flags & 255
- if known_type != rposix_scandir.DT_UNKNOWN:
+ if not _WIN32 and known_type != rposix_scandir.DT_UNKNOWN:
return known_type == rposix_scandir.DT_LNK
return self.check_mode(follow_symlinks=False) == stat.S_IFLNK
@@ -294,7 +329,15 @@
return build_stat_result(space, st)
def descr_inode(self, space):
- return space.newint(self.inode)
+ inode = self.inode
+ if inode is None: # _WIN32
+ try:
+ st = self.get_stat_or_lstat(follow_symlinks=False)
+ except OSError as e:
+ raise wrap_oserror2(space, e, self.fget_path(space),
+ eintr_retry=False)
+ inode = st.st_ino
+ return space.newint(inode)
W_DirEntry.typedef = TypeDef(
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -386,8 +386,8 @@
def test_times(self):
"""
- posix.times() should return a posix.times_result object giving
- float-representations (seconds, effectively) of the four fields from
+ posix.times() should return a posix.times_result object giving
+ float-representations (seconds, effectively) of the four fields from
the underlying struct tms and the return value.
"""
result = self.posix.times()
@@ -977,7 +977,7 @@
assert posix.sched_get_priority_min(posix.SCHED_OTHER) != -1
if getattr(posix, 'SCHED_BATCH', None):
assert posix.sched_get_priority_min(posix.SCHED_BATCH) != -1
-
+
if hasattr(rposix, 'sched_get_priority_min'):
def test_os_sched_priority_max_greater_than_min(self):
posix, os = self.posix, self.os
@@ -992,7 +992,7 @@
def test_sched_yield(self):
os = self.posix
#Always suceeds on Linux
- os.sched_yield()
+ os.sched_yield()
def test_write_buffer(self):
os = self.posix
@@ -1157,7 +1157,7 @@
expected = min(myprio + 3, 19)
assert os.WEXITSTATUS(status1) == expected
- if hasattr(os, 'symlink'):
+ if sys.platform != 'win32':
def test_symlink(self):
posix = self.posix
bytes_dir = self.bytes_dir
@@ -1187,6 +1187,10 @@
finally:
posix.close(f)
posix.unlink(bytes_dir + '/somelink'.encode())
+ else:
+ def test_symlink(self):
+ posix = self.posix
+ raises(NotImplementedError, posix.symlink, 'a', 'b')
if hasattr(os, 'ftruncate'):
def test_truncate(self):
@@ -1350,7 +1354,7 @@
posix.close(fd)
s2.close()
s1.close()
-
+
def test_os_lockf(self):
posix, os = self.posix, self.os
fd = os.open(self.path2 + 'test_os_lockf', os.O_WRONLY | os.O_CREAT)
@@ -1441,6 +1445,25 @@
e = raises(OSError, self.posix.symlink, 'bok', '/nonexistentdir/boz')
assert str(e.value).endswith(": 'bok' -> '/nonexistentdir/boz'")
+ if hasattr(rposix, 'getxattr'):
+ def test_xattr_simple(self):
+ # Minimal testing here, lib-python has better tests.
+ os = self.posix
+ with open(self.path, 'wb'):
+ pass
+ init_names = os.listxattr(self.path)
+ excinfo = raises(OSError, os.getxattr, self.path, 'user.test')
+ assert excinfo.value.filename == self.path
+ os.setxattr(self.path, 'user.test', b'', os.XATTR_CREATE, follow_symlinks=False)
+ assert os.getxattr(self.path, 'user.test') == b''
+ os.setxattr(self.path, b'user.test', b'foo', os.XATTR_REPLACE)
+ assert os.getxattr(self.path, 'user.test', follow_symlinks=False) == b'foo'
+ assert set(os.listxattr(self.path)) == set(
+ init_names + ['user.test'])
+ os.removexattr(self.path, 'user.test', follow_symlinks=False)
+ raises(OSError, os.getxattr, self.path, 'user.test')
+ assert os.listxattr(self.path, follow_symlinks=False) == init_names
+
class AppTestEnvironment(object):
def setup_class(cls):
@@ -1495,6 +1518,7 @@
res = os.system(cmd)
assert res == 0
+
@py.test.fixture
def check_fsencoding(space, pytestconfig):
if pytestconfig.getvalue('runappdirect'):
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
@@ -1,4 +1,5 @@
import sys, os
+import py
from rpython.tool.udir import udir
from pypy.module.posix.test import test_posix2
@@ -31,6 +32,8 @@
def setup_class(cls):
space = cls.space
+ cls.w_WIN32 = space.wrap(sys.platform == 'win32')
+ cls.w_sep = space.wrap(os.sep)
cls.w_posix = space.appexec([], test_posix2.GET_POSIX)
cls.w_dir_empty = space.wrap(_make_dir('empty', {}))
cls.w_dir0 = space.wrap(_make_dir('dir0', {'f1': 'file',
@@ -38,10 +41,11 @@
'f3': 'file'}))
cls.w_dir1 = space.wrap(_make_dir('dir1', {'file1': 'file'}))
cls.w_dir2 = space.wrap(_make_dir('dir2', {'subdir2': 'dir'}))
- cls.w_dir3 = space.wrap(_make_dir('dir3', {'sfile3': 'symlink-file'}))
- cls.w_dir4 = space.wrap(_make_dir('dir4', {'sdir4': 'symlink-dir'}))
- cls.w_dir5 = space.wrap(_make_dir('dir5', {'sbrok5': 'symlink-broken'}))
- cls.w_dir6 = space.wrap(_make_dir('dir6', {'serr6': 'symlink-error'}))
+ if sys.platform != 'win32':
+ cls.w_dir3 = space.wrap(_make_dir('dir3', {'sfile3': 'symlink-file'}))
+ cls.w_dir4 = space.wrap(_make_dir('dir4', {'sdir4': 'symlink-dir'}))
+ cls.w_dir5 = space.wrap(_make_dir('dir5', {'sbrok5': 'symlink-broken'}))
+ cls.w_dir6 = space.wrap(_make_dir('dir6', {'serr6': 'symlink-error'}))
def test_scandir_empty(self):
posix = self.posix
@@ -60,27 +64,32 @@
d = next(posix.scandir())
assert type(d.name) is str
assert type(d.path) is str
- assert d.path == './' + d.name
+ assert d.path == '.' + self.sep + d.name
d = next(posix.scandir(None))
assert type(d.name) is str
assert type(d.path) is str
- assert d.path == './' + d.name
+ assert d.path == '.' + self.sep + d.name
d = next(posix.scandir(u'.'))
assert type(d.name) is str
assert type(d.path) is str
- assert d.path == './' + d.name
- d = next(posix.scandir(b'.'))
- assert type(d.name) is bytes
- assert type(d.path) is bytes
- assert d.path == b'./' + d.name
- d = next(posix.scandir('/'))
+ assert d.path == '.' + self.sep + d.name
+ d = next(posix.scandir(self.sep))
assert type(d.name) is str
assert type(d.path) is str
- assert d.path == '/' + d.name
- d = next(posix.scandir(b'/'))
- assert type(d.name) is bytes
- assert type(d.path) is bytes
- assert d.path == b'/' + d.name
+ assert d.path == self.sep + d.name
+ if not self.WIN32:
+ d = next(posix.scandir(b'.'))
+ assert type(d.name) is bytes
+ assert type(d.path) is bytes
+ assert d.path == b'./' + d.name
+ d = next(posix.scandir(b'/'))
+ assert type(d.name) is bytes
+ assert type(d.path) is bytes
+ assert d.path == b'/' + d.name
+ else:
+ raises(TypeError, posix.scandir, b'.')
+ raises(TypeError, posix.scandir, b'/')
+ raises(TypeError, posix.scandir, b'\\')
def test_stat1(self):
posix = self.posix
@@ -89,6 +98,8 @@
assert d.stat().st_mode & 0o170000 == 0o100000 # S_IFREG
assert d.stat().st_size == 0
+ @py.test.mark.skipif(sys.platform == "win32",
+ reason="no symlink support so far")
def test_stat4(self):
posix = self.posix
d = next(posix.scandir(self.dir4))
@@ -118,6 +129,8 @@
assert not d.is_file(follow_symlinks=False)
assert d.is_dir(follow_symlinks=False)
+ @py.test.mark.skipif(sys.platform == "win32",
+ reason="no symlink support so far")
def test_dir3(self):
posix = self.posix
d = next(posix.scandir(self.dir3))
@@ -128,6 +141,8 @@
assert d.is_file(follow_symlinks=True)
assert not d.is_file(follow_symlinks=False)
+ @py.test.mark.skipif(sys.platform == "win32",
+ reason="no symlink support so far")
def test_dir4(self):
posix = self.posix
d = next(posix.scandir(self.dir4))
@@ -138,6 +153,8 @@
assert d.is_dir(follow_symlinks=True)
assert not d.is_dir(follow_symlinks=False)
+ @py.test.mark.skipif(sys.platform == "win32",
+ reason="no symlink support so far")
def test_dir5(self):
posix = self.posix
d = next(posix.scandir(self.dir5))
@@ -147,6 +164,8 @@
assert d.is_symlink()
raises(OSError, d.stat)
+ @py.test.mark.skipif(sys.platform == "win32",
+ reason="no symlink support so far")
def test_dir6(self):
posix = self.posix
d = next(posix.scandir(self.dir6))
diff --git a/pypy/module/zipimport/interp_zipimport.py b/pypy/module/zipimport/interp_zipimport.py
--- a/pypy/module/zipimport/interp_zipimport.py
+++ b/pypy/module/zipimport/interp_zipimport.py
@@ -252,6 +252,8 @@
gets in code_object.co_filename. Something like
'myfile.zip/mymodule.py'
"""
+ if ZIPSEP != os.path.sep:
+ filename = filename.replace(ZIPSEP, os.path.sep)
return self.filename + os.path.sep + filename
def load_module(self, space, w_fullname):
diff --git a/pypy/tool/build_cffi_imports.py b/pypy/tool/build_cffi_imports.py
--- a/pypy/tool/build_cffi_imports.py
+++ b/pypy/tool/build_cffi_imports.py
@@ -17,8 +17,8 @@
"resource": "_resource_build.py" if sys.platform != "win32" else None,
"lzma": "_lzma_build.py",
"_decimal": "_decimal_build.py",
- "ssl": "_ssl_build.py",
- # hashlib does not need to be built! It uses API calls from ssl
+ "_ssl": "_ssl_build.py",
+ # hashlib does not need to be built! It uses API calls from _ssl
"xx": None, # for testing: 'None' should be completely ignored
}
@@ -28,7 +28,7 @@
'lzma': ('https://tukaani.org/xz/xz-5.2.3.tar.gz',
'71928b357d0a09a12a4b4c5fafca8c31c19b0e7d3b8ebb19622e96f26dbf28cb',
[]),
- 'ssl': ('http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.6.2.tar.gz',
+ '_ssl': ('http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.6.2.tar.gz',
'b029d2492b72a9ba5b5fcd9f3d602c9fd0baa087912f2aaecc28f52f567ec478',
['--without-openssldir']),
'_gdbm': ('http://ftp.gnu.org/gnu/gdbm/gdbm-1.13.tar.gz',
@@ -159,6 +159,12 @@
continue
if module is None or getattr(options, 'no_' + key, False):
continue
+ # the key is the module name, has it already been built?
+ status, stdout, stderr = run_subprocess(str(pypy_c), ['-c', 'import %s' % key])
+ if status == 0:
+ print('*', ' %s already built' % key, file=sys.stderr)
+ continue
+
if module.endswith('.py'):
args = [module]
cwd = str(join(basedir,'lib_pypy'))
@@ -175,7 +181,7 @@
shutil.rmtree(destdir, ignore_errors=True)
os.makedirs(destdir)
- if key == 'ssl' and sys.platform == 'darwin':
+ if key == '_ssl' and sys.platform == 'darwin':
# this patch is loosely inspired by an Apple and adds
# a fallback to the OS X roots when none are available
patches = [
@@ -201,7 +207,7 @@
env['LDFLAGS'] = \
'-L{}/usr/lib {}'.format(destdir, env.get('LDFLAGS', ''))
- if key == 'ssl' and sys.platform == 'darwin':
+ if key == '_ssl' and sys.platform == 'darwin':
# needed for our roots patch
env['LDFLAGS'] += ' -framework CoreFoundation -framework Security'
@@ -237,7 +243,7 @@
help='instead of executing sys.executable' \
' you can specify an alternative pypy vm here')
parser.add_argument('--only', dest='only', default=None,
- help='Only build the modules delimited by a colon. E.g. ssl,sqlite')
+ help='Only build the modules delimited by a colon. E.g. _ssl,sqlite')
parser.add_argument('--embed-dependencies', dest='embed_dependencies', action='store_true',
help='embed dependencies for distribution')
args = parser.parse_args()
diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -381,16 +381,14 @@
class __extend__(pairtype(SomeChar, SomeUnicodeCodePoint),
pairtype(SomeUnicodeCodePoint, SomeChar)):
def union((uchr1, uchr2)):
- return SomeUnicodeCodePoint()
+ no_nul = uchr1.no_nul and uchr2.no_nul
+ return SomeUnicodeCodePoint(no_nul=no_nul)
class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeCodePoint)):
def union((uchr1, uchr2)):
no_nul = uchr1.no_nul and uchr2.no_nul
return SomeUnicodeCodePoint(no_nul=no_nul)
- def add((chr1, chr2)):
- return SomeUnicodeString()
-
class __extend__(pairtype(SomeString, SomeUnicodeString),
pairtype(SomeUnicodeString, SomeString)):
def mod((str, unistring)):
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -2574,3 +2574,160 @@
"""Passes offset==NULL; not support on all OSes"""
res = c_sendfile(out_fd, in_fd, lltype.nullptr(_OFF_PTR_T.TO), count)
return handle_posix_error('sendfile', res)
+
+# ____________________________________________________________
+# Support for *xattr functions
+
+if sys.platform.startswith('linux'):
+
+ class CConfig:
+ _compilation_info_ = ExternalCompilationInfo(
+ includes=['sys/xattr.h', 'linux/limits.h'],)
+ XATTR_SIZE_MAX = rffi_platform.DefinedConstantInteger('XATTR_SIZE_MAX')
+ XATTR_CREATE = rffi_platform.DefinedConstantInteger('XATTR_CREATE')
+ XATTR_REPLACE = rffi_platform.DefinedConstantInteger('XATTR_REPLACE')
+
+ cConfig = rffi_platform.configure(CConfig)
+ globals().update(cConfig)
+ c_fgetxattr = external('fgetxattr',
+ [rffi.INT, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_getxattr = external('getxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lgetxattr = external('lgetxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_fsetxattr = external('fsetxattr',
+ [rffi.INT, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_setxattr = external('setxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lsetxattr = external('lsetxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T, rffi.INT],
+ rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_fremovexattr = external('fremovexattr',
+ [rffi.INT, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_removexattr = external('removexattr',
+ [rffi.CCHARP, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_lremovexattr = external('lremovexattr',
+ [rffi.CCHARP, rffi.CCHARP], rffi.INT,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_flistxattr = external('flistxattr',
+ [rffi.INT, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_listxattr = external('listxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ c_llistxattr = external('llistxattr',
+ [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
+ compilation_info=CConfig._compilation_info_,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+ buf_sizes = [256, XATTR_SIZE_MAX]
+
+ def fgetxattr(fd, name):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ void_buf = rffi.cast(rffi.VOIDP, buf.raw)
+ res = c_fgetxattr(fd, name, void_buf, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ raise OSError(err, 'fgetxattr failed')
+ else:
+ return buf.str(res)
+ else:
+ raise OSError(errno.ERANGE, 'fgetxattr failed')
+
+ def getxattr(path, name, follow_symlinks=True):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ void_buf = rffi.cast(rffi.VOIDP, buf.raw)
+ if follow_symlinks:
+ res = c_getxattr(path, name, void_buf, size)
+ else:
+ res = c_lgetxattr(path, name, void_buf, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ c_name = 'getxattr' if follow_symlinks else 'lgetxattr'
+ raise OSError(err, c_name + 'failed')
+ else:
+ return buf.str(res)
+ else:
+ c_name = 'getxattr' if follow_symlinks else 'lgetxattr'
+ raise OSError(errno.ERANGE, c_name + 'failed')
+
+ def fsetxattr(fd, name, value, flags=0):
+ return handle_posix_error(
+ 'fsetxattr', c_fsetxattr(fd, name, value, len(value), flags))
+
+ def setxattr(path, name, value, flags=0, follow_symlinks=True):
+ if follow_symlinks:
+ return handle_posix_error(
+ 'setxattr', c_setxattr(path, name, value, len(value), flags))
+ else:
+ return handle_posix_error(
+ 'lsetxattr', c_lsetxattr(path, name, value, len(value), flags))
+
+ def fremovexattr(fd, name):
+ return handle_posix_error('fremovexattr', c_fremovexattr(fd, name))
+
+ def removexattr(path, name, follow_symlinks=True):
+ if follow_symlinks:
+ return handle_posix_error('removexattr', c_removexattr(path, name))
+ else:
+ return handle_posix_error('lremovexattr', c_lremovexattr(path, name))
+
+ def _unpack_attrs(attr_string):
+ result = attr_string.split('\0')
+ del result[-1]
+ return result
+
+ def flistxattr(fd):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ res = c_flistxattr(fd, buf.raw, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ raise OSError(err, 'flistxattr failed')
+ else:
+ return _unpack_attrs(buf.str(res))
+ else:
+ raise OSError(errno.ERANGE, 'flistxattr failed')
+
+ def listxattr(path, follow_symlinks=True):
+ for size in buf_sizes:
+ with rffi.scoped_alloc_buffer(size) as buf:
+ if follow_symlinks:
+ res = c_listxattr(path, buf.raw, size)
+ else:
+ res = c_llistxattr(path, buf.raw, size)
+ if res < 0:
+ err = get_saved_errno()
+ if err != errno.ERANGE:
+ c_name = 'listxattr' if follow_symlinks else 'llistxattr'
+ raise OSError(err, c_name + 'failed')
+ else:
+ return _unpack_attrs(buf.str(res))
+ else:
+ c_name = 'listxattr' if follow_symlinks else 'llistxattr'
+ raise OSError(errno.ERANGE, c_name + 'failed')
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
@@ -1,56 +1,126 @@
from rpython.rlib import rposix, rwin32
from rpython.rlib.objectmodel import specialize
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.rarithmetic import intmask
- at specialize.argtype(0)
-def opendir(path):
- path = rposix._as_bytes0(path)
- return opendir_bytes(path)
-
-def opendir_bytes(path):
- dirp = rposix.c_opendir(path)
- if not dirp:
- raise OSError(rposix.get_saved_errno(), "opendir failed")
- return dirp
-
-def closedir(dirp):
- rposix.c_closedir(dirp)
-
if not rwin32.WIN32:
+ @specialize.argtype(0)
+ def opendir(path):
+ path = rposix._as_bytes0(path)
+ return opendir_bytes(path)
+
+ def opendir_bytes(path):
+ dirp = rposix.c_opendir(path)
+ if not dirp:
+ raise OSError(rposix.get_saved_errno(), "opendir failed")
+ return dirp
+
+ def closedir(dirp):
+ rposix.c_closedir(dirp)
+
NULL_DIRP = lltype.nullptr(rposix.DIRP.TO)
-def nextentry(dirp):
- """Read the next entry and returns an opaque object.
- Use the methods has_xxx() and get_xxx() to read from that
- opaque object. The opaque object is valid until the next
- time nextentry() or closedir() is called. This may raise
- OSError, or return a NULL pointer when exhausted. Note
- that this doesn't filter out the "." and ".." entries.
- """
- direntp = rposix.c_readdir(dirp)
- if direntp:
- error = rposix.get_saved_errno()
- if error:
- raise OSError(error, "readdir failed")
- return direntp
+ def nextentry(dirp):
+ """Read the next entry and returns an opaque object.
+ Use the methods has_xxx() and get_xxx() to read from that
+ opaque object. The opaque object is valid until the next
+ time nextentry() or closedir() is called. This may raise
+ OSError, or return a NULL pointer when exhausted. Note
+ that this doesn't filter out the "." and ".." entries.
+ """
+ direntp = rposix.c_readdir(dirp)
+ if direntp:
+ error = rposix.get_saved_errno()
+ if error:
+ raise OSError(error, "readdir failed")
+ return direntp
-def has_name_bytes(direntp):
- return True
+ def get_name_bytes(direntp):
+ namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
+ return rffi.charp2str(namep)
-def get_name_bytes(direntp):
- namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
- return rffi.charp2str(namep)
+ DT_UNKNOWN = rposix.dirent_config.get('DT_UNKNOWN', 0)
+ DT_REG = rposix.dirent_config.get('DT_REG', 255)
+ DT_DIR = rposix.dirent_config.get('DT_DIR', 255)
+ DT_LNK = rposix.dirent_config.get('DT_LNK', 255)
-DT_UNKNOWN = rposix.dirent_config.get('DT_UNKNOWN', 0)
-DT_REG = rposix.dirent_config.get('DT_REG', 255)
-DT_DIR = rposix.dirent_config.get('DT_DIR', 255)
-DT_LNK = rposix.dirent_config.get('DT_LNK', 255)
+ def get_known_type(direntp):
+ if rposix.HAVE_D_TYPE:
+ return rffi.getintfield(direntp, 'c_d_type')
+ return DT_UNKNOWN
-def get_known_type(direntp):
- 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')
-def get_inode(direntp):
- return rffi.getintfield(direntp, 'c_d_ino')
+else:
+ # ----- Win32 version -----
+ import stat
+ from rpython.rlib._os_support import unicode_traits
+ from rpython.rlib.rwin32file import make_win32_traits
+ from rpython.rlib import rposix_stat
+
+ win32traits = make_win32_traits(unicode_traits)
+
+
+ SCANDIRP = lltype.Ptr(lltype.Struct('SCANDIRP',
+ ('filedata', win32traits.WIN32_FIND_DATA),
+ ('hFindFile', rwin32.HANDLE),
+ ('first_time', lltype.Bool),
+ ))
+ NULL_DIRP = lltype.nullptr(SCANDIRP.TO)
+
+
+ # must only be called with unicode!
+ def opendir(path):
+ if len(path) == 0:
+ path = u'.'
+ if path[-1] not in (u'\\', u'/', u':'):
+ mask = path + u'\\*.*'
+ else:
+ mask = path + u'*.*'
+ dirp = lltype.malloc(SCANDIRP.TO, flavor='raw')
+ hFindFile = win32traits.FindFirstFile(mask, dirp.filedata)
+ if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+ error = rwin32.GetLastError_saved()
+ lltype.free(dirp, flavor='raw')
+ raise WindowsError(error, "FindFirstFileW failed")
+ dirp.hFindFile = hFindFile
+ dirp.first_time = True
+ return dirp
+
+ def closedir(dirp):
+ if dirp.hFindFile != rwin32.INVALID_HANDLE_VALUE:
+ win32traits.FindClose(dirp.hFindFile)
+ lltype.free(dirp, flavor='raw')
+
+ def nextentry(dirp):
+ """Read the next entry and returns an opaque object.
+ Use the methods has_xxx() and get_xxx() to read from that
+ opaque object. The opaque object is valid until the next
+ time nextentry() or closedir() is called. This may raise
+ WindowsError, or return NULL when exhausted. Note
+ that this doesn't filter out the "." and ".." entries.
+ """
+ if dirp.first_time:
+ dirp.first_time = False
+ else:
+ if not win32traits.FindNextFile(dirp.hFindFile, dirp.filedata):
+ # error or no more files
+ error = rwin32.GetLastError_saved()
+ if error == win32traits.ERROR_NO_MORE_FILES:
+ return lltype.nullptr(win32traits.WIN32_FIND_DATA)
+ raise WindowsError(error, "FindNextFileW failed")
+ return dirp.filedata
+
+ def get_name_unicode(filedata):
+ return unicode_traits.charp2str(rffi.cast(unicode_traits.CCHARP,
+ filedata.c_cFileName))
+
+ def get_known_type(filedata):
+ attr = filedata.c_dwFileAttributes
+ st_mode = rposix_stat.win32_attributes_to_mode(win32traits, attr)
+ return stat.S_IFMT(st_mode)
+
+ def get_inode(filedata):
+ return None
diff --git a/rpython/rlib/rwin32file.py b/rpython/rlib/rwin32file.py
--- a/rpython/rlib/rwin32file.py
+++ b/rpython/rlib/rwin32file.py
@@ -148,7 +148,7 @@
save_err=rffi.RFFI_SAVE_LASTERROR)
FindClose = external('FindClose',
[rwin32.HANDLE],
- rwin32.BOOL)
+ rwin32.BOOL, releasegil=False)
GetFileAttributes = external(
'GetFileAttributes' + suffix,
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -1,3 +1,6 @@
+from hypothesis import given, strategies as st, assume
+import pytest
+
from rpython.rtyper.test.test_llinterp import interpret
from rpython.translator.c.test.test_genc import compile
from rpython.tool.pytest.expecttest import ExpectTest
@@ -8,10 +11,10 @@
import py
def rposix_requires(funcname):
- return py.test.mark.skipif(not hasattr(rposix, funcname),
+ return pytest.mark.skipif(not hasattr(rposix, funcname),
reason="Requires rposix.%s()" % funcname)
-win_only = py.test.mark.skipif("os.name != 'nt'")
+win_only = pytest.mark.skipif("os.name != 'nt'")
class TestPosixFunction:
def test_access(self):
@@ -827,3 +830,61 @@
rposix.lockf(fd, rposix.F_ULOCK, 4)
finally:
os.close(fd)
+
+def check_working_xattr():
+ fname = str(udir.join('xattr_test0.txt'))
+ with open(fname, 'wb'):
+ pass
+ try:
+ rposix.setxattr(fname, 'user.foo', '')
+ except OSError:
+ return False
+ else:
+ return True
+
+ at pytest.mark.skipif(not (hasattr(rposix, 'getxattr') and check_working_xattr()),
+ reason="Requires working rposix.getxattr()")
+ at given(
+ name=st.text(
+ alphabet=st.characters(min_codepoint=1), min_size=1, max_size=10),
+ value=st.binary(max_size=10),
+ follow_symlinks=st.booleans(), use_fd=st.booleans())
+def test_xattr(name, value, follow_symlinks, use_fd):
+ assume(follow_symlinks or not use_fd)
+ name = 'user.' + name.encode('utf-8')
+ fname = str(udir.join('xattr_test.txt'))
+ try:
+ os.unlink(fname)
+ except OSError:
+ pass
+ with open(fname, 'wb'):
+ pass
+ if use_fd:
+ file_id = os.open(fname, os.O_CREAT, 0777)
+ read, write, delete = rposix.fgetxattr, rposix.fsetxattr, rposix.fremovexattr
+ all_names = rposix.flistxattr
+ else:
+ file_id = fname
+ if follow_symlinks:
+ read, write, delete = rposix.getxattr, rposix.setxattr, rposix.removexattr
+ all_names = rposix.listxattr
+ else:
+ read = lambda *args, **kwargs: rposix.getxattr(*args, follow_symlinks=False, **kwargs)
+ write = lambda *args, **kwargs: rposix.setxattr(*args, follow_symlinks=False, **kwargs)
+ delete = lambda *args, **kwargs: rposix.removexattr(*args, follow_symlinks=False, **kwargs)
+ all_names = lambda *args, **kwargs: rposix.listxattr(*args, follow_symlinks=False, **kwargs)
+ try:
+ init_names = all_names(file_id)
+ with pytest.raises(OSError):
+ read(file_id, name)
+ write(file_id, name, value)
+ assert read(file_id, name) == value
+ assert set(all_names(file_id)) == set(init_names + [name])
+ assert '' not in all_names(file_id)
+ delete(file_id, name)
+ with pytest.raises(OSError):
+ read(file_id, name)
+ assert set(all_names(file_id)) == set(init_names)
+ finally:
+ if use_fd:
+ os.close(file_id)
More information about the pypy-commit
mailing list