Skip to content

Commit

Permalink
Detect situation where functions are called as methods
Browse files Browse the repository at this point in the history
Fix #2156
  • Loading branch information
serge-sans-paille committed Dec 5, 2023
1 parent e2f1044 commit 3529a55
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 2 deletions.
11 changes: 11 additions & 0 deletions pythran/tests/test_normalize_methods.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pythran
from pythran.tests import TestEnv

import numpy
Expand Down Expand Up @@ -124,6 +125,16 @@ def test_dispatch_update(self):
{1}, {1:1},
dispatch_update=[Set[int], Dict[int,int]])

def test_invalid_method_call(self):
code = '''
def np_asarray7(sRate=44100):
import numpy as np
x = np.expand_dims(np.ones(sRate),-1)
x = np.maximum(np.minimum(x,.5),-.5).asarray() # asarray is not a method
return x'''
with self.assertRaises(pythran.syntax.PythranSyntaxError):
self.run_test(code, 30, np_asarray7=[int])

def test_capture_bound_method(self):
code = '''
def capture_bound_method(fname, r):
Expand Down
15 changes: 13 additions & 2 deletions pythran/transformations/normalize_method_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class NormalizeMethodCalls(Transformation):

def __init__(self):
Transformation.__init__(self, Globals, Ancestors)
self.imports = {'builtins': 'builtins'}
self.imports = {'builtins': 'builtins',
mangle('__dispatch__'): '__dispatch__'}
self.to_import = set()

def visit_Module(self, node):
Expand Down Expand Up @@ -156,6 +157,7 @@ def visit_Attribute(self, node):
self.update = True
mod = methods[node.attr][0]
self.to_import.add(mangle(mod[0]))
self.to_import.add(mangle('functools'))
func = self.attr_to_func(node)
z = ast.Call(
ast.Attribute(
Expand Down Expand Up @@ -250,7 +252,16 @@ def visit_Call(self, node):
self.to_import.add(mangle(mod[0]))
node.func = self.attr_to_func(node.func)
# else methods have been called using function syntax
if node.func.attr in methods or node.func.attr in functions:

ismethod = node.func.attr in methods
isfunction = node.func.attr in functions
if ismethod or isfunction: # i.e. if it's callable
if not ismethod and self.baseobj(node.func.value):
raise PythranSyntaxError(
"'{}' called as a method while it's a function"
.format(node.func.attr),
node)

# Now, methods and function have both function syntax
def rec(path, cur_module):
"""
Expand Down

0 comments on commit 3529a55

Please sign in to comment.