call_function(doStuff()) means "use the value returned by doStuff as the argument to call_function". This is not what you want, you want to use the function doStuff itself as the argument.
To get the effect you want, omit the parentheses on the function you're passing as an argument: call_function(doStuff)
The key insight here is the distinction between the function itself and the value returned by the function. The function itself is an entity in python, like a string or a list or a dictionary, which has the property of being callable. (that is, it has a __call__ method)
When you see a reference to a function followed by a matched pair of parentheses, either by name (as in doStuff()) or by alias (as in func()) or as a reference (as in lambda x: x+1()) that expression evaluates to the value returned by the function. This value is None unless the execution of the function hits a return statement, in which case the returned value is just the result of evaluating the expression following the return. The value returned by the function can be any legitimate python entity, including another function.
All of these words, which bear thinking about and possibly further experimentation or study on your part, allow me to say more simply that doStuff is the name of a function, and doStuff() is an expression which triggers the execution of that function and evaluates to the returned value of that function