Author: Armin Rigo <[email protected]>
Branch: remove-raisingops
Changeset: r84703:e431a60a7e4d
Date: 2016-05-26 09:23 +0200
http://bitbucket.org/pypy/pypy/changeset/e431a60a7e4d/
Log: hg merge default
diff too long, truncating to 2000 out of 4033 lines
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -22,3 +22,4 @@
bbd45126bc691f669c4ebdfbd74456cd274c6b92 release-5.0.1
3260adbeba4a8b6659d1cc0d0b41f266769b74da release-5.1
b0a649e90b6642251fb4a765fe5b27a97b1319a9 release-5.1.1
+80ef432a32d9baa4b3c5a54c215e8ebe499f6374 release-5.1.2
diff --git a/lib-python/2.7/test/test_sys_settrace.py
b/lib-python/2.7/test/test_sys_settrace.py
--- a/lib-python/2.7/test/test_sys_settrace.py
+++ b/lib-python/2.7/test/test_sys_settrace.py
@@ -328,8 +328,8 @@
def test_13_genexp(self):
if self.using_gc:
+ gc.enable()
test_support.gc_collect()
- gc.enable()
try:
self.run_test(generator_example)
# issue1265: if the trace function contains a generator,
diff --git a/lib_pypy/cffi/commontypes.py b/lib_pypy/cffi/commontypes.py
--- a/lib_pypy/cffi/commontypes.py
+++ b/lib_pypy/cffi/commontypes.py
@@ -35,8 +35,11 @@
"you call ffi.set_unicode()" % (commontype,))
else:
if commontype == cdecl:
- raise api.FFIError("Unsupported type: %r. Please file a bug "
- "if you think it should be." %
(commontype,))
+ raise api.FFIError(
+ "Unsupported type: %r. Please look at "
+ "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations "
+ "and file an issue if you think this type should really "
+ "be supported." % (commontype,))
result, quals = parser.parse_type_and_quals(cdecl) # recursive
assert isinstance(result, model.BaseTypeByIdentity)
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -89,3 +89,19 @@
Use the new rgc.FinalizerQueue mechanism to clean up the handling of
``__del__`` methods. Fixes notably issue #2287. (All RPython
subclasses of W_Root need to use FinalizerQueue now.)
+
+.. branch: ufunc-outer
+
+Implement ufunc.outer on numpypy
+
+.. branch: verbose-imports
+
+Support ``pypy -v``: verbose imports. It does not log as much as
+cpython, but it should be enough to help when debugging package layout
+problems.
+
+.. branch: cpyext-macros-cast
+
+Fix some warnings when compiling CPython C extension modules
+
+.. branch: syntax_fix
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -2,7 +2,7 @@
# This is pure Python code that handles the main entry point into "pypy".
# See test/test_app_main.
-# Missing vs CPython: -d, -t, -v, -x, -3
+# Missing vs CPython: -d, -t, -x, -3
USAGE1 = __doc__ = """\
Options and arguments (and corresponding environment variables):
-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
@@ -19,6 +19,8 @@
-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE
-S : don't imply 'import site' on initialization
-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
+-v : verbose (trace import statements); also PYTHONVERBOSE=x
+ can be supplied multiple times to increase verbosity
-V : print the Python version number and exit (also --version)
-W arg : warning control; arg is action:message:category:module:lineno
also PYTHONWARNINGS=arg
@@ -529,6 +531,7 @@
warnoptions,
unbuffered,
ignore_environment,
+ verbose,
**ignored):
# with PyPy in top of CPython we can only have around 100
# but we need more in the translated PyPy for the compiler package
@@ -663,6 +666,8 @@
inspect = True
else:
# If not interactive, just read and execute stdin normally.
+ if verbose:
+ print_banner(not no_site)
@hidden_applevel
def run_it():
co_stdin = compile(sys.stdin.read(), '<stdin>', 'exec',
@@ -724,10 +729,10 @@
return status
def print_banner(copyright):
- print 'Python %s on %s' % (sys.version, sys.platform)
+ print >> sys.stderr, 'Python %s on %s' % (sys.version, sys.platform)
if copyright:
- print ('Type "help", "copyright", "credits" or '
- '"license" for more information.')
+ print >> sys.stderr, ('Type "help", "copyright", "credits" or '
+ '"license" for more information.')
STDLIB_WARNING = """\
debug: WARNING: Library path not found, using compiled-in sys.path.
diff --git a/pypy/interpreter/astcompiler/test/test_ast.py
b/pypy/interpreter/astcompiler/test/test_ast.py
--- a/pypy/interpreter/astcompiler/test/test_ast.py
+++ b/pypy/interpreter/astcompiler/test/test_ast.py
@@ -1,8 +1,8 @@
from pypy.interpreter.astcompiler import ast
class TestAstToObject:
def test_types(self, space):
- assert space.is_true(space.issubtype(
- ast.get(space).w_Module, ast.get(space).w_mod))
+ assert space.issubtype_w(
+ ast.get(space).w_Module, ast.get(space).w_mod)
def test_num(self, space):
value = space.wrap(42)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1215,7 +1215,7 @@
def abstract_issubclass_w(self, w_cls1, w_cls2):
# Equivalent to 'issubclass(cls1, cls2)'.
- return self.is_true(self.issubtype(w_cls1, w_cls2))
+ return self.issubtype_w(w_cls1, w_cls2)
def abstract_isinstance_w(self, w_obj, w_cls):
# Equivalent to 'isinstance(obj, cls)'.
@@ -1237,16 +1237,16 @@
def exception_is_valid_obj_as_class_w(self, w_obj):
if not self.isinstance_w(w_obj, self.w_type):
return False
- return self.is_true(self.issubtype(w_obj, self.w_BaseException))
+ return self.issubtype_w(w_obj, self.w_BaseException)
def exception_is_valid_class_w(self, w_cls):
- return self.is_true(self.issubtype(w_cls, self.w_BaseException))
+ return self.issubtype_w(w_cls, self.w_BaseException)
def exception_getclass(self, w_obj):
return self.type(w_obj)
def exception_issubclass_w(self, w_cls1, w_cls2):
- return self.is_true(self.issubtype(w_cls1, w_cls2))
+ return self.issubtype_w(w_cls1, w_cls2)
def new_exception_class(self, *args, **kwargs):
"NOT_RPYTHON; convenience method to create excceptions in modules"
diff --git a/pypy/module/__builtin__/__init__.py
b/pypy/module/__builtin__/__init__.py
--- a/pypy/module/__builtin__/__init__.py
+++ b/pypy/module/__builtin__/__init__.py
@@ -86,8 +86,8 @@
'max' : 'functional.max',
'reversed' : 'functional.reversed',
'super' : 'descriptor.W_Super',
- 'staticmethod' : 'descriptor.StaticMethod',
- 'classmethod' : 'descriptor.ClassMethod',
+ 'staticmethod' : 'pypy.interpreter.function.StaticMethod',
+ 'classmethod' : 'pypy.interpreter.function.ClassMethod',
'property' : 'descriptor.W_Property',
'globals' : 'interp_inspect.globals',
diff --git a/pypy/module/__builtin__/abstractinst.py
b/pypy/module/__builtin__/abstractinst.py
--- a/pypy/module/__builtin__/abstractinst.py
+++ b/pypy/module/__builtin__/abstractinst.py
@@ -76,11 +76,10 @@
w_pretendtype = space.getattr(w_obj, space.wrap('__class__'))
if space.is_w(w_pretendtype, space.type(w_obj)):
return False # common case: obj.__class__ is type(obj)
- if allow_override:
- w_result = space.issubtype_allow_override(w_pretendtype,
- w_klass_or_tuple)
- else:
- w_result = space.issubtype(w_pretendtype, w_klass_or_tuple)
+ if not allow_override:
+ return space.issubtype_w(w_pretendtype, w_klass_or_tuple)
+ w_result = space.issubtype_allow_override(w_pretendtype,
+ w_klass_or_tuple)
except OperationError as e:
if e.async(space):
raise
@@ -137,11 +136,9 @@
# -- case (type, type)
try:
- if allow_override:
- w_result = space.issubtype_allow_override(w_derived,
- w_klass_or_tuple)
- else:
- w_result = space.issubtype(w_derived, w_klass_or_tuple)
+ if not allow_override:
+ return space.issubtype_w(w_derived, w_klass_or_tuple)
+ w_result = space.issubtype_allow_override(w_derived, w_klass_or_tuple)
except OperationError as e: # if one of the args was not a type, ignore
it
if not e.match(space, space.w_TypeError):
raise # propagate other errors
diff --git a/pypy/module/__builtin__/descriptor.py
b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -1,31 +1,39 @@
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.function import StaticMethod, ClassMethod
-from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
-from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w,
- generic_new_descr)
+from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
+from pypy.interpreter.typedef import (
+ TypeDef, generic_new_descr, interp_attrproperty_w)
from pypy.objspace.descroperation import object_getattribute
class W_Super(W_Root):
- def __init__(self, space, w_starttype, w_objtype, w_self):
+
+ def __init__(self, space):
+ self.w_starttype = None
+ self.w_objtype = None
+ self.w_self = None
+
+ def descr_init(self, space, w_starttype, w_obj_or_type=None):
+ if space.is_none(w_obj_or_type):
+ w_type = None # unbound super object
+ w_obj_or_type = space.w_None
+ else:
+ w_type = _super_check(space, w_starttype, w_obj_or_type)
self.w_starttype = w_starttype
- self.w_objtype = w_objtype
- self.w_self = w_self
+ self.w_objtype = w_type
+ self.w_self = w_obj_or_type
def get(self, space, w_obj, w_type=None):
- w = space.wrap
if self.w_self is None or space.is_w(w_obj, space.w_None):
- return w(self)
+ return self
else:
# if type(self) is W_Super:
# XXX write a fast path for this common case
- w_selftype = space.type(w(self))
+ w_selftype = space.type(self)
return space.call_function(w_selftype, self.w_starttype, w_obj)
- @unwrap_spec(name=str)
- def getattribute(self, space, name):
- w = space.wrap
+ def getattribute(self, space, w_name):
+ name = space.str_w(w_name)
# only use a special logic for bound super objects and not for
# getting the __class__ of the super object itself.
if self.w_objtype is not None and name != '__class__':
@@ -45,44 +53,42 @@
return space.get_and_call_function(w_get, w_value,
w_obj, self.w_objtype)
# fallback to object.__getattribute__()
- return space.call_function(object_getattribute(space),
- w(self), w(name))
+ return space.call_function(object_getattribute(space), self, w_name)
-def descr_new_super(space, w_subtype, w_starttype, w_obj_or_type=None):
- if space.is_none(w_obj_or_type):
- w_type = None # unbound super object
- w_obj_or_type = space.w_None
- else:
- w_objtype = space.type(w_obj_or_type)
- if space.is_true(space.issubtype(w_objtype, space.w_type)) and \
- space.is_true(space.issubtype(w_obj_or_type, w_starttype)):
- w_type = w_obj_or_type # special case for class methods
- elif space.is_true(space.issubtype(w_objtype, w_starttype)):
- w_type = w_objtype # normal case
- else:
- try:
- w_type = space.getattr(w_obj_or_type, space.wrap('__class__'))
- except OperationError as o:
- if not o.match(space, space.w_AttributeError):
- raise
- w_type = w_objtype
- if not space.is_true(space.issubtype(w_type, w_starttype)):
- raise oefmt(space.w_TypeError,
- "super(type, obj): obj must be an instance or "
- "subtype of type")
- # XXX the details of how allocate_instance() should be used are not
- # really well defined
- w_result = space.allocate_instance(W_Super, w_subtype)
- W_Super.__init__(w_result, space, w_starttype, w_type, w_obj_or_type)
- return w_result
+def _super_check(space, w_starttype, w_obj_or_type):
+ """Check that the super() call makes sense. Returns a type"""
+ w_objtype = space.type(w_obj_or_type)
+
+ if (space.issubtype_w(w_objtype, space.w_type) and
+ space.issubtype_w(w_obj_or_type, w_starttype)):
+ # special case for class methods
+ return w_obj_or_type
+
+ if space.issubtype_w(w_objtype, w_starttype):
+ # normal case
+ return w_objtype
+
+ try:
+ w_type = space.getattr(w_obj_or_type, space.wrap('__class__'))
+ except OperationError as e:
+ if not e.match(space, space.w_AttributeError):
+ raise
+ w_type = w_objtype
+
+ if space.issubtype_w(w_type, w_starttype):
+ return w_type
+ raise oefmt(space.w_TypeError,
+ "super(type, obj): obj must be an instance or subtype of type")
W_Super.typedef = TypeDef(
'super',
- __new__ = interp2app(descr_new_super),
+ __new__ = generic_new_descr(W_Super),
+ __init__ = interp2app(W_Super.descr_init),
__thisclass__ = interp_attrproperty_w("w_starttype", W_Super),
__getattribute__ = interp2app(W_Super.getattribute),
__get__ = interp2app(W_Super.get),
- __doc__ = """super(type) -> unbound super object
+ __doc__ = """\
+super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
@@ -100,10 +106,10 @@
def __init__(self, space):
pass
- @unwrap_spec(w_fget = WrappedDefault(None),
- w_fset = WrappedDefault(None),
- w_fdel = WrappedDefault(None),
- w_doc = WrappedDefault(None))
+ @unwrap_spec(w_fget=WrappedDefault(None),
+ w_fset=WrappedDefault(None),
+ w_fdel=WrappedDefault(None),
+ w_doc=WrappedDefault(None))
def init(self, space, w_fget=None, w_fset=None, w_fdel=None, w_doc=None):
self.w_fget = w_fget
self.w_fset = w_fset
@@ -113,18 +119,17 @@
# our __doc__ comes from the getter if we don't have an explicit one
if (space.is_w(self.w_doc, space.w_None) and
not space.is_w(self.w_fget, space.w_None)):
- w_getter_doc = space.findattr(self.w_fget, space.wrap("__doc__"))
+ w_getter_doc = space.findattr(self.w_fget, space.wrap('__doc__'))
if w_getter_doc is not None:
if type(self) is W_Property:
self.w_doc = w_getter_doc
else:
- space.setattr(space.wrap(self), space.wrap("__doc__"),
- w_getter_doc)
+ space.setattr(self, space.wrap('__doc__'), w_getter_doc)
self.getter_doc = True
def get(self, space, w_obj, w_objtype=None):
if space.is_w(w_obj, space.w_None):
- return space.wrap(self)
+ return self
if space.is_w(self.w_fget, space.w_None):
raise oefmt(space.w_AttributeError, "unreadable attribute")
return space.call_function(self.w_fget, w_obj)
@@ -162,11 +167,13 @@
else:
w_doc = self.w_doc
w_type = self.getclass(space)
- return space.call_function(w_type, w_getter, w_setter, w_deleter,
w_doc)
+ return space.call_function(w_type, w_getter, w_setter, w_deleter,
+ w_doc)
W_Property.typedef = TypeDef(
'property',
- __doc__ = '''property(fget=None, fset=None, fdel=None, doc=None) ->
property attribute
+ __doc__ = '''\
+property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
fget is a function to be used for getting an attribute value, and likewise
fset is a function for setting, and fdel a function for deleting, an
diff --git a/pypy/module/__builtin__/functional.py
b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -145,8 +145,17 @@
else:
compare = space.lt
jitdriver = min_jitdriver
+ any_kwds = bool(args.keywords)
args_w = args.arguments_w
if len(args_w) > 1:
+ if unroll and len(args_w) == 2 and not any_kwds:
+ # a fast path for the common case, useful for interpreted
+ # mode and to reduce the length of the jit trace
+ w0, w1 = args_w
+ if space.is_true(compare(w1, w0)):
+ return w1
+ else:
+ return w0
w_sequence = space.newtuple(args_w)
elif len(args_w):
w_sequence = args_w[0]
@@ -155,8 +164,8 @@
"%s() expects at least one argument",
implementation_of)
w_key = None
- kwds = args.keywords
- if kwds:
+ if any_kwds:
+ kwds = args.keywords
if kwds[0] == "key" and len(kwds) == 1:
w_key = args.keywords_w[0]
else:
diff --git a/pypy/module/__builtin__/test/test_functional.py
b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -296,6 +296,11 @@
assert min([1, 2, 3]) == 1
raises(TypeError, min, 1, 2, bar=2)
raises(TypeError, min, 1, 2, key=lambda x: x, bar=2)
+ assert type(min(1, 1.0)) is int
+ assert type(min(1.0, 1)) is float
+ assert type(min(1, 1.0, 1L)) is int
+ assert type(min(1.0, 1L, 1)) is float
+ assert type(min(1L, 1, 1.0)) is long
def test_max(self):
assert max(1, 2) == 2
@@ -303,3 +308,8 @@
assert max([1, 2, 3]) == 3
raises(TypeError, max, 1, 2, bar=2)
raises(TypeError, max, 1, 2, key=lambda x: x, bar=2)
+ assert type(max(1, 1.0)) is int
+ assert type(max(1.0, 1)) is float
+ assert type(max(1, 1.0, 1L)) is int
+ assert type(max(1.0, 1L, 1)) is float
+ assert type(max(1L, 1, 1.0)) is long
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
@@ -51,6 +51,11 @@
space.newint(cache.misses.get(name, 0))])
def builtinify(space, w_func):
+ """To implement at app-level modules that are, in CPython,
+ implemented in C: this decorator protects a function from being ever
+ bound like a method. Useful because some tests do things like put
+ a "built-in" function on a class and access it via the instance.
+ """
from pypy.interpreter.function import Function, BuiltinFunction
func = space.interp_w(Function, w_func)
bltn = BuiltinFunction(func)
diff --git a/pypy/module/_cffi_backend/ctypeobj.py
b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -233,10 +233,9 @@
# __________ app-level attributes __________
def dir(self):
space = self.space
- w_self = space.wrap(self)
lst = [space.wrap(name)
for name in _name_of_attributes
- if space.findattr(w_self, space.wrap(name)) is not None]
+ if space.findattr(self, space.wrap(name)) is not None]
return space.newlist(lst)
def _fget(self, attrchar):
diff --git a/pypy/module/_cffi_backend/lib_obj.py
b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -196,9 +196,13 @@
if is_getattr and attr == '__dict__':
return self.full_dict_copy()
if is_getattr and attr == '__class__':
- return self.space.type(self)
+ # used to be space.type(self). But HAAAAAACK!
+ # That makes help() behave correctly. I couldn't
+ # find a more reasonable way. Urgh.
+ from pypy.interpreter.module import Module
+ return self.space.gettypeobject(Module.typedef)
if is_getattr and attr == '__name__':
- return self.descr_repr()
+ return self.space.wrap("%s.lib" % self.libname)
raise oefmt(self.space.w_AttributeError,
"cffi library '%s' has no function, constant "
"or global variable named '%s'",
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py
b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -1039,8 +1039,8 @@
assert MYFOO == 42
assert hasattr(lib, '__dict__')
assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar'
- assert lib.__name__ == repr(lib)
- assert lib.__class__ is type(lib)
+ assert lib.__name__ == '_CFFI_test_import_from_lib.lib'
+ assert lib.__class__ is type(sys) # !! hack for help()
def test_macro_var_callback(self):
ffi, lib = self.prepare(
diff --git a/pypy/module/_collections/interp_deque.py
b/pypy/module/_collections/interp_deque.py
--- a/pypy/module/_collections/interp_deque.py
+++ b/pypy/module/_collections/interp_deque.py
@@ -389,20 +389,18 @@
def copy(self):
"Return a shallow copy of a deque."
space = self.space
- w_self = space.wrap(self)
if self.maxlen == sys.maxint:
- return space.call_function(space.type(w_self), w_self)
+ return space.call_function(space.type(self), self)
else:
- return space.call_function(space.type(w_self), w_self,
+ return space.call_function(space.type(self), self,
space.wrap(self.maxlen))
def reduce(self):
"Return state information for pickling."
space = self.space
- w_self = space.wrap(self)
- w_type = space.type(w_self)
- w_dict = space.findattr(w_self, space.wrap('__dict__'))
- w_list = space.call_function(space.w_list, w_self)
+ w_type = space.type(self)
+ w_dict = space.findattr(self, space.wrap('__dict__'))
+ w_list = space.call_function(space.w_list, self)
if w_dict is None:
if self.maxlen == sys.maxint:
result = [
diff --git a/pypy/module/_weakref/interp__weakref.py
b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -156,12 +156,12 @@
class W_WeakrefBase(W_Root):
- def __init__(w_self, space, w_obj, w_callable):
+ def __init__(self, space, w_obj, w_callable):
assert w_callable is not space.w_None # should be really None
- w_self.space = space
+ self.space = space
assert w_obj is not None
- w_self.w_obj_weak = weakref.ref(w_obj)
- w_self.w_callable = w_callable
+ self.w_obj_weak = weakref.ref(w_obj)
+ self.w_callable = w_callable
@jit.dont_look_inside
def dereference(self):
@@ -171,8 +171,8 @@
def clear(self):
self.w_obj_weak = dead_ref
- def activate_callback(w_self):
- w_self.space.call_function(w_self.w_callable, w_self)
+ def activate_callback(self):
+ self.space.call_function(self.w_callable, self)
def descr__repr__(self, space):
w_obj = self.dereference()
@@ -189,9 +189,9 @@
class W_Weakref(W_WeakrefBase):
- def __init__(w_self, space, w_obj, w_callable):
- W_WeakrefBase.__init__(w_self, space, w_obj, w_callable)
- w_self.w_hash = None
+ def __init__(self, space, w_obj, w_callable):
+ W_WeakrefBase.__init__(self, space, w_obj, w_callable)
+ self.w_hash = None
def descr__init__weakref(self, space, w_obj, w_callable=None,
__args__=None):
diff --git a/pypy/module/_winreg/interp_winreg.py
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -16,10 +16,11 @@
class W_HKEY(W_Root):
def __init__(self, space, hkey):
self.hkey = hkey
+ self.space = space
self.register_finalizer(space)
- def _finalize_(self, space):
- self.Close(space)
+ def _finalize_(self):
+ self.Close(self.space)
def as_int(self):
return rffi.cast(rffi.SIZE_T, self.hkey)
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -203,46 +203,46 @@
# id. Invariant: this variable always contain 0 when the PyPy GIL is
# released. It should also contain 0 when regular RPython code
# executes. In non-cpyext-related code, it will thus always be 0.
-#
+#
# **make_generic_cpy_call():** RPython to C, with the GIL held. Before
# the call, must assert that the global variable is 0 and set the
# current thread identifier into the global variable. After the call,
# assert that the global variable still contains the current thread id,
# and reset it to 0.
-#
+#
# **make_wrapper():** C to RPython; by default assume that the GIL is
# held, but accepts gil="acquire", "release", "around",
# "pygilstate_ensure", "pygilstate_release".
-#
+#
# When a wrapper() is called:
-#
+#
# * "acquire": assert that the GIL is not currently held, i.e. the
# global variable does not contain the current thread id (otherwise,
# deadlock!). Acquire the PyPy GIL. After we acquired it, assert
# that the global variable is 0 (it must be 0 according to the
# invariant that it was 0 immediately before we acquired the GIL,
# because the GIL was released at that point).
-#
+#
# * gil=None: we hold the GIL already. Assert that the current thread
# identifier is in the global variable, and replace it with 0.
-#
+#
# * "pygilstate_ensure": if the global variable contains the current
# thread id, replace it with 0 and set the extra arg to 0. Otherwise,
# do the "acquire" and set the extra arg to 1. Then we'll call
# pystate.py:PyGILState_Ensure() with this extra arg, which will do
# the rest of the logic.
-#
+#
# When a wrapper() returns, first assert that the global variable is
# still 0, and then:
-#
+#
# * "release": release the PyPy GIL. The global variable was 0 up to
# and including at the point where we released the GIL, but afterwards
# it is possible that the GIL is acquired by a different thread very
# quickly.
-#
+#
# * gil=None: we keep holding the GIL. Set the current thread
# identifier into the global variable.
-#
+#
# * "pygilstate_release": if the argument is PyGILState_UNLOCKED,
# release the PyPy GIL; otherwise, set the current thread identifier
# into the global variable. The rest of the logic of
@@ -254,7 +254,7 @@
cpyext_namespace = NameManager('cpyext_')
-class ApiFunction:
+class ApiFunction(object):
def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
c_name=None, gil=None, result_borrowed=False,
result_is_ll=False):
self.argtypes = argtypes
@@ -292,11 +292,48 @@
def get_wrapper(self, space):
wrapper = getattr(self, '_wrapper', None)
if wrapper is None:
- wrapper = make_wrapper(space, self.callable, self.gil)
- self._wrapper = wrapper
- wrapper.relax_sig_check = True
- if self.c_name is not None:
- wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
+ wrapper = self._wrapper = self._make_wrapper(space)
+ return wrapper
+
+ # Make the wrapper for the cases (1) and (2)
+ def _make_wrapper(self, space):
+ "NOT_RPYTHON"
+ # This logic is obscure, because we try to avoid creating one
+ # big wrapper() function for every callable. Instead we create
+ # only one per "signature".
+
+ argtypesw = zip(self.argtypes,
+ [_name.startswith("w_") for _name in self.argnames])
+ error_value = getattr(self, "error_value", CANNOT_FAIL)
+ if (isinstance(self.restype, lltype.Ptr)
+ and error_value is not CANNOT_FAIL):
+ assert lltype.typeOf(error_value) == self.restype
+ assert not error_value # only support error=NULL
+ error_value = 0 # because NULL is not hashable
+
+ if self.result_is_ll:
+ result_kind = "L"
+ elif self.result_borrowed:
+ result_kind = "B" # note: 'result_borrowed' is ignored if we
also
+ else: # say 'result_is_ll=True' (in this case it's
+ result_kind = "." # up to you to handle refcounting anyway)
+
+ signature = (tuple(argtypesw),
+ self.restype,
+ result_kind,
+ error_value,
+ self.gil)
+
+ cache = space.fromcache(WrapperCache)
+ try:
+ wrapper_gen = cache.wrapper_gens[signature]
+ except KeyError:
+ wrapper_gen = WrapperGen(space, signature)
+ cache.wrapper_gens[signature] = wrapper_gen
+ wrapper = wrapper_gen.make_wrapper(self.callable)
+ wrapper.relax_sig_check = True
+ if self.c_name is not None:
+ wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
return wrapper
DEFAULT_HEADER = 'pypy_decl.h'
@@ -373,7 +410,16 @@
arg = rffi.cast(ARG, as_pyobj(space, input_arg))
else:
arg = rffi.cast(ARG, input_arg)
- elif is_PyObject(ARG) and is_wrapped:
+ elif ARG == rffi.VOIDP and not is_wrapped:
+ # unlike is_PyObject case above, we allow any kind of
+ # argument -- just, if it's an object, we assume the
+ # caller meant for it to become a PyObject*.
+ if input_arg is None or isinstance(input_arg, W_Root):
+ keepalives += (input_arg,)
+ arg = rffi.cast(ARG, as_pyobj(space, input_arg))
+ else:
+ arg = rffi.cast(ARG, input_arg)
+ elif (is_PyObject(ARG) or ARG == rffi.VOIDP) and
is_wrapped:
# build a W_Root, possibly from a 'PyObject *'
if is_pyobj(input_arg):
arg = from_ref(space, input_arg)
@@ -660,7 +706,7 @@
w_obj_type = space.type(w_obj)
w_type = get_w_type(space)
return (space.is_w(w_obj_type, w_type) or
- space.is_true(space.issubtype(w_obj_type, w_type)))
+ space.issubtype_w(w_obj_type, w_type))
def check_exact(space, w_obj):
"Implements the Py_Xxx_CheckExact function"
w_obj_type = space.type(w_obj)
@@ -683,92 +729,61 @@
def __init__(self, space):
self.space = space
self.wrapper_gens = {} # {signature: WrapperGen()}
- self.stats = [0, 0]
class WrapperGen(object):
wrapper_second_level = None
+ A = lltype.Array(lltype.Char)
def __init__(self, space, signature):
self.space = space
self.signature = signature
- self.callable2name = []
def make_wrapper(self, callable):
- self.callable2name.append((callable, callable.__name__))
if self.wrapper_second_level is None:
self.wrapper_second_level = make_wrapper_second_level(
- self.space, self.callable2name, *self.signature)
+ self.space, *self.signature)
wrapper_second_level = self.wrapper_second_level
+ name = callable.__name__
+ pname = lltype.malloc(self.A, len(name), flavor='raw', immortal=True)
+ for i in range(len(name)):
+ pname[i] = name[i]
+
def wrapper(*args):
# no GC here, not even any GC object
- args += (callable,)
- return wrapper_second_level(*args)
+ return wrapper_second_level(callable, pname, *args)
wrapper.__name__ = "wrapper for %r" % (callable, )
return wrapper
-# Make the wrapper for the cases (1) and (2)
-def make_wrapper(space, callable, gil=None):
- "NOT_RPYTHON"
- # This logic is obscure, because we try to avoid creating one
- # big wrapper() function for every callable. Instead we create
- # only one per "signature".
- argnames = callable.api_func.argnames
- argtypesw = zip(callable.api_func.argtypes,
- [_name.startswith("w_") for _name in argnames])
- error_value = getattr(callable.api_func, "error_value", CANNOT_FAIL)
- if (isinstance(callable.api_func.restype, lltype.Ptr)
- and error_value is not CANNOT_FAIL):
- assert lltype.typeOf(error_value) == callable.api_func.restype
- assert not error_value # only support error=NULL
- error_value = 0 # because NULL is not hashable
-
- if callable.api_func.result_is_ll:
- result_kind = "L"
- elif callable.api_func.result_borrowed:
- result_kind = "B" # note: 'result_borrowed' is ignored if we also
- else: # say 'result_is_ll=True' (in this case it's
- result_kind = "." # up to you to handle refcounting anyway)
-
- signature = (tuple(argtypesw),
- callable.api_func.restype,
- result_kind,
- error_value,
- gil)
-
- cache = space.fromcache(WrapperCache)
- cache.stats[1] += 1
- try:
- wrapper_gen = cache.wrapper_gens[signature]
- except KeyError:
- #print signature
- wrapper_gen = cache.wrapper_gens[signature] = WrapperGen(space,
- signature)
- cache.stats[0] += 1
- #print 'Wrapper cache [wrappers/total]:', cache.stats
- return wrapper_gen.make_wrapper(callable)
-
+@dont_inline
+def _unpack_name(pname):
+ return ''.join([pname[i] for i in range(len(pname))])
@dont_inline
def deadlock_error(funcname):
+ funcname = _unpack_name(funcname)
fatalerror_notb("GIL deadlock detected when a CPython C extension "
"module calls '%s'" % (funcname,))
@dont_inline
def no_gil_error(funcname):
+ funcname = _unpack_name(funcname)
fatalerror_notb("GIL not held when a CPython C extension "
"module calls '%s'" % (funcname,))
@dont_inline
def not_supposed_to_fail(funcname):
- raise SystemError("The function '%s' was not supposed to fail"
- % (funcname,))
+ funcname = _unpack_name(funcname)
+ print "Error in cpyext, CPython compatibility layer:"
+ print "The function", funcname, "was not supposed to fail"
+ raise SystemError
@dont_inline
def unexpected_exception(funcname, e, tb):
+ funcname = _unpack_name(funcname)
print 'Fatal error in cpyext, CPython compatibility layer,
calling',funcname
print 'Either report a bug or consider not using this particular extension'
if not we_are_translated():
@@ -784,7 +799,7 @@
pypy_debug_catch_fatal_exception()
assert False
-def make_wrapper_second_level(space, callable2name, argtypesw, restype,
+def make_wrapper_second_level(space, argtypesw, restype,
result_kind, error_value, gil):
from rpython.rlib import rgil
argtypes_enum_ui = unrolling_iterable(enumerate(argtypesw))
@@ -807,29 +822,19 @@
def invalid(err):
"NOT_RPYTHON: translation-time crash if this ends up being called"
raise ValueError(err)
- invalid.__name__ = 'invalid_%s' % (callable2name[0][1],)
- def nameof(callable):
- for c, n in callable2name:
- if c is callable:
- return n
- return '<unknown function>'
- nameof._dont_inline_ = True
-
- def wrapper_second_level(*args):
+ def wrapper_second_level(callable, pname, *args):
from pypy.module.cpyext.pyobject import make_ref, from_ref, is_pyobj
from pypy.module.cpyext.pyobject import as_pyobj
# we hope that malloc removal removes the newtuple() that is
# inserted exactly here by the varargs specializer
- callable = args[-1]
- args = args[:-1]
# see "Handling of the GIL" above (careful, we don't have the GIL here)
tid = rthread.get_or_make_ident()
_gil_auto = (gil_auto_workaround and cpyext_glob_tid_ptr[0] != tid)
if gil_acquire or _gil_auto:
if cpyext_glob_tid_ptr[0] == tid:
- deadlock_error(nameof(callable))
+ deadlock_error(pname)
rgil.acquire()
assert cpyext_glob_tid_ptr[0] == 0
elif pygilstate_ensure:
@@ -842,7 +847,7 @@
args += (pystate.PyGILState_UNLOCKED,)
else:
if cpyext_glob_tid_ptr[0] != tid:
- no_gil_error(nameof(callable))
+ no_gil_error(pname)
cpyext_glob_tid_ptr[0] = 0
rffi.stackcounter.stacks_counter += 1
@@ -859,6 +864,10 @@
if is_PyObject(typ) and is_wrapped:
assert is_pyobj(arg)
arg_conv = from_ref(space, rffi.cast(PyObject, arg))
+ elif typ == rffi.VOIDP and is_wrapped:
+ # Many macros accept a void* so that one can pass a
+ # PyObject* or a PySomeSubtype*.
+ arg_conv = from_ref(space, rffi.cast(PyObject, arg))
else:
arg_conv = arg
boxed_args += (arg_conv, )
@@ -888,7 +897,7 @@
if failed:
if error_value is CANNOT_FAIL:
- raise not_supposed_to_fail(nameof(callable))
+ raise not_supposed_to_fail(pname)
retval = error_value
elif is_PyObject(restype):
@@ -908,7 +917,7 @@
retval = rffi.cast(restype, result)
except Exception as e:
- unexpected_exception(nameof(callable), e, tb)
+ unexpected_exception(pname, e, tb)
return fatal_value
assert lltype.typeOf(retval) == restype
@@ -1019,7 +1028,7 @@
structindex = {}
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if not func:
+ if not func:
# added only for the macro, not the decl
continue
restype, args = c_function_signature(db, func)
@@ -1033,7 +1042,7 @@
RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI;
""" % dict(members=structmembers)
- functions = generate_decls_and_callbacks(db, export_symbols,
+ functions = generate_decls_and_callbacks(db, export_symbols,
prefix='cpyexttest')
global_objects = []
@@ -1415,7 +1424,7 @@
generate_macros(export_symbols, prefix=prefix)
- functions = generate_decls_and_callbacks(db, [], api_struct=False,
+ functions = generate_decls_and_callbacks(db, [], api_struct=False,
prefix=prefix)
code = "#include <Python.h>\n"
if use_micronumpy:
@@ -1471,7 +1480,7 @@
if not func:
continue
newname = mangle_name('PyPy', name) or name
- deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
+ deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
relax=True)
deco(func.get_wrapper(space))
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -1,4 +1,5 @@
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.annlowlevel import llhelper
from pypy.module.cpyext.pyobject import PyObject, make_ref
from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
PyObjectFields)
@@ -16,6 +17,23 @@
('TimeType', PyTypeObjectPtr),
('DeltaType', PyTypeObjectPtr),
('TZInfoType', PyTypeObjectPtr),
+
+ ('Date_FromDate', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+ PyObject))),
+ ('Time_FromTime', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr],
+ PyObject))),
+ ('DateTime_FromDateAndTime', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr],
+ PyObject))),
+ ('Delta_FromDelta', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyTypeObjectPtr],
+ PyObject))),
))
@cpython_api([], lltype.Ptr(PyDateTime_CAPI))
@@ -45,6 +63,19 @@
datetimeAPI.c_TZInfoType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ datetimeAPI.c_Date_FromDate = llhelper(
+ _PyDate_FromDate.api_func.functype,
+ _PyDate_FromDate.api_func.get_wrapper(space))
+ datetimeAPI.c_Time_FromTime = llhelper(
+ _PyTime_FromTime.api_func.functype,
+ _PyTime_FromTime.api_func.get_wrapper(space))
+ datetimeAPI.c_DateTime_FromDateAndTime = llhelper(
+ _PyDateTime_FromDateAndTime.api_func.functype,
+ _PyDateTime_FromDateAndTime.api_func.get_wrapper(space))
+ datetimeAPI.c_Delta_FromDelta = llhelper(
+ _PyDelta_FromDelta.api_func.functype,
+ _PyDelta_FromDelta.api_func.get_wrapper(space))
+
return datetimeAPI
PyDateTime_DateStruct = lltype.ForwardReference()
@@ -94,36 +125,40 @@
make_check_function("PyDelta_Check", "timedelta")
make_check_function("PyTZInfo_Check", "tzinfo")
-# Constructors
+# Constructors. They are better used as macros.
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDate_FromDate(space, year, month, day):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+ PyObject)
+def _PyDate_FromDate(space, year, month, day, w_type):
"""Return a datetime.date object with the specified year, month and day.
"""
year = rffi.cast(lltype.Signed, year)
month = rffi.cast(lltype.Signed, month)
day = rffi.cast(lltype.Signed, day)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "date",
+ return space.call_function(
+ w_type,
space.wrap(year), space.wrap(month), space.wrap(day))
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real],
PyObject)
-def PyTime_FromTime(space, hour, minute, second, usecond):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr], PyObject)
+def _PyTime_FromTime(space, hour, minute, second, usecond, w_tzinfo, w_type):
"""Return a ``datetime.time`` object with the specified hour, minute,
second and
microsecond."""
hour = rffi.cast(lltype.Signed, hour)
minute = rffi.cast(lltype.Signed, minute)
second = rffi.cast(lltype.Signed, second)
usecond = rffi.cast(lltype.Signed, usecond)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "time",
+ return space.call_function(
+ w_type,
space.wrap(hour), space.wrap(minute), space.wrap(second),
- space.wrap(usecond))
+ space.wrap(usecond), w_tzinfo)
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDateTime_FromDateAndTime(space, year, month, day, hour, minute, second,
usecond):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr], PyObject)
+def _PyDateTime_FromDateAndTime(space, year, month, day,
+ hour, minute, second, usecond,
+ w_tzinfo, w_type):
"""Return a datetime.datetime object with the specified year, month, day,
hour,
minute, second and microsecond.
"""
@@ -134,12 +169,11 @@
minute = rffi.cast(lltype.Signed, minute)
second = rffi.cast(lltype.Signed, second)
usecond = rffi.cast(lltype.Signed, usecond)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "datetime",
+ return space.call_function(
+ w_type,
space.wrap(year), space.wrap(month), space.wrap(day),
space.wrap(hour), space.wrap(minute), space.wrap(second),
- space.wrap(usecond))
+ space.wrap(usecond), w_tzinfo)
@cpython_api([PyObject], PyObject)
def PyDateTime_FromTimestamp(space, w_args):
@@ -161,8 +195,10 @@
w_method = space.getattr(w_type, space.wrap("fromtimestamp"))
return space.call(w_method, w_args)
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDelta_FromDSU(space, days, seconds, useconds):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyTypeObjectPtr],
+ PyObject)
+def _PyDelta_FromDelta(space, days, seconds, useconds, normalize, w_type):
"""Return a datetime.timedelta object representing the given number of
days,
seconds and microseconds. Normalization is performed so that the resulting
number of microseconds and seconds lie in the ranges documented for
@@ -171,74 +207,73 @@
days = rffi.cast(lltype.Signed, days)
seconds = rffi.cast(lltype.Signed, seconds)
useconds = rffi.cast(lltype.Signed, useconds)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "timedelta",
+ return space.call_function(
+ w_type,
space.wrap(days), space.wrap(seconds), space.wrap(useconds))
# Accessors
-@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_YEAR(space, w_obj):
"""Return the year, as a positive int.
"""
return space.int_w(space.getattr(w_obj, space.wrap("year")))
-@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_MONTH(space, w_obj):
"""Return the month, as an int from 1 through 12.
"""
return space.int_w(space.getattr(w_obj, space.wrap("month")))
-@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_DAY(space, w_obj):
"""Return the day, as an int from 1 through 31.
"""
return space.int_w(space.getattr(w_obj, space.wrap("day")))
-@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
-@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
-@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
-@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
-@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
-@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
-@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
-@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
@@ -248,14 +283,14 @@
# But it does not seem possible to expose a different structure
# for types defined in a python module like lib/datetime.py.
-@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_DAYS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("days")))
-@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_SECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("seconds")))
-@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("microseconds")))
diff --git a/pypy/module/cpyext/floatobject.py
b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -48,7 +48,7 @@
def PyFloat_AsDouble(space, w_obj):
return space.float_w(space.float(w_obj))
-@cpython_api([PyObject], lltype.Float, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], lltype.Float, error=CANNOT_FAIL)
def PyFloat_AS_DOUBLE(space, w_float):
"""Return a C double representation of the contents of w_float, but
without error checking."""
diff --git a/pypy/module/cpyext/include/datetime.h
b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -12,6 +12,13 @@
PyTypeObject *TimeType;
PyTypeObject *DeltaType;
PyTypeObject *TZInfoType;
+
+ /* constructors */
+ PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*);
+ PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int,
+ PyObject*, PyTypeObject*);
+ PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*);
+ PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*);
} PyDateTime_CAPI;
PyAPI_DATA(PyDateTime_CAPI*) PyDateTimeAPI;
@@ -41,6 +48,22 @@
PyObject_HEAD
} PyDateTime_TZInfo;
+/* Macros for accessing constructors in a simplified fashion. */
+#define PyDate_FromDate(year, month, day) \
+ PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType)
+
+#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \
+ PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \
+ min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType)
+
+#define PyTime_FromTime(hour, minute, second, usecond) \
+ PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \
+ Py_None, PyDateTimeAPI->TimeType)
+
+#define PyDelta_FromDSU(days, seconds, useconds) \
+ PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \
+ PyDateTimeAPI->DeltaType)
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/include/listobject.h
b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,1 @@
-#define PyList_GET_ITEM PyList_GetItem
+#define PyList_GET_ITEM(o, i) PyList_GetItem((PyObject*)(o), (i))
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -104,7 +104,7 @@
num = space.bigint_w(w_int)
return num.ulonglongmask()
-@cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL)
def PyInt_AS_LONG(space, w_int):
"""Return the value of the object w_int. No error checking is performed."""
return space.int_w(w_int)
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -21,7 +21,7 @@
"""
return space.newlist([None] * len)
-@cpython_api([PyObject, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
+@cpython_api([rffi.VOIDP, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
result_borrowed=True)
def PyList_SET_ITEM(space, w_list, index, w_item):
"""Macro form of PyList_SetItem() without error checking. This is normally
@@ -87,7 +87,7 @@
space.call_method(space.w_list, "insert", w_list, space.wrap(index),
w_item)
return 0
-@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PyList_GET_SIZE(space, w_list):
"""Macro form of PyList_Size() without error checking.
"""
diff --git a/pypy/module/cpyext/modsupport.py b/pypy/module/cpyext/modsupport.py
--- a/pypy/module/cpyext/modsupport.py
+++ b/pypy/module/cpyext/modsupport.py
@@ -113,7 +113,7 @@
w_type = space.gettypeobject(Module.typedef)
w_obj_type = space.type(w_obj)
return int(space.is_w(w_type, w_obj_type) or
- space.is_true(space.issubtype(w_obj_type, w_type)))
+ space.issubtype_w(w_obj_type, w_type))
@cpython_api([PyObject], PyObject, result_borrowed=True)
def PyModule_GetDict(space, w_mod):
diff --git a/pypy/module/cpyext/ndarrayobject.py
b/pypy/module/cpyext/ndarrayobject.py
--- a/pypy/module/cpyext/ndarrayobject.py
+++ b/pypy/module/cpyext/ndarrayobject.py
@@ -35,7 +35,7 @@
w_obj_type = space.type(w_obj)
w_type = space.gettypeobject(W_NDimArray.typedef)
return (space.is_w(w_obj_type, w_type) or
- space.is_true(space.issubtype(w_obj_type, w_type)))
+ space.issubtype_w(w_obj_type, w_type))
@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL, header=HEADER)
def _PyArray_CheckExact(space, w_obj):
diff --git a/pypy/module/cpyext/pyfile.py b/pypy/module/cpyext/pyfile.py
--- a/pypy/module/cpyext/pyfile.py
+++ b/pypy/module/cpyext/pyfile.py
@@ -1,10 +1,10 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
- cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, build_type_checkers, fdopen,
- fileno)
+ cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, build_type_checkers, fdopen)
from pypy.module.cpyext.pyobject import PyObject
from pypy.module.cpyext.object import Py_PRINT_RAW
-from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.error import (OperationError, oefmt,
+ exception_from_saved_errno)
from pypy.module._file.interp_file import W_File
PyFile_Check, PyFile_CheckExact = build_type_checkers("File", W_File)
@@ -45,16 +45,29 @@
w_mode = space.wrap(rffi.charp2str(mode))
return space.call_method(space.builtin, 'file', w_filename, w_mode)
-@cpython_api([PyObject], FILEP, error=CANNOT_FAIL)
+@cpython_api([PyObject], FILEP, error=lltype.nullptr(FILEP.TO))
def PyFile_AsFile(space, w_p):
"""Return the file object associated with p as a FILE*.
If the caller will ever use the returned FILE* object while
the GIL is released it must also call the PyFile_IncUseCount() and
PyFile_DecUseCount() functions as appropriate."""
+ if not PyFile_Check(space, w_p):
+ raise oefmt(space.w_IOError, 'first argument must be an open file')
assert isinstance(w_p, W_File)
- return fdopen(space.int_w(space.call_method(w_p, 'fileno')),
- w_p.mode)
+ try:
+ fd = space.int_w(space.call_method(w_p, 'fileno'))
+ mode = w_p.mode
+ except OperationError as e:
+ raise oefmt(space.w_IOError, 'could not call fileno')
+ if (fd < 0 or not mode or mode[0] not in ['r', 'w', 'a', 'U'] or
+ ('U' in mode and ('w' in mode or 'a' in mode))):
+ raise oefmt(space.w_IOError, 'invalid fileno or mode')
+ ret = fdopen(fd, mode)
+ if not ret:
+ raise exception_from_saved_errno(space, space.w_IOError)
+ return ret
+
@cpython_api([FILEP, CONST_STRING, CONST_STRING, rffi.VOIDP], PyObject)
def PyFile_FromFile(space, fp, name, mode, close):
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -54,7 +54,7 @@
except OperationError:
raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m)))
-@cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
+@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject, result_borrowed=True)
def PySequence_Fast_GET_ITEM(space, w_obj, index):
"""Return the ith element of o, assuming that o was returned by
PySequence_Fast(), o is not NULL, and that i is within bounds.
@@ -67,7 +67,7 @@
"PySequence_Fast_GET_ITEM called but object is not a list or "
"sequence")
-@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PySequence_Fast_GET_SIZE(space, w_obj):
"""Returns the length of o, assuming that o was returned by
PySequence_Fast() and that o is not NULL. The size can also be
@@ -82,7 +82,7 @@
"PySequence_Fast_GET_SIZE called but object is not a list or "
"sequence")
-@cpython_api([PyObject], PyObjectP)
+@cpython_api([rffi.VOIDP], PyObjectP)
def PySequence_Fast_ITEMS(space, w_obj):
"""Return the underlying array of PyObject pointers. Assumes that o was
returned
by PySequence_Fast() and o is not NULL.
@@ -119,7 +119,7 @@
space.delslice(w_obj, space.wrap(start), space.wrap(end))
return 0
-@cpython_api([PyObject, Py_ssize_t], PyObject)
+@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject)
def PySequence_ITEM(space, w_obj, i):
"""Return the ith element of o or NULL on failure. Macro form of
PySequence_GetItem() but without checking that
diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py
--- a/pypy/module/cpyext/setobject.py
+++ b/pypy/module/cpyext/setobject.py
@@ -74,7 +74,7 @@
space.call_method(space.w_set, 'clear', w_set)
return 0
-@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PySet_GET_SIZE(space, w_s):
"""Macro form of PySet_Size() without error checking."""
return space.int_w(space.len(w_s))
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -78,8 +78,7 @@
args_w = space.fixedview(w_args)
ref = make_ref(space, w_self)
if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
- not space.is_true(space.issubtype(space.type(args_w[0]),
- space.type(w_self)))):
+ not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
return space.w_NotImplemented
Py_DecRef(space, ref)
return generic_cpy_call(space, func_binary, w_self, args_w[0])
@@ -90,8 +89,7 @@
args_w = space.fixedview(w_args)
ref = make_ref(space, w_self)
if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
- not space.is_true(space.issubtype(space.type(args_w[0]),
- space.type(w_self)))):
+ not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
return space.w_NotImplemented
Py_DecRef(space, ref)
return generic_cpy_call(space, func_binary, args_w[0], w_self)
@@ -113,8 +111,7 @@
args_w = space.fixedview(w_args)
ref = make_ref(space, w_self)
if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
- not space.is_true(space.issubtype(space.type(args_w[0]),
- space.type(w_self)))):
+ not space.issubtype_w(space.type(args_w[0]), space.type(w_self))):
return space.w_NotImplemented
Py_DecRef(space, ref)
arg3 = space.w_None
@@ -346,8 +343,7 @@
check_num_args(space, w_args, 1)
w_other, = space.fixedview(w_args)
- if not space.is_true(space.issubtype(space.type(w_self),
- space.type(w_other))):
+ if not space.issubtype_w(space.type(w_self), space.type(w_other)):
raise oefmt(space.w_TypeError,
"%T.__cmp__(x,y) requires y to be a '%T', not a '%T'",
w_self, w_self, w_other)
diff --git a/pypy/module/cpyext/test/test_bytesobject.py
b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -288,6 +288,24 @@
# This does not test much, but at least the refcounts are checked.
assert module.test_intern_inplace('s') == 's'
+ def test_bytes_macros(self):
+ """The PyString_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyString_FromString("");
+ PyStringObject* u = (PyStringObject*)o;
+
+ PyString_GET_SIZE(u);
+ PyString_GET_SIZE(o);
+
+ PyString_AS_STRING(o);
+ PyString_AS_STRING(u);
+
+ return o;
+ """)])
+ assert module.test_macro_invocations() == ''
+
def test_hash_and_state(self):
module = self.import_extension('foo', [
("test_hash", "METH_VARARGS",
diff --git a/pypy/module/cpyext/test/test_datetime.py
b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -4,7 +4,8 @@
class TestDatetime(BaseApiTest):
def test_date(self, space, api):
- w_date = api.PyDate_FromDate(2010, 06, 03)
+ date_api = api._PyDateTime_Import()
+ w_date = api._PyDate_FromDate(2010, 06, 03, date_api.c_DateType)
assert space.unwrap(space.str(w_date)) == '2010-06-03'
assert api.PyDate_Check(w_date)
@@ -15,7 +16,9 @@
assert api.PyDateTime_GET_DAY(w_date) == 3
def test_time(self, space, api):
- w_time = api.PyTime_FromTime(23, 15, 40, 123456)
+ date_api = api._PyDateTime_Import()
+ w_time = api._PyTime_FromTime(23, 15, 40, 123456,
+ space.w_None, date_api.c_TimeType)
assert space.unwrap(space.str(w_time)) == '23:15:40.123456'
assert api.PyTime_Check(w_time)
@@ -27,8 +30,10 @@
assert api.PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
def test_datetime(self, space, api):
- w_date = api.PyDateTime_FromDateAndTime(
- 2010, 06, 03, 23, 15, 40, 123456)
+ date_api = api._PyDateTime_Import()
+ w_date = api._PyDateTime_FromDateAndTime(
+ 2010, 06, 03, 23, 15, 40, 123456,
+ space.w_None, date_api.c_DateTimeType)
assert space.unwrap(space.str(w_date)) == '2010-06-03 23:15:40.123456'
assert api.PyDateTime_Check(w_date)
@@ -45,6 +50,7 @@
assert api.PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
def test_delta(self, space, api):
+ date_api = api._PyDateTime_Import()
w_delta = space.appexec(
[space.wrap(3), space.wrap(15)], """(days, seconds):
from datetime import timedelta
@@ -53,7 +59,7 @@
assert api.PyDelta_Check(w_delta)
assert api.PyDelta_CheckExact(w_delta)
- w_delta = api.PyDelta_FromDSU(10, 20, 30)
+ w_delta = api._PyDelta_FromDelta(10, 20, 30, True,
date_api.c_DeltaType)
assert api.PyDelta_Check(w_delta)
assert api.PyDelta_CheckExact(w_delta)
@@ -117,3 +123,139 @@
datetime.timedelta,
datetime.tzinfo)
module.clear_types()
+
+ def test_constructors(self):
+ module = self.import_extension('foo', [
+ ("new_date", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->Date_FromDate(
+ 2000, 6, 6, PyDateTimeAPI->DateType);
+ """),
+ ("new_time", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->Time_FromTime(
+ 6, 6, 6, 6, Py_None, PyDateTimeAPI->TimeType);
+ """),
+ ("new_datetime", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->DateTime_FromDateAndTime(
+ 2000, 6, 6, 6, 6, 6, 6, Py_None,
+ PyDateTimeAPI->DateTimeType);
+ """),
+ ])
+ import datetime
+ assert module.new_date() == datetime.date(2000, 6, 6)
+ assert module.new_time() == datetime.time(6, 6, 6, 6)
+ assert module.new_datetime() == datetime.datetime(
+ 2000, 6, 6, 6, 6, 6, 6)
+
+ def test_macros(self):
+ module = self.import_extension('foo', [
+ ("test_date_macros", "METH_NOARGS",
+ """
+ PyObject* obj;
+ PyDateTime_Date* d;
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ obj = PyDate_FromDate(2000, 6, 6);
+ d = (PyDateTime_Date*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(d);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(d);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(d);
+
+ return obj;
+ """),
+ ("test_datetime_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6,
6, 6);
+ PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(dt);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(dt);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(dt);
+
+ PyDateTime_DATE_GET_HOUR(obj);
+ PyDateTime_DATE_GET_HOUR(dt);
+
+ PyDateTime_DATE_GET_MINUTE(obj);
+ PyDateTime_DATE_GET_MINUTE(dt);
+
+ PyDateTime_DATE_GET_SECOND(obj);
+ PyDateTime_DATE_GET_SECOND(dt);
+
+ PyDateTime_DATE_GET_MICROSECOND(obj);
+ PyDateTime_DATE_GET_MICROSECOND(dt);
+
+ return obj;
+ """),
+ ("test_time_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyTime_FromTime(6, 6, 6, 6);
+ PyDateTime_Time* t = (PyDateTime_Time*)obj;
+
+ PyDateTime_TIME_GET_HOUR(obj);
+ PyDateTime_TIME_GET_HOUR(t);
+
+ PyDateTime_TIME_GET_MINUTE(obj);
+ PyDateTime_TIME_GET_MINUTE(t);
+
+ PyDateTime_TIME_GET_SECOND(obj);
+ PyDateTime_TIME_GET_SECOND(t);
+
+ PyDateTime_TIME_GET_MICROSECOND(obj);
+ PyDateTime_TIME_GET_MICROSECOND(t);
+
+ return obj;
+ """),
+ ("test_delta_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDelta_FromDSU(6, 6, 6);
+ PyDateTime_Delta* delta = (PyDateTime_Delta*)obj;
+
+ PyDateTime_DELTA_GET_DAYS(obj);
+ PyDateTime_DELTA_GET_DAYS(delta);
+
+ PyDateTime_DELTA_GET_SECONDS(obj);
+ PyDateTime_DELTA_GET_SECONDS(delta);
+
+ PyDateTime_DELTA_GET_MICROSECONDS(obj);
+ PyDateTime_DELTA_GET_MICROSECONDS(delta);
+
+ return obj;
+ """),
+ ])
+ import datetime
+ assert module.test_date_macros() == datetime.date(2000, 6, 6)
+ assert module.test_datetime_macros() == datetime.datetime(
+ 2000, 6, 6, 6, 6, 6, 6)
+ assert module.test_time_macros() == datetime.time(6, 6, 6, 6)
+ assert module.test_delta_macros() == datetime.timedelta(6, 6, 6)
diff --git a/pypy/module/cpyext/test/test_floatobject.py
b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -77,3 +77,19 @@
neginf = module.return_neginf()
assert neginf < 0
assert math.isinf(neginf)
+
+ def test_macro_accepts_wrong_pointer_type(self):
+ import math
+
+ module = self.import_extension('foo', [
+ ("test_macros", "METH_NOARGS",
+ """
+ PyObject* o = PyFloat_FromDouble(1.0);
+ // no PyFloatObject
+ char* dumb_pointer = (char*)o;
+
+ PyFloat_AS_DOUBLE(o);
+ PyFloat_AS_DOUBLE(dumb_pointer);
+
+ Py_RETURN_NONE;"""),
+ ])
diff --git a/pypy/module/cpyext/test/test_intobject.py
b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -191,3 +191,17 @@
i = mod.test_int()
assert isinstance(i, int)
assert i == 42
+
+ def test_int_macros(self):
+ mod = self.import_extension('foo', [
+ ("test_macros", "METH_NOARGS",
+ """
+ PyObject * obj = PyInt_FromLong(42);
+ PyIntObject * i = (PyIntObject*)obj;
+ PyInt_AS_LONG(obj);
+ PyInt_AS_LONG(i);
+ Py_RETURN_NONE;
+ """
+ ),
+ ])
+
diff --git a/pypy/module/cpyext/test/test_listobject.py
b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -137,6 +137,33 @@
module.setlistitem(l,0)
assert l == [None, 2, 3]
+ def test_list_macros(self):
+ """The PyList_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyList_New(2);
+ PyListObject* l = (PyListObject*)o;
+
+
+ Py_INCREF(o);
+ PyList_SET_ITEM(o, 0, o);
+ Py_INCREF(o);
+ PyList_SET_ITEM(l, 1, o);
+
+ PyList_GET_ITEM(o, 0);
+ PyList_GET_ITEM(l, 1);
+
+ PyList_GET_SIZE(o);
+ PyList_GET_SIZE(l);
+
+ return o;
+ """
+ )
+ ])
+ x = module.test_macro_invocations()
+ assert x[0] is x[1] is x
+
def test_get_item_macro(self):
module = self.import_extension('foo', [
("test_get_item", "METH_NOARGS",
diff --git a/pypy/module/cpyext/test/test_sequence.py
b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -155,6 +155,29 @@
result = api.PySequence_Index(w_gen, w_tofind)
assert result == 4
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_sequence_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject *o = PyList_New(0);
+ PyListObject* l;
+ PyList_Append(o, o);
+ l = (PyListObject*)o;
+
+ PySequence_Fast_GET_ITEM(o, 0);
+ PySequence_Fast_GET_ITEM(l, 0);
+
+ PySequence_Fast_GET_SIZE(o);
+ PySequence_Fast_GET_SIZE(l);
+
+ PySequence_ITEM(o, 0);
+ PySequence_ITEM(l, 0);
+
+ return o;
+ """
+ )
+ ])
class TestCPyListStrategy(BaseApiTest):
def test_getitem_setitem(self, space, api):
w_l = space.wrap([1, 2, 3, 4])
diff --git a/pypy/module/cpyext/test/test_setobject.py
b/pypy/module/cpyext/test/test_setobject.py
--- a/pypy/module/cpyext/test/test_setobject.py
+++ b/pypy/module/cpyext/test/test_setobject.py
@@ -2,6 +2,7 @@
from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -45,3 +46,20 @@
w_frozenset = space.newfrozenset([space.wrap(i) for i in [1, 2, 3, 4]])
assert api.PyAnySet_CheckExact(w_set)
assert api.PyAnySet_CheckExact(w_frozenset)
+
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_set_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject* o = PySet_New(NULL);
+ // no PySetObject
+ char* dumb_pointer = (char*) o;
+
+ PySet_GET_SIZE(o);
+ PySet_GET_SIZE(dumb_pointer);
+
+ return o;
+ """
+ )
+ ])
diff --git a/pypy/module/cpyext/test/test_translate.py
b/pypy/module/cpyext/test/test_translate.py
--- a/pypy/module/cpyext/test/test_translate.py
+++ b/pypy/module/cpyext/test/test_translate.py
@@ -11,11 +11,11 @@
FT = lltype.FuncType([], lltype.Signed)
FTPTR = lltype.Ptr(FT)
- def make_wrapper(space, func, gil=None):
+ def make_wrapper(self, space):
def wrapper():
- return func(space)
+ return self.callable(space)
return wrapper
- monkeypatch.setattr(pypy.module.cpyext.api, 'make_wrapper', make_wrapper)
+ monkeypatch.setattr(pypy.module.cpyext.api.ApiFunction, '_make_wrapper',
make_wrapper)
@specialize.memo()
def get_tp_function(space, typedef):
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -744,7 +744,7 @@
int intval;
PyObject *name;
- if (!PyArg_ParseTuple(args, "l", &intval))
+ if (!PyArg_ParseTuple(args, "i", &intval))
return NULL;
IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT;
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
@@ -111,6 +111,26 @@
assert isinstance(res, str)
assert res == 'caf?'
+ def test_unicode_macros(self):
+ """The PyUnicode_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyUnicode_FromString("");
+ PyUnicodeObject* u = (PyUnicodeObject*)o;
+
+ PyUnicode_GET_SIZE(u);
+ PyUnicode_GET_SIZE(o);
+
+ PyUnicode_GET_DATA_SIZE(u);
+ PyUnicode_GET_DATA_SIZE(o);
+
+ PyUnicode_AS_UNICODE(o);
+ PyUnicode_AS_UNICODE(u);
+ return o;
+ """)])
+ assert module.test_macro_invocations() == u''
+
class TestUnicode(BaseApiTest):
def test_unicodeobject(self, space, api):
assert api.PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
diff --git a/pypy/module/cpyext/test/test_weakref.py
b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -7,7 +7,6 @@
w_ref = api.PyWeakref_NewRef(w_obj, space.w_None)
assert w_ref is not None
assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj)
- assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj)
assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj)
w_obj = space.newtuple([])
@@ -34,3 +33,26 @@
del w_obj
import gc; gc.collect()
assert space.is_w(api.PyWeakref_LockObject(w_ref), space.w_None)
+
+
+class AppTestWeakReference(AppTestCpythonExtensionBase):
+
+ def test_weakref_macro(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ // PyExc_Warning is some weak-reffable PyObject*.
+ char* dumb_pointer;
+ PyObject* weakref_obj = PyWeakref_NewRef(PyExc_Warning, NULL);
+ if (!weakref_obj) return weakref_obj;
+ // No public PyWeakReference type.
+ dumb_pointer = (char*) weakref_obj;
+
+ PyWeakref_GET_OBJECT(weakref_obj);
+ PyWeakref_GET_OBJECT(dumb_pointer);
+
+ return weakref_obj;
+ """
+ )
+ ])
+ module.test_macro_cast()
diff --git a/pypy/module/cpyext/tupleobject.py
b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -47,7 +47,7 @@
def tuple_check_ref(space, ref):
w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
return (w_type is space.w_tuple or
- space.is_true(space.issubtype(w_type, space.w_tuple)))
+ space.issubtype_w(w_type, space.w_tuple))
def new_empty_tuple(space, length):
"""
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -18,8 +18,9 @@
Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
PyObjectFields, Py_TPFLAGS_BASETYPE)
-from pypy.module.cpyext.methodobject import (
- PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef)
+from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
+ PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
+ W_PyCMethodObject, W_PyCFunctionObject)
from pypy.module.cpyext.modsupport import convert_method_defs
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
@@ -125,6 +126,14 @@
cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields,
PyGetSetDescrObjectStruct, level=2)
+PyMethodDescrObjectStruct = lltype.ForwardReference()
+PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct)
+PyMethodDescrObjectFields = PyDescrObjectFields + (
+ ("d_method", lltype.Ptr(PyMethodDef)),
+ )
+cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields,
+ PyMethodDescrObjectStruct, level=2)
+
@bootstrap_function
def init_memberdescrobject(space):
make_typedescr(W_MemberDescr.typedef,
@@ -136,6 +145,16 @@
basestruct=PyGetSetDescrObject.TO,
attach=getsetdescr_attach,
)
+ make_typedescr(W_PyCClassMethodObject.typedef,
+ basestruct=PyMethodDescrObject.TO,
+ attach=methoddescr_attach,
+ realize=classmethoddescr_realize,
+ )
+ make_typedescr(W_PyCMethodObject.typedef,
+ basestruct=PyMethodDescrObject.TO,
+ attach=methoddescr_attach,
+ realize=methoddescr_realize,
+ )
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit