diff --git a/com.ibm.wala.cast.python.ml.test/source/com/ibm/wala/cast/python/ml/test/TestTensorflow2Model.java b/com.ibm.wala.cast.python.ml.test/source/com/ibm/wala/cast/python/ml/test/TestTensorflow2Model.java
index 55650af55..0706e9b5b 100644
--- a/com.ibm.wala.cast.python.ml.test/source/com/ibm/wala/cast/python/ml/test/TestTensorflow2Model.java
+++ b/com.ibm.wala.cast.python.ml.test/source/com/ibm/wala/cast/python/ml/test/TestTensorflow2Model.java
@@ -814,6 +814,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 {
@@ -3621,6 +3627,94 @@ 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 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method2.py", "f", 1, 1, 2);
+ }
+
+ @Test
+ public void testDecoratedMethod3() throws ClassHierarchyException, CancelException, IOException {
+ // NOTE: Change to 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method3.py", "raffi", 1, 1, 2);
+ }
+
+ @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 {
+ // NOTE: Change to 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method9.py", "f", 1, 1, 2);
+ }
+
+ @Test
+ public void testDecoratedMethod10() throws ClassHierarchyException, CancelException, IOException {
+ // NOTE: Change to 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method10.py", "f", 1, 1, 2);
+ }
+
+ @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 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method12.py", "f", 1, 1, 2);
+ }
+
+ @Test
+ public void testDecoratedMethod13() throws ClassHierarchyException, CancelException, IOException {
+ // NOTE: Change to 0, 0 once https://github.com/wala/ML/issues/147 is fixed.
+ test("tf2_test_decorated_method13.py", "f", 1, 1, 2);
+ }
+
+ @Test
+ public void testDecoratedFunctions()
+ throws ClassHierarchyException, CancelException, IOException {
+ test("tf2_test_decorated_functions.py", "dummy_fun", 1, 1, 2);
+ test("tf2_test_decorated_functions.py", "dummy_test", 1, 1, 2);
+ test("tf2_test_decorated_functions.py", "test_function", 1, 1, 2);
+ test("tf2_test_decorated_functions.py", "test_function2", 1, 1, 2);
+ test("tf2_test_decorated_functions.py", "test_function3", 1, 1, 2);
+ test("tf2_test_decorated_functions.py", "test_function4", 1, 1, 2);
+ }
+
private void test(
String filename,
String functionName,
diff --git a/com.ibm.wala.cast.python.ml/data/tensorflow.xml b/com.ibm.wala.cast.python.ml/data/tensorflow.xml
index 0148ac7d8..adf31dc52 100644
--- a/com.ibm.wala.cast.python.ml/data/tensorflow.xml
+++ b/com.ibm.wala.cast.python.ml/data/tensorflow.xml
@@ -252,6 +252,12 @@
+
+
+
+
+
+
@@ -276,7 +282,7 @@
-
+
@@ -291,6 +297,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_abstract_method3.py b/com.ibm.wala.cast.python.test/data/tf2_test_abstract_method3.py
new file mode 100644
index 000000000..156ca76f9
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_abstract_method3.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_functions.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_functions.py
new file mode 100644
index 000000000..57cfd06cf
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_functions.py
@@ -0,0 +1,41 @@
+import tensorflow
+import pytest
+import sys
+
+
+@tensorflow.autograph.experimental.do_not_convert
+def dummy_fun(a):
+ pass
+
+
+@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
+def dummy_test(x, test_input, expected):
+ pass
+
+
+@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
+def test_function(x):
+ pass
+
+
+@pytest.mark.skip(reason="requires python3.10 or higher")
+def test_function2(x):
+ pass
+
+
+@pytest.mark.skip("requires python3.10 or higher")
+def test_function3(x):
+ pass
+
+
+@pytest.mark.skip
+def test_function4(x):
+ pass
+
+
+dummy_fun(tensorflow.constant(1))
+dummy_test(tensorflow.constant(1), "1", "1")
+test_function(tensorflow.constant(1))
+test_function2(tensorflow.constant(1))
+test_function3(tensorflow.constant(1))
+test_function4(tensorflow.constant(1))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method.py
new file mode 100644
index 000000000..bb0c78b33
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method.py
@@ -0,0 +1,8 @@
+import tensorflow as tf
+
+
+def f(x):
+ assert isinstance(x, tf.Tensor)
+
+
+f(tf.constant(1))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method10.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method10.py
new file mode 100644
index 000000000..b47d91529
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method10.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method11.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method11.py
new file mode 100644
index 000000000..5acd08010
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method11.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method12.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method12.py
new file mode 100644
index 000000000..508fe10a7
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method12.py
@@ -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
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method13.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method13.py
new file mode 100644
index 000000000..a50d7b516
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method13.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method2.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method2.py
new file mode 100644
index 000000000..4530abd96
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method2.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method3.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method3.py
new file mode 100644
index 000000000..7219630a0
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method3.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method4.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method4.py
new file mode 100644
index 000000000..10a460ed6
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method4.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method5.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method5.py
new file mode 100644
index 000000000..8d2d86a4d
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method5.py
@@ -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)))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method6.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method6.py
new file mode 100644
index 000000000..a72105b73
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method6.py
@@ -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))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method7.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method7.py
new file mode 100644
index 000000000..e88d7ab66
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method7.py
@@ -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)))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method8.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method8.py
new file mode 100644
index 000000000..bb0c78b33
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method8.py
@@ -0,0 +1,8 @@
+import tensorflow as tf
+
+
+def f(x):
+ assert isinstance(x, tf.Tensor)
+
+
+f(tf.constant(1))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method9.py b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method9.py
new file mode 100644
index 000000000..fca8bacf6
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_test_decorated_method9.py
@@ -0,0 +1,9 @@
+import tensorflow as tf
+
+
+@mama
+def f(x):
+ assert isinstance(x, tf.Tensor)
+
+
+f(tf.constant(1))
diff --git a/com.ibm.wala.cast.python.test/data/tf2_testing_decorator11.py b/com.ibm.wala.cast.python.test/data/tf2_testing_decorator11.py
new file mode 100644
index 000000000..1af119da2
--- /dev/null
+++ b/com.ibm.wala.cast.python.test/data/tf2_testing_decorator11.py
@@ -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)
diff --git a/com.ibm.wala.cast.python/data/pytest.xml b/com.ibm.wala.cast.python/data/pytest.xml
index b84a73c2e..a35612ed1 100644
--- a/com.ibm.wala.cast.python/data/pytest.xml
+++ b/com.ibm.wala.cast.python/data/pytest.xml
@@ -10,6 +10,10 @@
+
+
+
+
@@ -29,6 +33,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/com.ibm.wala.cast.python/source/com/ibm/wala/cast/python/client/PythonAnalysisEngine.java b/com.ibm.wala.cast.python/source/com/ibm/wala/cast/python/client/PythonAnalysisEngine.java
index 10bd1053a..93c129023 100644
--- a/com.ibm.wala.cast.python/source/com/ibm/wala/cast/python/client/PythonAnalysisEngine.java
+++ b/com.ibm.wala.cast.python/source/com/ibm/wala/cast/python/client/PythonAnalysisEngine.java
@@ -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