Skip to content

Commit

Permalink
Tests and changes for decorators (#102)
Browse files Browse the repository at this point in the history
- Decorator testing.
- Actually capture the decorated function for @tf.function decorated functions.
- Add `pytest.mark.skip` summary.
- Use pytest summary for all Python analysis. There are some decorators it may work for.
  - Test pytest decorator.
  • Loading branch information
khatchad authored Apr 30, 2024
1 parent 857a4ea commit 43f337c
Show file tree
Hide file tree
Showing 19 changed files with 310 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,12 @@ public void testDecorator10()
test("tf2_testing_decorator10.py", "returned", 1, 1, 2);
}

@Test
public void testDecorator11()
throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
test("tf2_testing_decorator11.py", "C.returned", 1, 1, 3);
}

@Test
public void testDataset()
throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
Expand Down Expand Up @@ -2666,6 +2672,82 @@ public void testAbstractMethod2() throws ClassHierarchyException, CancelExceptio
test("tf2_test_abstract_method2.py", "C.f", 1, 1, 3);
}

@Test
public void testAbstractMethod3() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_abstract_method3.py", "C.f", 1, 1, 3);
}

@Test
public void testDecoratedMethod() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method.py", "f", 1, 1, 2);
}

@Test
public void testDecoratedMethod2() throws ClassHierarchyException, CancelException, IOException {
// NOTE: Change to 1, 1, 2 once https://github.com/wala/ML/issues/188 is fixed.
test("tf2_test_decorated_method2.py", "f", 0, 0);
}

@Test
public void testDecoratedMethod3() throws ClassHierarchyException, CancelException, IOException {
// NOTE: Change to 1, 1, 2 once https://github.com/wala/ML/issues/190 is fixed.
test("tf2_test_decorated_method3.py", "raffi", 0, 0);
}

@Test
public void testDecoratedMethod4() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method4.py", "raffi", 1, 1, 2);
}

@Test
public void testDecoratedMethod5() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method5.py", "raffi", 1, 1, 2);
}

@Test
public void testDecoratedMethod6() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method6.py", "f", 1, 1, 2);
}

@Test
public void testDecoratedMethod7() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method7.py", "f", 1, 1, 2);
}

@Test
public void testDecoratedMethod8() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method8.py", "f", 1, 1, 2);
}

/** This decorator isn't defined. Thus, we shouldn't have a CG node for it. */
@Test
public void testDecoratedMethod9() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method9.py", "f", 0, 0);
}

@Test
public void testDecoratedMethod10() throws ClassHierarchyException, CancelException, IOException {
// NOTE: Change to 1, 1, 2 once https://github.com/wala/ML/issues/190 is fixed.
test("tf2_test_decorated_method10.py", "f", 0, 0);
}

@Test
public void testDecoratedMethod11() throws ClassHierarchyException, CancelException, IOException {
test("tf2_test_decorated_method11.py", "f", 1, 1, 2);
}

@Test
public void testDecoratedMethod12() throws ClassHierarchyException, CancelException, IOException {
// NOTE: Change to 1, 1, 2 once https://github.com/wala/ML/issues/188 is fixed.
test("tf2_test_decorated_method12.py", "f", 0, 0);
}

@Test
public void testDecoratedMethod13() throws ClassHierarchyException, CancelException, IOException {
// NOTE: Change to 1, 1, 2 once https://github.com/wala/ML/issues/190 is fixed.
test("tf2_test_decorated_method13.py", "f", 0, 0);
}

