Commit 4ed665be authored by scoder's avatar scoder Committed by GitHub

Merge pull request #2469 from aguinet/fix/pythran_numpy

Pythran: verify that pythran supports called Numpy APIs
parents fb0e935a 779d5db1
......@@ -43,9 +43,10 @@ from . import Future
from ..Debugging import print_call_chain
from .DebugFlags import debug_disposal_code, debug_temp_alloc, \
debug_coercion
from .Pythran import to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type, \
is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran, \
pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type
from .Pythran import (to_pythran, is_pythran_supported_type, is_pythran_supported_operation_type,
is_pythran_expr, pythran_func_type, pythran_binop_type, pythran_unaryop_type, has_np_pythran,
pythran_indexing_code, pythran_indexing_type, is_pythran_supported_node_or_none, pythran_type,
pythran_is_numpy_func_supported, pythran_get_func_include_file, pythran_functor)
from .PyrexTypes import PythranExpr
try:
......@@ -5408,7 +5409,8 @@ class SimpleCallNode(CallNode):
func_type = self.function_type()
self.is_numpy_call_with_exprs = False
if has_np_pythran(env) and self.function.is_numpy_attribute:
if (has_np_pythran(env) and function.is_numpy_attribute and
pythran_is_numpy_func_supported(function)):
has_pythran_args = True
self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple = self.arg_tuple.analyse_types(env)
......@@ -5416,12 +5418,12 @@ class SimpleCallNode(CallNode):
has_pythran_args &= is_pythran_supported_node_or_none(arg)
self.is_numpy_call_with_exprs = bool(has_pythran_args)
if self.is_numpy_call_with_exprs:
env.add_include_file("pythonic/numpy/%s.hpp" % self.function.attribute)
env.add_include_file(pythran_get_func_include_file(function))
return NumPyMethodCallNode.from_node(
self,
function=self.function,
function=function,
arg_tuple=self.arg_tuple,
type=PythranExpr(pythran_func_type(self.function.attribute, self.arg_tuple.args)),
type=PythranExpr(pythran_func_type(function, self.arg_tuple.args)),
)
elif func_type.is_pyobject:
self.arg_tuple = TupleNode(self.pos, args = self.args)
......@@ -5839,10 +5841,10 @@ class NumPyMethodCallNode(SimpleCallNode):
code.putln("// function evaluation code for numpy function")
code.putln("__Pyx_call_destructor(%s);" % self.result())
code.putln("new (&%s) decltype(%s){pythonic::numpy::functor::%s{}(%s)};" % (
code.putln("new (&%s) decltype(%s){%s{}(%s)};" % (
self.result(),
self.result(),
self.function.attribute,
pythran_functor(self.function),
", ".join(a.pythran_result() for a in args)))
......
......@@ -613,7 +613,8 @@ class TrackNumpyAttributes(VisitorTransform, SkipDeclarations):
def visit_AttributeNode(self, node):
self.visitchildren(node)
if node.obj.is_name and node.obj.name in self.numpy_module_names:
if (node.obj.is_name and node.obj.name in self.numpy_module_names) or \
node.obj.is_numpy_attribute:
node.is_numpy_attribute = True
return node
......
......@@ -6,16 +6,20 @@ from .PyrexTypes import CType, CTypedefType, CStructOrUnionType
import cython
try:
import pythran
_pythran_available = True
except ImportError:
_pythran_available = False
# Pythran/Numpy specific operations
def has_np_pythran(env):
while env is not None:
directives = getattr(env, 'directives', None)
if directives and env.directives.get('np_pythran', False):
return True
env = env.outer_scope
if env is None:
return False
directives = getattr(env, 'directives', None)
return (directives and directives.get('np_pythran', False))
@cython.ccall
def is_pythran_supported_dtype(type_):
......@@ -111,10 +115,32 @@ def pythran_indexing_type(type_, indices):
def pythran_indexing_code(indices):
return _index_access(_index_code, indices)
def np_func_to_list(func):
if not func.is_numpy_attribute:
return []
return np_func_to_list(func.obj) + [func.attribute]
if _pythran_available:
def pythran_is_numpy_func_supported(func):
CurF = pythran.tables.MODULES['numpy']
FL = np_func_to_list(func)
for F in FL:
CurF = CurF.get(F, None)
if CurF is None:
return False
return True
else:
def pythran_is_numpy_func_supported(name):
return False
def pythran_functor(func):
func = np_func_to_list(func)
submodules = "::".join(func[:-1] + ["functor"])
return "pythonic::numpy::%s::%s" % (submodules, func[-1])
def pythran_func_type(func, args):
args = ",".join(("std::declval<%s>()" % pythran_type(a.type) for a in args))
return "decltype(pythonic::numpy::functor::%s{}(%s))" % (func, args)
return "decltype(%s{}(%s))" % (pythran_functor(func), args)
@cython.ccall
......@@ -168,6 +194,9 @@ def is_pythran_buffer(type_):
return (type_.is_numpy_buffer and is_pythran_supported_dtype(type_.dtype) and
type_.mode in ("c", "strided") and not type_.cast)
def pythran_get_func_include_file(func):
func = np_func_to_list(func)
return "pythonic/include/numpy/%s.hpp" % "/".join(func)
def include_pythran_generic(env):
# Generic files
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment