[pypy-commit] pypy py3.5: hg merge py3k
arigo
pypy.commits at gmail.com
Sat Aug 20 17:17:18 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r86364:7d8da1e4bd2c
Date: 2016-08-20 23:11 +0200
http://bitbucket.org/pypy/pypy/changeset/7d8da1e4bd2c/
Log: hg merge py3k
diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -40,9 +40,6 @@
and possibly more locals."""
return self.signature().getallvarnames()
- def getformalargcount(self):
- return self.signature().scope_length()
-
def getdocstring(self, space):
return space.w_None
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -38,7 +38,9 @@
'name?',
'w_kw_defs?']
- def __init__(self, space, code, w_globals=None, defs_w=[], w_kw_defs=None,
+ w_kw_defs = None
+
+ def __init__(self, space, code, w_globals=None, defs_w=[], kw_defs_w=None,
closure=None, w_ann=None, forcename=None, qualname=None):
self.space = space
self.name = forcename or code.co_name
@@ -48,10 +50,12 @@
self.w_func_globals = w_globals # the globals dictionary
self.closure = closure # normally, list of Cell instances or None
self.defs_w = defs_w
- self.w_kw_defs = w_kw_defs
self.w_func_dict = None # filled out below if needed
self.w_module = None
self.w_ann = w_ann
+ #
+ if kw_defs_w is not None:
+ self.init_kwdefaults_dict(kw_defs_w)
def __repr__(self):
# return "function %s.%s" % (self.space, self.name)
@@ -379,14 +383,29 @@
def fset_func_kwdefaults(self, space, w_new):
if space.is_w(w_new, space.w_None):
- w_new = None
- elif not space.isinstance_w(w_new, space.w_dict):
- raise oefmt(space.w_TypeError, "__kwdefaults__ must be a dict")
- self.w_kw_defs = w_new
+ self.w_kw_defs = None
+ else:
+ if not space.isinstance_w(w_new, space.w_dict):
+ raise oefmt(space.w_TypeError, "__kwdefaults__ must be a dict")
+ w_instance = self.init_kwdefaults_dict()
+ w_instance.setdict(space, w_new)
+ self.w_kw_defs = w_instance.getdict(space)
def fdel_func_kwdefaults(self, space):
self.w_kw_defs = None
+ def init_kwdefaults_dict(self, kw_defs_w=[]):
+ # use the mapdict logic to get at least not-too-bad JIT code
+ # from function calls with default values of kwonly arguments
+ space = self.space
+ w_class = space.fromcache(KwDefsClassCache).w_class
+ w_instance = space.call_function(w_class)
+ for w_name, w_value in kw_defs_w:
+ attr = space.unicode_w(w_name).encode('utf-8')
+ w_instance.setdictvalue(space, attr, w_value)
+ self.w_kw_defs = w_instance.getdict(space)
+ return w_instance
+
def fget_func_doc(self, space):
if self.w_doc is None:
self.w_doc = self.code.getdocstring(space)
@@ -663,10 +682,12 @@
def __init__(self, func):
assert isinstance(func, Function)
Function.__init__(self, func.space, func.code, func.w_func_globals,
- func.defs_w, None, func.closure, None, func.name)
+ func.defs_w, None, func.closure,
+ None, func.name)
self.w_doc = func.w_doc
self.w_func_dict = func.w_func_dict
self.w_module = func.w_module
+ self.w_kw_defs = func.w_kw_defs
def descr_builtinfunction__new__(space, w_subtype):
raise oefmt(space.w_TypeError,
@@ -684,3 +705,12 @@
else:
code = None
return isinstance(code, BuiltinCode)
+
+
+class KwDefsClassCache:
+ def __init__(self, space):
+ self.w_class = space.appexec([], """():
+ class KwDefs:
+ pass
+ return KwDefs
+ """)
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -28,6 +28,8 @@
from rpython.rlib.rarithmetic import r_longlong, r_int, r_ulonglong, r_uint
from rpython.tool.sourcetools import func_with_new_name, compile2
+NO_DEFAULT = object()
+
# internal non-translatable parts:
class SignatureBuilder(object):
@@ -44,12 +46,21 @@
self.argnames = argnames
self.varargname = varargname
self.kwargname = kwargname
+ self.kwonlyargnames = None
def append(self, argname):
- self.argnames.append(argname)
+ if self.kwonlyargnames is None:
+ self.argnames.append(argname)
+ else:
+ self.kwonlyargnames.append(argname)
+
+ def marker_kwonly(self):
+ assert self.kwonlyargnames is None
+ self.kwonlyargnames = []
def signature(self):
- return Signature(self.argnames, self.varargname, self.kwargname)
+ return Signature(self.argnames, self.varargname, self.kwargname,
+ self.kwonlyargnames)
#________________________________________________________________
@@ -66,13 +77,6 @@
"""NOT_RPYTHON"""
raise NotImplementedError
-def kwonly(arg_unwrapper):
- """Mark argument as keyword-only.
-
- XXX: has no actual effect for now.
- """
- return arg_unwrapper
-
class UnwrapSpecRecipe(object):
"NOT_RPYTHON"
@@ -229,6 +233,11 @@
name = int_unwrapping_space_method(typ)
self.checked_space_method(name, app_sig)
+ def visit_kwonly(self, _, app_sig):
+ argname = self.orig_arg()
+ assert argname == '__kwonly__'
+ app_sig.marker_kwonly()
+
class UnwrapSpec_EmitRun(UnwrapSpecEmit):
@@ -316,6 +325,9 @@
def visit_truncatedint_w(self, typ):
self.run_args.append("space.truncatedint_w(%s)" % (self.scopenext(),))
+ def visit_kwonly(self, typ):
+ self.run_args.append("None")
+
def _make_unwrap_activation_class(self, unwrap_spec, cache={}):
try:
key = tuple(unwrap_spec)
@@ -468,6 +480,9 @@
def visit_truncatedint_w(self, typ):
self.unwrap.append("space.truncatedint_w(%s)" % (self.nextarg(),))
+ def visit_kwonly(self, typ):
+ raise FastFuncNotSupported
+
def make_fastfunc(unwrap_spec, func):
unwrap_info = UnwrapSpec_FastFunc_Unwrap()
unwrap_info.apply_over(unwrap_spec)
@@ -563,6 +578,8 @@
unwrap_spec.append('args_w')
elif argname.startswith('w_'):
unwrap_spec.append(W_Root)
+ elif argname == '__kwonly__':
+ unwrap_spec.append('kwonly')
else:
unwrap_spec.append(None)
@@ -616,6 +633,8 @@
argnames = sig.argnames
varargname = sig.varargname
kwargname = sig.kwargname
+ if sig.kwonlyargnames:
+ import pdb; pdb.set_trace()
self._argnames = argnames
if unwrap_spec is None:
@@ -950,64 +969,71 @@
self.name = app_name
self.as_classmethod = as_classmethod
- if not f.func_defaults:
- self._staticdefs = []
- else:
- argnames = self._code._argnames
- defaults = f.func_defaults
- self._staticdefs = zip(argnames[-len(defaults):], defaults)
+ argnames = self._code._argnames
+ defaults = f.func_defaults or ()
+ self._staticdefs = dict(zip(
+ argnames[len(argnames) - len(defaults):], defaults))
+
return self
def _getdefaults(self, space):
"NOT_RPYTHON"
- defs_w = []
- unwrap_spec = self._code._unwrap_spec[-len(self._staticdefs):]
- for i, (name, defaultval) in enumerate(self._staticdefs):
+ alldefs_w = {}
+ assert len(self._code._argnames) == len(self._code._unwrap_spec)
+ for name, spec in zip(self._code._argnames, self._code._unwrap_spec):
+ if name == '__kwonly__':
+ continue
+
+ defaultval = self._staticdefs.get(name, NO_DEFAULT)
+ w_def = Ellipsis
if name.startswith('w_'):
- assert defaultval is None, (
+ assert defaultval in (NO_DEFAULT, None), (
"%s: default value for '%s' can only be None, got %r; "
"use unwrap_spec(...=WrappedDefault(default))" % (
self._code.identifier, name, defaultval))
- defs_w.append(None)
- elif name != '__args__' and name != 'args_w':
- spec = unwrap_spec[i]
- if isinstance(defaultval, str) and spec not in [str]:
- defs_w.append(space.newbytes(defaultval))
- else:
- defs_w.append(space.wrap(defaultval))
- if self._code._unwrap_spec:
- UNDEFINED = object()
- alldefs_w = [UNDEFINED] * len(self._code.sig.argnames)
- if defs_w:
- alldefs_w[-len(defs_w):] = defs_w
- code = self._code
- assert isinstance(code._unwrap_spec, (list, tuple))
- assert isinstance(code._argnames, list)
- assert len(code._unwrap_spec) == len(code._argnames)
- for i in range(len(code._unwrap_spec)-1, -1, -1):
- spec = code._unwrap_spec[i]
- argname = code._argnames[i]
- if isinstance(spec, tuple) and spec[0] is W_Root:
- assert False, "use WrappedDefault"
- if isinstance(spec, WrappedDefault):
- default_value = spec.default_value
- if isinstance(default_value, str):
- w_default = space.newbytes(default_value)
- else:
- w_default = space.wrap(default_value)
- assert isinstance(w_default, W_Root)
- assert argname.startswith('w_')
- argname = argname[2:]
- j = self._code.sig.argnames.index(argname)
- assert alldefs_w[j] in (UNDEFINED, None)
- alldefs_w[j] = w_default
- first_defined = 0
- while (first_defined < len(alldefs_w) and
- alldefs_w[first_defined] is UNDEFINED):
- first_defined += 1
- defs_w = alldefs_w[first_defined:]
- assert UNDEFINED not in defs_w
- return defs_w
+ if defaultval is None:
+ w_def = None
+
+ if isinstance(spec, tuple) and spec[0] is W_Root:
+ assert False, "use WrappedDefault"
+ elif isinstance(spec, WrappedDefault):
+ assert name.startswith('w_')
+ defaultval = spec.default_value
+ w_def = Ellipsis
+
+ if defaultval is not NO_DEFAULT:
+ if name != '__args__' and name != 'args_w':
+ if w_def is Ellipsis:
+ if isinstance(defaultval, str) and spec not in [str]:
+ w_def = space.newbytes(defaultval)
+ else:
+ w_def = space.wrap(defaultval)
+ if name.startswith('w_'):
+ name = name[2:]
+ alldefs_w[name] = w_def
+ #
+ # Here, 'alldefs_w' maps some argnames to their wrapped default
+ # value. We return two lists:
+ # - a list of defaults for positional arguments, which covers
+ # some suffix of the sig.argnames list
+ # - a list of pairs (w_name, w_def) for kwonly arguments
+ #
+ sig = self._code.sig
+ first_defined = 0
+ while (first_defined < len(sig.argnames) and
+ sig.argnames[first_defined] not in alldefs_w):
+ first_defined += 1
+ defs_w = [alldefs_w.pop(name) for name in sig.argnames[first_defined:]]
+
+ kw_defs_w = None
+ if alldefs_w:
+ kw_defs_w = []
+ for name, w_def in sorted(alldefs_w.items()):
+ assert name in sig.kwonlyargnames
+ w_name = space.newunicode(name.decode('utf-8'))
+ kw_defs_w.append((w_name, w_def))
+
+ return defs_w, kw_defs_w
# lazy binding to space
@@ -1027,9 +1053,10 @@
def build(cache, gateway):
"NOT_RPYTHON"
space = cache.space
- defs = gateway._getdefaults(space) # needs to be implemented by subclass
+ defs_w, kw_defs_w = gateway._getdefaults(space)
code = gateway._code
- fn = FunctionWithFixedCode(space, code, None, defs, forcename=gateway.name)
+ fn = FunctionWithFixedCode(space, code, None, defs_w, kw_defs_w,
+ forcename=gateway.name)
if not space.config.translating:
fn.add_to_table()
if gateway.as_classmethod:
@@ -1167,15 +1194,15 @@
source = source[source.find('\n') + 1:].lstrip()
assert source.startswith("def "), "can only transform functions"
source = source[4:]
- import __future__
- if flags & __future__.CO_FUTURE_DIVISION:
- prefix += "from __future__ import division\n"
- if flags & __future__.CO_FUTURE_ABSOLUTE_IMPORT:
- prefix += "from __future__ import absolute_import\n"
- if flags & __future__.CO_FUTURE_PRINT_FUNCTION:
- prefix += "from __future__ import print_function\n"
- if flags & __future__.CO_FUTURE_UNICODE_LITERALS:
- prefix += "from __future__ import unicode_literals\n"
+ # The following flags have no effect any more in app-level code
+ # (i.e. they are always on anyway), and have been removed:
+ # CO_FUTURE_DIVISION
+ # CO_FUTURE_ABSOLUTE_IMPORT
+ # CO_FUTURE_PRINT_FUNCTION
+ # CO_FUTURE_UNICODE_LITERALS
+ # Original code was, for each of these flags:
+ # if flags & __future__.CO_xxx:
+ # prefix += "from __future__ import yyy\n"
p = source.find('(')
assert p >= 0
funcname = source[:p].strip()
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -19,6 +19,7 @@
""" NOT_RPYTHON """
Module.__init__(self, space, w_name)
self.lazy = True
+ self.lazy_initial_values_w = {}
self.__class__.buildloaders()
self.loaders = self.loaders.copy() # copy from the class to the inst
self.submodules_w = []
@@ -57,22 +58,11 @@
if not self.lazy and self.w_initialdict is None:
self.save_module_content_for_future_reload()
- def save_module_content_for_future_reload(self, save_all=False):
- # Because setdictvalue is unable to immediately load all attributes
- # (due to an importlib bootstrapping problem), this method needs to be
- # able to support saving the content of a module's dict without
- # requiring that the entire dict already be loaded. To support that
- # properly, when updating the dict, we must be careful to never
- # overwrite the value of a key already in w_initialdict. (So as to avoid
- # overriding the builtin value with a user-provided value)
- if self.space.is_none(self.w_initialdict) or save_all:
- self.w_initialdict = self.space.call_method(self.w_dict, 'copy')
- else:
- w_items = self.space.call_method(self.w_dict, 'items')
- for w_item in self.space.iteriterable(w_items):
- w_key, w_value = self.space.fixedview(w_item, expected_length=2)
- if not self.space.contains_w(self.w_initialdict, w_key):
- self.space.setitem(self.w_initialdict, w_key, w_value)
+ def save_module_content_for_future_reload(self):
+ # Save the current dictionary in w_initialdict, for future
+ # reloads. This forces the dictionary if needed.
+ w_dict = self.getdict(self.space)
+ self.w_initialdict = self.space.call_method(w_dict, 'copy')
@classmethod
def get_applevel_name(cls):
@@ -101,9 +91,13 @@
return w_value
def setdictvalue(self, space, attr, w_value):
- if self.lazy:
- self._load_lazily(space, attr)
- self.save_module_content_for_future_reload()
+ if self.lazy and attr not in self.lazy_initial_values_w:
+ # in lazy mode, the first time an attribute changes,
+ # we save away the old (initial) value. This allows
+ # a future getdict() call to build the correct
+ # self.w_initialdict, containing the initial value.
+ w_initial_value = self._load_lazily(space, attr)
+ self.lazy_initial_values_w[attr] = w_initial_value
space.setitem_str(self.w_dict, attr, w_value)
return True
@@ -137,13 +131,29 @@
def getdict(self, space):
if self.lazy:
- for name in self.loaders:
- w_value = self.get(name)
- space.setitem(self.w_dict, space.new_interned_str(name), w_value)
- self.lazy = False
- self.save_module_content_for_future_reload()
+ self._force_lazy_dict_now()
return self.w_dict
+ def _force_lazy_dict_now(self):
+ # Force the dictionary by calling all lazy loaders now.
+ # This also saves in self.w_initialdict a copy of all the
+ # initial values, including if they have already been
+ # modified by setdictvalue().
+ space = self.space
+ for name in self.loaders:
+ w_value = self.get(name)
+ space.setitem(self.w_dict, space.new_interned_str(name), w_value)
+ self.lazy = False
+ self.save_module_content_for_future_reload()
+ for key, w_initial_value in self.lazy_initial_values_w.items():
+ w_key = space.new_interned_str(key)
+ if w_initial_value is not None:
+ space.setitem(self.w_initialdict, w_key, w_initial_value)
+ else:
+ if space.finditem(self.w_initialdict, w_key) is not None:
+ space.delitem(self.w_initialdict, w_key)
+ del self.lazy_initial_values_w
+
def _cleanup_(self):
self.getdict(self.space)
self.w_initialdict = None
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1288,15 +1288,15 @@
for i in range(len(names_w) - 1, -1, -1):
space.setitem(w_ann, names_w[i], self.popvalue())
defaultarguments = self.popvalues(posdefaults)
- w_kw_defs = None
+ kw_defs_w = None
if kwdefaults:
- w_kw_defs = space.newdict(strdict=True)
- for i in range(kwdefaults - 1, -1, -1):
- w_name = self.popvalue()
- w_def = self.popvalue()
- space.setitem(w_kw_defs, w_def, w_name)
+ kw_defs_w = []
+ for i in range(kwdefaults):
+ w_defvalue = self.popvalue()
+ w_defname = self.popvalue()
+ kw_defs_w.append((w_defname, w_defvalue))
fn = function.Function(space, codeobj, self.get_w_globals(), defaultarguments,
- w_kw_defs, freevars, w_ann, qualname=qualname)
+ kw_defs_w, freevars, w_ann, qualname=qualname)
self.pushvalue(space.wrap(fn))
def MAKE_FUNCTION(self, oparg, next_instr):
diff --git a/pypy/interpreter/signature.py b/pypy/interpreter/signature.py
--- a/pypy/interpreter/signature.py
+++ b/pypy/interpreter/signature.py
@@ -39,6 +39,7 @@
def scope_length(self):
scopelen = len(self.argnames)
+ scopelen += len(self.kwonlyargnames)
scopelen += self.has_vararg()
scopelen += self.has_kwarg()
return scopelen
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -30,7 +30,7 @@
assert sig.num_argnames() == 3
assert sig.has_vararg()
assert sig.has_kwarg()
- assert sig.scope_length() == 5
+ assert sig.scope_length() == 6
assert sig.getallvarnames() == ["a", "b", "c", "d", "kwonly", "c"]
def test_eq(self):
diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -47,6 +47,12 @@
code = gateway.BuiltinCode(f, unwrap_spec=[gateway.ObjSpace, "index"])
assert code.signature() == Signature(["index"], None, None)
+ def f(space, __kwonly__, w_x):
+ pass
+ code = gateway.BuiltinCode(f, unwrap_spec=[gateway.ObjSpace,
+ "kwonly", W_Root])
+ assert code.signature() == Signature([], kwonlyargnames=['x'])
+
def test_call(self):
def c(space, w_x, w_y, hello_w):
@@ -753,7 +759,7 @@
@gateway.unwrap_spec(w_x = WrappedDefault(42), y=int)
def g(space, w_x, y):
never_called
- py.test.raises(AssertionError, space.wrap, gateway.interp2app_temp(g))
+ py.test.raises(KeyError, space.wrap, gateway.interp2app_temp(g))
def test_unwrap_spec_default_applevel_bug2(self):
space = self.space
@@ -803,6 +809,80 @@
w_res = space.call_args(w_g, args)
assert space.eq_w(w_res, space.newbytes('foo'))
+ def test_unwrap_spec_kwonly(self):
+ space = self.space
+ def g(space, w_x, __kwonly__, w_y):
+ return space.sub(w_x, w_y)
+ w_g = space.wrap(gateway.interp2app_temp(g))
+ w = space.wrap
+ w1 = w(1)
+
+ for i in range(4):
+ a = argument.Arguments(space, [w1, w1, w1])
+ py.test.raises(gateway.OperationError, space.call_args, w_g, a)
+ py.test.raises(gateway.OperationError, space.call_function, w_g,
+ *(i * (w1,)))
+
+ args = argument.Arguments(space, [w(1)],
+ w_starstararg = w({'y': 10}))
+ assert space.eq_w(space.call_args(w_g, args), w(-9))
+ args = argument.Arguments(space, [],
+ w_starstararg = w({'x': 2, 'y': 10}))
+ assert space.eq_w(space.call_args(w_g, args), w(-8))
+
+ def test_unwrap_spec_kwonly_default(self):
+ space = self.space
+ @gateway.unwrap_spec(w_x2=WrappedDefault(50), y2=int)
+ def g(space, w_x1, w_x2, __kwonly__, w_y1, y2=200):
+ return space.sub(space.sub(w_x1, w_x2),
+ space.sub(w_y1, w(y2)))
+ w_g = space.wrap(gateway.interp2app_temp(g))
+ w = space.wrap
+ w1 = w(1)
+
+ for i in range(6):
+ py.test.raises(gateway.OperationError, space.call_function, w_g,
+ *(i * (w1,)))
+
+ def expected(x1, x2=50, y1="missing", y2=200):
+ return (x1 - x2) - (y1 - y2)
+
+ def check(*args, **kwds):
+ a = argument.Arguments(space, [], w_stararg = w(args),
+ w_starstararg = w(kwds))
+ w_res = space.call_args(w_g, a)
+ assert space.eq_w(w_res, w(expected(*args, **kwds)))
+
+ del kwds['y1']
+ a = argument.Arguments(space, [], w_stararg = w(args),
+ w_starstararg = w(kwds))
+ py.test.raises(gateway.OperationError, space.call_args, w_g, a)
+
+ args += (1234,)
+ a = argument.Arguments(space, [], w_stararg = w(args),
+ w_starstararg = w(kwds))
+ py.test.raises(gateway.OperationError, space.call_args, w_g, a)
+
+ check(5, y1=1234)
+ check(5, 1, y1=1234)
+ check(5, x2=1, y1=1234)
+ check(5, y1=1234, y2=343)
+ check(5, 1, y1=1234, y2=343)
+ check(5, x2=1, y1=1234, y2=343)
+ check(x1=5, y1=1234, )
+ check(x1=5, x2=1, y1=1234, )
+ check(x1=5, y1=1234, y2=343)
+ check(x1=5, x2=1, y1=1234, y2=343)
+
+ def test_unwrap_spec_kwonly_default_2(self):
+ space = self.space
+ @gateway.unwrap_spec(w_x2=WrappedDefault(50))
+ def g(space, w_x2=None):
+ return w_x2
+ w_g = space.wrap(gateway.interp2app_temp(g))
+ w_res = space.call_function(w_g)
+ assert space.eq_w(w_res, space.wrap(50))
+
class AppTestPyTestMark:
@py.test.mark.unlikely_to_exist
diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py
--- a/pypy/interpreter/test/test_interpreter.py
+++ b/pypy/interpreter/test/test_interpreter.py
@@ -435,6 +435,20 @@
assert X().f() == 42
"""
+ def test_kwonlyarg_required(self):
+ """
+ def f(*, a=5, b):
+ return (a, b)
+ assert f(b=10) == (5, 10)
+ assert f(a=7, b=12) == (7, 12)
+ raises(TypeError, f)
+ raises(TypeError, f, 1)
+ raises(TypeError, f, 1, 1)
+ raises(TypeError, f, a=1)
+ raises(TypeError, f, 1, a=1)
+ raises(TypeError, f, 1, b=1)
+ """
+
def test_extended_unpacking_short(self):
"""
class Seq:
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -131,7 +131,7 @@
@unwrap_spec(w_module=MixedModule)
def save_module_content_for_future_reload(space, w_module):
- w_module.save_module_content_for_future_reload(save_all=True)
+ w_module.save_module_content_for_future_reload()
def set_code_callback(space, w_callable):
cache = space.fromcache(CodeHookCache)
diff --git a/pypy/module/_frozen_importlib/__init__.py b/pypy/module/_frozen_importlib/__init__.py
--- a/pypy/module/_frozen_importlib/__init__.py
+++ b/pypy/module/_frozen_importlib/__init__.py
@@ -16,11 +16,10 @@
@staticmethod
def _compile_bootstrap_module(space, name, w_name, w_dict):
"""NOT_RPYTHON"""
- ec = space.getexecutioncontext()
with open(os.path.join(lib_python, 'importlib', name + '.py')) as fp:
source = fp.read()
pathname = "<frozen importlib.%s>" % name
- code_w = ec.compiler.compile(source, pathname, 'exec', 0)
+ code_w = Module._cached_compile(space, source, pathname, 'exec', 0)
space.setitem(w_dict, space.wrap('__name__'), w_name)
space.setitem(w_dict, space.wrap('__builtins__'),
space.wrap(space.builtin))
@@ -43,6 +42,31 @@
self.w_import = space.wrap(interp_import.import_with_frames_removed)
+ @staticmethod
+ def _cached_compile(space, source, *args):
+ from rpython.config.translationoption import CACHE_DIR
+ from pypy.module.marshal import interp_marshal
+
+ cachename = os.path.join(CACHE_DIR, 'frozen_importlib_bootstrap')
+ try:
+ if space.config.translating:
+ raise IOError("don't use the cache when translating pypy")
+ with open(cachename, 'rb') as f:
+ previous = f.read(len(source) + 1)
+ if previous != source + '\x00':
+ raise IOError("source changed")
+ w_bin = space.newbytes(f.read())
+ code_w = interp_marshal.loads(space, w_bin)
+ except IOError:
+ # must (re)compile the source
+ ec = space.getexecutioncontext()
+ code_w = ec.compiler.compile(source, *args)
+ w_bin = interp_marshal.dumps(space, code_w, space.wrap(2))
+ content = source + '\x00' + space.bytes_w(w_bin)
+ with open(cachename, 'wb') as f:
+ f.write(content)
+ return code_w
+
def startup(self, space):
"""Copy our __import__ to builtins."""
w_install = self.getdictvalue(space, '_install')
diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py
--- a/pypy/module/_pypyjson/interp_decoder.py
+++ b/pypy/module/_pypyjson/interp_decoder.py
@@ -327,7 +327,8 @@
i += 1
if ch == '"':
content_utf8 = builder.build()
- content_unicode = unicodehelper.decode_utf8(self.space, content_utf8)
+ content_unicode = unicodehelper.decode_utf8(
+ self.space, content_utf8, allow_surrogates=True)
self.last_type = TYPE_STRING
self.pos = i
return self.space.wrap(content_unicode)
@@ -374,7 +375,8 @@
# this point
#
uchr = runicode.code_to_unichr(val) # may be a surrogate pair again
- utf8_ch = unicodehelper.encode_utf8(self.space, uchr)
+ utf8_ch = unicodehelper.encode_utf8(
+ self.space, uchr, allow_surrogates=True)
builder.append(utf8_ch)
return i
diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py
--- a/pypy/module/_pypyjson/test/test__pypyjson.py
+++ b/pypy/module/_pypyjson/test/test__pypyjson.py
@@ -10,10 +10,10 @@
assert dec.skip_whitespace(8) == len(s)
dec.close()
-
+
class AppTest(object):
- spaceconfig = {"objspace.usemodules._pypyjson": True}
+ spaceconfig = {"usemodules": ['_pypyjson']}
def test_raise_on_bytes(self):
import _pypyjson
@@ -40,7 +40,7 @@
raises(ValueError, _pypyjson.loads, 'fa')
raises(ValueError, _pypyjson.loads, 'f')
raises(ValueError, _pypyjson.loads, 'falXX')
-
+
def test_decode_string(self):
import _pypyjson
@@ -69,7 +69,7 @@
import _pypyjson
assert _pypyjson.loads(r'"\\"') == '\\'
assert _pypyjson.loads(r'"\""') == '"'
- assert _pypyjson.loads(r'"\/"') == '/'
+ assert _pypyjson.loads(r'"\/"') == '/'
assert _pypyjson.loads(r'"\b"') == '\b'
assert _pypyjson.loads(r'"\f"') == '\f'
assert _pypyjson.loads(r'"\n"') == '\n'
@@ -85,7 +85,7 @@
import _pypyjson
s = r'"hello\nworld' # missing the trailing "
raises(ValueError, "_pypyjson.loads(s)")
-
+
def test_escape_sequence_unicode(self):
import _pypyjson
s = r'"\u1234"'
@@ -166,7 +166,7 @@
def test_decode_object_nonstring_key(self):
import _pypyjson
raises(ValueError, "_pypyjson.loads('{42: 43}')")
-
+
def test_decode_array(self):
import _pypyjson
assert _pypyjson.loads('[]') == []
@@ -183,7 +183,7 @@
res = _pypyjson.loads('"z\\ud834\\udd20x"')
assert res == expected
- def test_surrogate_pair(self):
+ def test_lone_surrogate(self):
import _pypyjson
json = '{"a":"\\uD83D"}'
res = _pypyjson.loads(json)
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
@@ -15,8 +15,7 @@
from rpython.rlib.unroll import unrolling_iterable
from rpython.tool.sourcetools import func_with_new_name
-from pypy.interpreter.gateway import (
- unwrap_spec, WrappedDefault, Unwrapper, kwonly)
+from pypy.interpreter.gateway import unwrap_spec, WrappedDefault, Unwrapper
from pypy.interpreter.error import (
OperationError, oefmt, wrap_oserror, wrap_oserror2, strerror as _strerror)
from pypy.interpreter.executioncontext import ExecutionContext
@@ -211,7 +210,8 @@
"%s: %s unavailable on this platform", funcname, arg)
@unwrap_spec(flags=c_int, mode=c_int, dir_fd=DirFD(rposix.HAVE_OPENAT))
-def open(space, w_path, flags, mode=0777, dir_fd=DEFAULT_DIR_FD):
+def open(space, w_path, flags, mode=0777,
+ __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
"""open(path, flags, mode=0o777, *, dir_fd=None)
Open a file for low level IO. Returns a file handle (integer).
@@ -428,8 +428,8 @@
@unwrap_spec(
path=path_or_fd(allow_fd=True),
dir_fd=DirFD(rposix.HAVE_FSTATAT),
- follow_symlinks=kwonly(bool))
-def stat(space, path, dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
+ follow_symlinks=bool)
+def stat(space, path, __kwonly__, dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
"""stat(path, *, dir_fd=None, follow_symlinks=True) -> stat result
Perform a stat system call on the given path.
@@ -476,7 +476,7 @@
@unwrap_spec(
path=path_or_fd(allow_fd=False),
dir_fd=DirFD(rposix.HAVE_FSTATAT))
-def lstat(space, path, dir_fd=DEFAULT_DIR_FD):
+def lstat(space, path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
"""lstat(path, *, dir_fd=None) -> stat result
Like stat(), but do not follow symbolic links.
@@ -551,9 +551,9 @@
raise wrap_oserror(space, e)
@unwrap_spec(mode=c_int,
- dir_fd=DirFD(rposix.HAVE_FACCESSAT), effective_ids=kwonly(bool),
- follow_symlinks=kwonly(bool))
-def access(space, w_path, mode,
+ dir_fd=DirFD(rposix.HAVE_FACCESSAT), effective_ids=bool,
+ follow_symlinks=bool)
+def access(space, w_path, mode, __kwonly__,
dir_fd=DEFAULT_DIR_FD, effective_ids=False, follow_symlinks=True):
"""\
access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)
@@ -626,7 +626,7 @@
return space.wrap(rc)
@unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
-def unlink(space, w_path, dir_fd=DEFAULT_DIR_FD):
+def unlink(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
"""unlink(path, *, dir_fd=None)
Remove a file (same as remove()).
@@ -645,7 +645,7 @@
raise wrap_oserror2(space, e, w_path)
@unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
-def remove(space, w_path, dir_fd=DEFAULT_DIR_FD):
+def remove(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
"""remove(path, *, dir_fd=None)
Remove a file (same as unlink()).
@@ -710,7 +710,7 @@
raise wrap_oserror2(space, e, w_path)
@unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_MKDIRAT))
-def mkdir(space, w_path, mode=0o777, dir_fd=DEFAULT_DIR_FD):
+def mkdir(space, w_path, mode=0o777, __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
"""mkdir(path, mode=0o777, *, dir_fd=None)
Create a directory.
@@ -731,7 +731,7 @@
raise wrap_oserror2(space, e, w_path)
@unwrap_spec(dir_fd=DirFD(rposix.HAVE_UNLINKAT))
-def rmdir(space, w_path, dir_fd=DEFAULT_DIR_FD):
+def rmdir(space, w_path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
"""rmdir(path, *, dir_fd=None)
Remove a directory.
@@ -901,8 +901,9 @@
return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
@unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_FCHMODAT),
- follow_symlinks=kwonly(bool))
-def chmod(space, w_path, mode, dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
+ follow_symlinks=bool)
+def chmod(space, w_path, mode, __kwonly__,
+ dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
"""chmod(path, mode, *, dir_fd=None, follow_symlinks=True)
Change the access permissions of a file.
@@ -968,7 +969,7 @@
@unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT),
dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT))
-def rename(space, w_src, w_dst,
+def rename(space, w_src, w_dst, __kwonly__,
src_dir_fd=DEFAULT_DIR_FD, dst_dir_fd=DEFAULT_DIR_FD):
"""rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
@@ -992,7 +993,7 @@
@unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT),
dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT))
-def replace(space, w_src, w_dst,
+def replace(space, w_src, w_dst, __kwonly__,
src_dir_fd=DEFAULT_DIR_FD, dst_dir_fd=DEFAULT_DIR_FD):
"""replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
@@ -1015,7 +1016,7 @@
raise wrap_oserror(space, e)
@unwrap_spec(mode=c_int, dir_fd=DirFD(rposix.HAVE_MKFIFOAT))
-def mkfifo(space, w_path, mode=0666, dir_fd=DEFAULT_DIR_FD):
+def mkfifo(space, w_path, mode=0666, __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
"""mkfifo(path, mode=0o666, *, dir_fd=None)
Create a FIFO (a POSIX named pipe).
@@ -1034,7 +1035,8 @@
raise wrap_oserror2(space, e, w_path)
@unwrap_spec(mode=c_int, device=c_int, dir_fd=DirFD(rposix.HAVE_MKNODAT))
-def mknod(space, w_filename, mode=0600, device=0, dir_fd=DEFAULT_DIR_FD):
+def mknod(space, w_filename, mode=0600, device=0,
+ __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
"""mknod(filename, mode=0o600, device=0, *, dir_fd=None)
Create a filesystem node (file, device special file or named pipe)
@@ -1096,9 +1098,9 @@
@unwrap_spec(
src='fsencode', dst='fsencode',
src_dir_fd=DirFD(rposix.HAVE_LINKAT), dst_dir_fd=DirFD(rposix.HAVE_LINKAT),
- follow_symlinks=kwonly(bool))
+ follow_symlinks=bool)
def link(
- space, src, dst,
+ space, src, dst, __kwonly__,
src_dir_fd=DEFAULT_DIR_FD, dst_dir_fd=DEFAULT_DIR_FD,
follow_symlinks=True):
"""\
@@ -1128,7 +1130,7 @@
@unwrap_spec(dir_fd=DirFD(rposix.HAVE_SYMLINKAT))
def symlink(space, w_src, w_dst, w_target_is_directory=None,
- dir_fd=DEFAULT_DIR_FD):
+ __kwonly__=None, dir_fd=DEFAULT_DIR_FD):
"""symlink(src, dst, target_is_directory=False, *, dir_fd=None)
Create a symbolic link pointing to src named dst.
@@ -1156,7 +1158,7 @@
@unwrap_spec(
path=path_or_fd(allow_fd=False),
dir_fd=DirFD(rposix.HAVE_READLINKAT))
-def readlink(space, path, dir_fd=DEFAULT_DIR_FD):
+def readlink(space, path, __kwonly__, dir_fd=DEFAULT_DIR_FD):
"""readlink(path, *, dir_fd=None) -> path
Return a string representing the path to which the symbolic link points.
@@ -1356,9 +1358,9 @@
@unwrap_spec(
path=path_or_fd(allow_fd=rposix.HAVE_FUTIMENS or rposix.HAVE_FUTIMES),
- w_times=WrappedDefault(None), w_ns=kwonly(WrappedDefault(None)),
- dir_fd=DirFD(rposix.HAVE_UTIMENSAT), follow_symlinks=kwonly(bool))
-def utime(space, path, w_times, w_ns, dir_fd=DEFAULT_DIR_FD,
+ w_times=WrappedDefault(None), w_ns=WrappedDefault(None),
+ dir_fd=DirFD(rposix.HAVE_UTIMENSAT), follow_symlinks=bool)
+def utime(space, path, w_times, __kwonly__, w_ns, dir_fd=DEFAULT_DIR_FD,
follow_symlinks=True):
"""utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True)
@@ -1892,8 +1894,9 @@
@unwrap_spec(
uid=c_uid_t, gid=c_gid_t,
- dir_fd=DirFD(rposix.HAVE_FCHOWNAT), follow_symlinks=kwonly(bool))
-def chown(space, w_path, uid, gid, dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
+ dir_fd=DirFD(rposix.HAVE_FCHOWNAT), follow_symlinks=bool)
+def chown(space, w_path, uid, gid, __kwonly__,
+ dir_fd=DEFAULT_DIR_FD, follow_symlinks=True):
"""chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)
Change the owner and group id of path to the numeric uid and gid.
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -14,6 +14,13 @@
"""NOT_RPYTHON""" # because parent __init__ isn't
if space.config.translating:
del self.__class__.interpleveldefs['pypy_getudir']
+ del self.__class__.appleveldefs['stdin']
+ del self.__class__.appleveldefs['__stdin__']
+ del self.__class__.appleveldefs['stdout']
+ del self.__class__.appleveldefs['__stdout__']
+ del self.__class__.appleveldefs['stderr']
+ del self.__class__.appleveldefs['__stderr__']
+
super(Module, self).__init__(space, w_name)
self.recursionlimit = 100
self.defaultencoding = "utf-8"
@@ -99,6 +106,15 @@
'flags' : 'app.null_sysflags',
'_xoptions' : 'app.null__xoptions',
'implementation' : 'app.implementation',
+
+ # these six attributes are here only during tests;
+ # they are removed before translation
+ 'stdin' : 'std_test.stdin',
+ '__stdin__' : 'std_test.stdin',
+ 'stdout' : 'std_test.stdout',
+ '__stdout__' : 'std_test.stdout',
+ 'stderr' : 'std_test.stderr',
+ '__stderr__' : 'std_test.stderr',
}
def startup(self, space):
@@ -123,28 +139,12 @@
space = self.space
if not space.config.translating:
- from pypy.module.sys.interp_encoding import _getfilesystemencoding
- self.filesystemencoding = _getfilesystemencoding(space)
-
- if not space.config.translating:
- # Install standard streams for tests that don't call app_main.
- # Always use line buffering, even for tests that capture
- # standard descriptors.
- space.appexec([], """():
- import sys, io
- sys.stdin = sys.__stdin__ = io.open(0, "r", encoding="ascii",
- closefd=False)
- sys.stdin.buffer.raw.name = "<stdin>"
- sys.stdout = sys.__stdout__ = io.open(1, "w", encoding="ascii",
- buffering=1,
- closefd=False)
- sys.stdout.buffer.raw.name = "<stdout>"
- sys.stderr = sys.__stderr__ = io.open(2, "w", encoding="ascii",
- errors="backslashreplace",
- buffering=1,
- closefd=False)
- sys.stderr.buffer.raw.name = "<stderr>"
- """)
+ ##from pypy.module.sys.interp_encoding import _getfilesystemencoding
+ ##self.filesystemencoding = _getfilesystemencoding(space)
+ # XXX the two lines above take a few seconds to run whenever
+ # we initialize the space; for tests, use a simpler version
+ from pypy.module.sys.interp_encoding import base_encoding
+ self.filesystemencoding = space.wrap(base_encoding)
def flush_std_files(self, space):
w_stdout = space.sys.getdictvalue(space, 'stdout')
diff --git a/pypy/module/sys/std_test.py b/pypy/module/sys/std_test.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/sys/std_test.py
@@ -0,0 +1,19 @@
+# Install standard streams for tests that don't call app_main. Always
+# use line buffering, even for tests that capture standard descriptors.
+
+import io
+
+stdin = io.open(0, "r", encoding="ascii",
+ closefd=False)
+stdin.buffer.raw.name = "<stdin>"
+
+stdout = io.open(1, "w", encoding="ascii",
+ buffering=1,
+ closefd=False)
+stdout.buffer.raw.name = "<stdout>"
+
+stderr = io.open(2, "w", encoding="ascii",
+ errors="backslashreplace",
+ buffering=1,
+ closefd=False)
+stderr.buffer.raw.name = "<stderr>"
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -68,6 +68,7 @@
@jit.elidable
def find_map_attr(self, name, index):
# attr cache
+ assert type(name) is str # utf8-encoded
space = self.space
cache = space.fromcache(MapAttrCache)
SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
@@ -336,7 +337,7 @@
space = self.space
w_dict = obj.getdict(space)
try:
- space.delitem(w_dict, space.wrap(name))
+ space.delitem(w_dict, space.wrap(name.decode('utf-8')))
except OperationError as ex:
if not ex.match(space, space.w_KeyError):
raise
@@ -401,7 +402,7 @@
def materialize_r_dict(self, space, obj, dict_w):
new_obj = self.back.materialize_r_dict(space, obj, dict_w)
if self.index == DICT:
- w_attr = space.wrap(self.name)
+ w_attr = space.wrap(self.name.decode('utf-8'))
dict_w[w_attr] = obj._mapdict_read_storage(self.storageindex)
else:
self._copy_attr(obj, new_obj)
@@ -809,7 +810,7 @@
raise KeyError
key = curr.name
w_value = self.getitem_str(w_dict, key)
- w_key = self.space.wrap(key)
+ w_key = self.space.wrap(key.decode('utf-8'))
self.delitem(w_dict, w_key)
return (w_key, w_value)
@@ -844,7 +845,7 @@
if curr_map:
self.curr_map = curr_map.back
attr = curr_map.name
- w_attr = self.space.wrap(attr)
+ w_attr = self.space.wrap(attr.decode('utf-8'))
return w_attr
return None
@@ -885,7 +886,7 @@
if curr_map:
self.curr_map = curr_map.back
attr = curr_map.name
- w_attr = self.space.wrap(attr)
+ w_attr = self.space.wrap(attr.decode('utf-8'))
return w_attr, self.w_obj.getdictvalue(self.space, attr)
return None, None
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -1282,7 +1282,7 @@
assert a == self.string2
assert b == 2000
if not self._str_devolves:
- result = self.impl.getitem_str(self.string)
+ result = self.impl.getitem_str(self.string.encode('utf-8'))
else:
result = self.impl.getitem(self.string)
assert result == 1000
@@ -1293,7 +1293,7 @@
assert self.impl.length() == 1
assert self.impl.getitem(self.string) == 1000
if not self._str_devolves:
- result = self.impl.getitem_str(self.string)
+ result = self.impl.getitem_str(self.string.encode('utf-8'))
else:
result = self.impl.getitem(self.string)
assert result == 1000
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictObject
from pypy.objspace.std.mapdict import *
@@ -873,6 +875,15 @@
d = x.__dict__
assert list(__pypy__.reversed_dict(d)) == list(d.keys())[::-1]
+ def test_nonascii_argname(self):
+ """
+ class X:
+ pass
+ x = X()
+ x.日本 = 3
+ assert x.日本 == 3
+ assert x.__dict__ == {'日本': 3}
+ """
class AppTestWithMapDictAndCounters(object):
spaceconfig = {"objspace.std.withmethodcachecounter": True}
More information about the pypy-commit
mailing list