Skip to content

Commit 81ad455

Browse files
committed
Python: full list of magic methods to be tested
1 parent d7c08f7 commit 81ad455

File tree

2 files changed

+325
-152
lines changed

2 files changed

+325
-152
lines changed

python/ql/test/experimental/dataflow/coverage/classes.py

Lines changed: 182 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# User-defined methods, both instance methods and class methods, can be called in many non-standard ways
2-
# i.e. differently from simply `c.f()` or `C.f()`. For example, a user-defined `__await__` function will
3-
# be called by the syntactic constru
4-
# This should cover all the class calls that we hope to support. It is based on https://docs.python.org/3/reference/datamodel.html.
2+
# i.e. differently from simply `c.f()` or `C.f()`. For example, a user-defined `__await__` function on a
3+
# class `C` will be called by the syntactic construct `await c` when `c` is an instance of `C`.
4+
#
5+
# These tests should cover all the class calls that we hope to support.
6+
# It is based on https://docs.python.org/3/reference/datamodel.html, and headings refer there.
57
#
68
# Intended sources should be the variable `SOURCE` and intended sinks should be.
79
# arguments to the function `SINK` (see python/ql/test/experimental/dataflow/testConfig.qll).
@@ -10,10 +12,14 @@
1012

1113

1214
# These are included so that we can easily evaluate the test code.
15+
NONSOURCE = "not a source"
1316
SOURCE = "source"
1417
def SINK(x):
1518
print(x)
1619

20+
def SINK_F(x):
21+
print("Unexpected flow: ", x)
22+
1723
# Callable types
1824
# These are the types to which the function call operation (see section Calls) can be applied:
1925

@@ -78,11 +84,11 @@ def gen(x, count):
7884

7985
iter = gen(SOURCE, 1)
8086
SINK(iter.__next__())
81-
SINK(iter.__next__()) # throws StopIteration, FP
87+
SINK_F(iter.__next__()) # throws StopIteration, FP
8288

8389
oiter = c.gen(SOURCE, 1)
8490
SINK(oiter.__next__())
85-
SINK(oiter.__next__()) # throws StopIteration, FP
91+
SINK_F(oiter.__next__()) # throws StopIteration, FP
8692

8793
# Coroutine functions
8894
# A function or method which is defined using async def is called a coroutine function. Such a function, when called, returns a coroutine object. It may contain await expressions, as well as async with and async for statements. See also the Coroutine Objects section.
@@ -95,14 +101,15 @@ async def coro(x):
95101

96102
class A:
97103

98-
def __await__(self, x):
99-
yield x
104+
def __await__(self):
105+
# yield SOURCE -- see https://groups.google.com/g/dev-python/c/_lrrc-vp9TI?pli=1
106+
return (yield from asyncio.coroutine(lambda: SOURCE)())
100107

101108
async def agen(x):
102109
a = A()
103-
return await a(SOURCE)
110+
return await a
104111

105-
SINK(asyncio.run(agen(SOURCE))) # fails with TypeError: 'A' object is not callable (possible query?)
112+
SINK(asyncio.run(agen(SOURCE)))
106113

107114
# Asynchronous generator functions
108115
# A function or method which is defined using async def and which uses the yield statement is called a asynchronous generator function. Such a function, when called, returns an asynchronous iterator object which can be used in an async for statement to execute the body of the function.
@@ -120,3 +127,169 @@ async def agen(x):
120127

121128
# Class Instances
122129
# Instances of arbitrary classes can be made callable by defining a __call__() method in their class.
130+
131+
class Customized:
132+
133+
a = NONSOURCE
134+
b = NONSOURCE
135+
136+
def __new__(cls):
137+
cls.a = SOURCE
138+
return super().__new__(cls)
139+
140+
def __init__(self):
141+
self.b = SOURCE
142+
143+
customized = Customized()
144+
SINK(Customized.a)
145+
SINK_F(Customized.b)
146+
SINK(customized.a)
147+
SINK(customized.b)
148+
149+
# def __del__(self):
150+
151+
# If a class sets __iter__() to None, calling iter() on its instances will raise a TypeError (without falling back to __getitem__()).
152+
153+
# 3.3.1. Basic customization
154+
# object.__new__(cls[, ...])
155+
# object.__init__(self[, ...])
156+
# object.__del__(self)
157+
# object.__repr__(self)
158+
# object.__str__(self)¶
159+
# object.__bytes__(self)
160+
# object.__format__(self, format_spec)
161+
# object.__lt__(self, other)
162+
# object.__le__(self, other)
163+
# object.__eq__(self, other)
164+
# object.__ne__(self, other)
165+
# object.__gt__(self, other)
166+
# object.__ge__(self, other)
167+
# object.__hash__(self)
168+
# object.__bool__(self)
169+
# len
170+
171+
# 3.3.2. Customizing attribute access
172+
# object.__getattr__(self, name)
173+
# object.__getattribute__(self, name)
174+
# object.__setattr__(self, name, value)
175+
# object.__delattr__(self, name)
176+
# object.__dir__(self)
177+
178+
# 3.3.2.2. Implementing Descriptors
179+
# object.__get__(self, instance, owner=None)
180+
# object.__set__(self, instance, value)
181+
# object.__delete__(self, instance)
182+
# object.__set_name__(self, owner, name)
183+
184+
# 3.3.2.4. __slots__
185+
# object.__slots__
186+
# __weakref__
187+
# __dict__
188+
189+
# 3.3.3. Customizing class creation
190+
# classmethod object.__init_subclass__(cls)
191+
192+
# 3.3.3.1. Metaclasses
193+
# By default, classes are constructed using type(). The class body is executed in a new namespace and the class name is bound locally to the result of type(name, bases, namespace).
194+
195+
# 3.3.3.2. Resolving MRO entries
196+
# __mro_entries__
197+
198+
# 3.3.3.4. Preparing the class namespace
199+
# metaclass.__prepare__(name, bases, **kwds)
200+
201+
# 3.3.4. Customizing instance and subclass checks
202+
# class.__instancecheck__(self, instance)
203+
# class.__subclasscheck__(self, subclass)
204+
205+
# 3.3.5. Emulating generic types
206+
# classmethod object.__class_getitem__(cls, key)
207+
208+
# 3.3.6. Emulating callable objects
209+
# object.__call__(self[, args...])
210+
211+
# 3.3.7. Emulating container types
212+
# object.__len__(self)
213+
# object.__length_hint__(self)
214+
# object.__getitem__(self, key)
215+
# object.__setitem__(self, key, value)
216+
# object.__delitem__(self, key)
217+
# object.__missing__(self, key)
218+
# object.__iter__(self)
219+
# object.__reversed__(self)
220+
# object.__contains__(self, item)
221+
222+
# 3.3.8. Emulating numeric types
223+
# object.__add__(self, other)
224+
# object.__sub__(self, other)
225+
# object.__mul__(self, other)
226+
# object.__matmul__(self, other)
227+
# object.__truediv__(self, other)
228+
# object.__floordiv__(self, other)
229+
# object.__mod__(self, other)
230+
# object.__divmod__(self, other)
231+
# object.__pow__(self, other[, modulo])
232+
# object.__lshift__(self, other)
233+
# object.__rshift__(self, other)
234+
# object.__and__(self, other)
235+
# object.__xor__(self, other)
236+
# object.__or__(self, other)
237+
# object.__radd__(self, other)
238+
# object.__rsub__(self, other)
239+
# object.__rmul__(self, other)
240+
# object.__rmatmul__(self, other)
241+
# object.__rtruediv__(self, other)
242+
# object.__rfloordiv__(self, other)
243+
# object.__rmod__(self, other)
244+
# object.__rdivmod__(self, other)
245+
# object.__rpow__(self, other[, modulo])
246+
# object.__rlshift__(self, other)
247+
# object.__rrshift__(self, other)
248+
# object.__rand__(self, other)
249+
# object.__rxor__(self, other)
250+
# object.__ror__(self, other)
251+
# object.__iadd__(self, other)
252+
# object.__isub__(self, other)
253+
# object.__imul__(self, other)
254+
# object.__imatmul__(self, other)
255+
# object.__itruediv__(self, other)
256+
# object.__ifloordiv__(self, other)
257+
# object.__imod__(self, other)
258+
# object.__ipow__(self, other[, modulo])
259+
# object.__ilshift__(self, other)
260+
# object.__irshift__(self, other)
261+
# object.__iand__(self, other)
262+
# object.__ixor__(self, other)
263+
# object.__ior__(self, other)
264+
# object.__neg__(self)
265+
# object.__pos__(self)
266+
# object.__abs__(self)
267+
# object.__invert__(self)
268+
# object.__complex__(self)
269+
# object.__int__(self)
270+
# object.__float__(self)
271+
# object.__index__(self)
272+
# object.__round__(self[, ndigits])
273+
# object.__trunc__(self)
274+
# object.__floor__(self)
275+
# object.__ceil__(self)
276+
277+
# 3.3.9. With Statement Context Managers
278+
# object.__enter__(self)
279+
# object.__exit__(self, exc_type, exc_value, traceback)
280+
281+
# 3.4.1. Awaitable Objects
282+
# object.__await__(self)
283+
284+
# 3.4.2. Coroutine Objects
285+
# coroutine.send(value)
286+
# coroutine.throw(type[, value[, traceback]])
287+
# coroutine.close()
288+
289+
# 3.4.3. Asynchronous Iterators
290+
# object.__aiter__(self)
291+
# object.__anext__(self)
292+
293+
# 3.4.4. Asynchronous Context Managers
294+
# object.__aenter__(self)
295+
# object.__aexit__(self, exc_type, exc_value, traceback)

0 commit comments

Comments
 (0)