private void test(
String filename,
String functionName,
Expand Down
2 changes: 1 addition & 1 deletion com.ibm.wala.cast.python.ml/data/tensorflow.xml
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@
</class>
<class name="function" allocatable="true">
<!-- These parameters are from TensorFlow v.2.9 https://www.tensorflow.org/versions/r2.9/api_docs/python/tf/function -->
<method name="do" descriptor="()LRoot;" numArgs="10" paramNames="func input_signature autograph jit_compile reduce_retracing experimental_implements experimental_autograph_options experimental_relax_shapes experimental_compile experimental_follow_type_hints">
<method name="do" descriptor="()LRoot;" numArgs="11" paramNames="self func input_signature autograph jit_compile reduce_retracing experimental_implements experimental_autograph_options experimental_relax_shapes experimental_compile experimental_follow_type_hints">
<new def="params" class="Ltensorflow/class/Function" />
<putfield class="LRoot" field="func" fieldType="LRoot" ref="params" value="func" />
<putfield class="LRoot" field="input_signature" fieldType="LRoot" ref="params" value="input_signature" />
Expand Down
14 changes: 14 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_abstract_method3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# From https://blog.teclado.com/python-abc-abstract-base-classes/#introducing-abstract-classes.
import tensorflow as tf
from abc import ABC, abstractmethod


class C(ABC):

@abstractmethod
def f(self, x):
assert isinstance(x, tf.Tensor)


c = C()
c.f(tf.constant(1))
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import tensorflow as tf


def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
13 changes: 13 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method10.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import tensorflow as tf


def mama(my_func):
return my_func


@mama
def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
10 changes: 10 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method11.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import tensorflow as tf
import pytest


@pytest.mark.skip
def f(a):
assert isinstance(a, tf.Tensor)


f(tf.constant(1))
27 changes: 27 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method12.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Test https://github.com/wala/ML/issues/188.

import tensorflow as tf


def mama(test=None):
assert test == "Hello"

def _mama(func):

def core(*args, **kwargs):
assert isinstance(args[0], tf.Tensor)
return func(*args, **kwargs)

return core

return _mama


@mama(test="Hello")
def f(x):
assert isinstance(x, tf.Tensor)
return 5


res = f(tf.constant(1))
assert res == 5
13 changes: 13 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method13.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import tensorflow as tf


def mama(my_func=None):
return my_func


@mama
def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
20 changes: 20 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Test for https://github.com/wala/ML/issues/188.

import tensorflow as tf


def mama(fun):

def wrapper_fun(*args, **kwargs):
assert isinstance(args[0], tf.Tensor)
fun(*args, **kwargs)

return wrapper_fun


@mama
def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
13 changes: 13 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import tensorflow as tf


def mama(fun):
return fun


@mama
def raffi(x):
assert isinstance(x, tf.Tensor)


raffi(tf.constant(1))
12 changes: 12 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import tensorflow as tf


def mama(fun):
return fun


def raffi(x):
assert isinstance(x, tf.Tensor)


raffi(tf.constant(1))
12 changes: 12 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import tensorflow as tf


def mama(fun):
return fun


def raffi(x):
assert isinstance(x, tf.Tensor)


mama(raffi(tf.constant(1)))
17 changes: 17 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import tensorflow as tf


def mama(fun):

def wrapper_fun(*args, **kwargs):
assert isinstance(args[0], tf.Tensor)
fun(*args, **kwargs)

return wrapper_fun


def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
17 changes: 17 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_test_decorated_method7.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import tensorflow as tf


def mama(fun):

def wrapper_fun(*args, **kwargs):
assert isinstance(args[0], tf.Tensor)
fun(*args, **kwargs)

return wrapper_fun


def f(x):
assert isinstance(x, tf.Tensor)


mama(f(tf.constant(1)))
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import tensorflow as tf


def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import tensorflow as tf


@mama
def f(x):
assert isinstance(x, tf.Tensor)


f(tf.constant(1))
16 changes: 16 additions & 0 deletions com.ibm.wala.cast.python.test/data/tf2_testing_decorator11.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import tensorflow as tf


class C:

@tf.function()
def returned(self, a):
assert isinstance(a, tf.Tensor)
return a


a = tf.range(5)
assert isinstance(a, tf.Tensor)
c = C()
b = c.returned(a)
assert isinstance(b, tf.Tensor)
17 changes: 17 additions & 0 deletions com.ibm.wala.cast.python/data/pytest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<putfield class="LRoot" field="mark" fieldType="LRoot" ref="x" value="mark" />
<new def="parametrize" class="Lpytest/class/parametrize" />
<putfield class="LRoot" field="parametrize" fieldType="LRoot" ref="mark" value="parametrize" />
<new def="skip" class="Lpytest/class/skip" />
<putfield class="LRoot" field="skip" fieldType="LRoot" ref="mark" value="skip" />
<return value="x" />
</method>
</class>
Expand All @@ -29,6 +31,21 @@
<return value="closure" />
</method>
</class>
<class name="Skip" allocatable="true">
<method name="do" descriptor="()LRoot;" numArgs="2" paramNames="self test">
<putfield class="LRoot" field="params" fieldType="LRoot" ref="test" value="self" />
<return value="test" />
</method>
</class>
<class name="skip" allocatable="true">
<!-- https://docs.pytest.org/en/8.2.x/reference/reference.html#pytest.mark.skip -->
<method name="do" descriptor="()LRoot;" numArgs="2" paramNames="self reason">
<new def="closure" class="Lpytest/class/Skip" />
<putfield class="LRoot" field="test" fieldType="LRoot" ref="closure" value="self" />
<putfield class="LRoot" field="params" fieldType="LRoot" ref="closure" value="reason" />
<return value="closure" />
</method>
</class>
</package>
</classloader>
</summary-spec>
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ protected void addBypassLogic(IClassHierarchy cha, AnalysisOptions options) {
addSummaryBypassLogic(options, "flask.xml");
addSummaryBypassLogic(options, "pandas.xml");
addSummaryBypassLogic(options, "functools.xml");
addSummaryBypassLogic(options, "pytest.xml");
}

@Override
Expand Down

0 comments on commit 43f337c

Please sign in to comment.