Find traceback of print caller [duplicate] - python

This question already has answers here:
Is there a trick to break on the print builtin with pdb?
(2 answers)
Closed 5 years ago.
I am working on a python program which interacts with many external libraries and has some fairly complex logic. In this program I've found that it'll sometimes print NoneType: None to the console (with no context) whatsoever. I have no idea where this is being printed or why and this is causing errors in other places of the program.
So is it possible to find the source of a print/warn call?

You can always override the built-in print() function and then observe what's going on, for example:
import builtins
import inspect
builtin_print = builtins.print # store a reference to the built-in print() function
def tracing_print(*args, **kwargs):
c = inspect.getouterframes(inspect.currentframe())[1] # get the calling frame
# print the caller info (you can add a condition like `if args and args[0] is None`):
builtin_print("{}, line {}, caller `{}`, source: {}".format(c[1], c[2], c[3], c[4]))
builtin_print(*args, **kwargs) # call the built-in method and forward the params
builtins.print = tracing_print # override the built-in print
That will give you a ton of info preceding every call to print(). For example:
def foo():
print("Bar!")
foo()
Will yield something like:
/tmp/playground/test.py, line 13, caller `foo`, source: [' print("Bar!")\n']
Bar!
Needless to say, do not use this in production code, it's meant for forensics.

Related

print(function) vs print(function()) in Python [duplicate]

This question already has answers here:
What is the difference between calling function with parentheses and without in python? [duplicate]
(5 answers)
Closed 2 years ago.
I've got following simple script, which gets text from some site:
from urllib.request import urlopen
def fetch_words():
contentdownload = urlopen('https://wolnelektury.pl/media/book/txt/treny-tren-viii.txt')
decluttered = []
for line in contentdownload:
decltr_line = line.decode('utf8').split(" ")
for word in decltr_line:
decluttered.append(word)
contentdownload.close()
return decluttered
When adding: print(fetch_words) at the end, the program returns: <function fetch_words at 0x7fa440feb200>, but on the other hand, when I replace it with: print(fetch_words()) it returns the content of the website, that a function downloads.
I have following question: why it works like this, what's the difference: function with () or without...
All help appreciated!
When you call print(fetch_words) you get the representation of the function as an object.
def fetch_words():
pass
isinstance(fetch_words,object)
return True. Indeed, functions in Python are objects.
So when you type print(fetch_words) you actually get the result of fetch_words.__str__(), a special method which is called when you print object.
And when you type print(fetch_words()) you get the result of the function (the value the function returns). Because, the () execute the function
So fetch_words is an object and fetch_words() execute the function and its value is the value the function returns.

Is it possible to "hack" Python's print function?

Note: This question is for informational purposes only. I am interested to see how deep into Python's internals it is possible to go with this.
Not very long ago, a discussion began inside a certain question regarding whether the strings passed to print statements could be modified after/during the call to print has been made. For example, consider the function:
def print_something():
print('This cat was scared.')
Now, when print is run, then the output to the terminal should display:
This dog was scared.
Notice the word "cat" has been replaced by the word "dog". Something somewhere somehow was able to modify those internal buffers to change what was printed. Assume this is done without the original code author's explicit permission (hence, hacking/hijacking).
This comment from the wise #abarnert, in particular, got me thinking:
There are a couple of ways to do that, but they're all very ugly, and
should never be done. The least ugly way is to probably replace the
code object inside the function with one with a different co_consts
list. Next is probably reaching into the C API to access the str's
internal buffer. [...]
So, it looks like this is actually possible.
Here's my naive way of approaching this problem:
>>> import inspect
>>> exec(inspect.getsource(print_something).replace('cat', 'dog'))
>>> print_something()
This dog was scared.
Of course, exec is bad, but that doesn't really answer the question, because it does not actually modify anything during when/after print is called.
How would it be done as #abarnert has explained it?
First, there's actually a much less hacky way. All we want to do is change what print prints, right?
_print = print
def print(*args, **kw):
args = (arg.replace('cat', 'dog') if isinstance(arg, str) else arg
for arg in args)
_print(*args, **kw)
Or, similarly, you can monkeypatch sys.stdout instead of print.
Also, nothing wrong with the exec … getsource … idea. Well, of course there's plenty wrong with it, but less than what follows here…
But if you do want to modify the function object's code constants, we can do that.
If you really want to play around with code objects for real, you should use a library like bytecode (when it's finished) or byteplay (until then, or for older Python versions) instead of doing it manually. Even for something this trivial, the CodeType initializer is a pain; if you actually need to do stuff like fixing up lnotab, only a lunatic would do that manually.
Also, it goes without saying that not all Python implementations use CPython-style code objects. This code will work in CPython 3.7, and probably all versions back to at least 2.2 with a few minor changes (and not the code-hacking stuff, but things like generator expressions), but it won't work with any version of IronPython.
import types
def print_function():
print ("This cat was scared.")
def main():
# A function object is a wrapper around a code object, with
# a bit of extra stuff like default values and closure cells.
# See inspect module docs for more details.
co = print_function.__code__
# A code object is a wrapper around a string of bytecode, with a
# whole bunch of extra stuff, including a list of constants used
# by that bytecode. Again see inspect module docs. Anyway, inside
# the bytecode for string (which you can read by typing
# dis.dis(string) in your REPL), there's going to be an
# instruction like LOAD_CONST 1 to load the string literal onto
# the stack to pass to the print function, and that works by just
# reading co.co_consts[1]. So, that's what we want to change.
consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
for c in co.co_consts)
# Unfortunately, code objects are immutable, so we have to create
# a new one, copying over everything except for co_consts, which
# we'll replace. And the initializer has a zillion parameters.
# Try help(types.CodeType) at the REPL to see the whole list.
co = types.CodeType(
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_flags, co.co_code,
consts, co.co_names, co.co_varnames, co.co_filename,
co.co_name, co.co_firstlineno, co.co_lnotab,
co.co_freevars, co.co_cellvars)
print_function.__code__ = co
print_function()
main()
What could go wrong with hacking up code objects? Mostly just segfaults, RuntimeErrors that eat up the whole stack, more normal RuntimeErrors that can be handled, or garbage values that will probably just raise a TypeError or AttributeError when you try to use them. For examples, try creating a code object with just a RETURN_VALUE with nothing on the stack (bytecode b'S\0' for 3.6+, b'S' before), or with an empty tuple for co_consts when there's a LOAD_CONST 0 in the bytecode, or with varnames decremented by 1 so the highest LOAD_FAST actually loads a freevar/cellvar cell. For some real fun, if you get the lnotab wrong enough, your code will only segfault when run in the debugger.
Using bytecode or byteplay won't protect you from all of those problems, but they do have some basic sanity checks, and nice helpers that let you do things like insert a chunk of code and let it worry about updating all offsets and labels so you can't get it wrong, and so on. (Plus, they keep you from having to type in that ridiculous 6-line constructor, and having to debug the silly typos that come from doing so.)
Now on to #2.
I mentioned that code objects are immutable. And of course the consts are a tuple, so we can't change that directly. And the thing in the const tuple is a string, which we also can't change directly. That's why I had to build a new string to build a new tuple to build a new code object.
But what if you could change a string directly?
Well, deep enough under the covers, everything is just a pointer to some C data, right? If you're using CPython, there's a C API to access the objects, and you can use ctypes to access that API from within Python itself, which is such a terrible idea that they put a pythonapi right there in the stdlib's ctypes module. :) The most important trick you need to know is that id(x) is the actual pointer to x in memory (as an int).
Unfortunately, the C API for strings won't let us safely get at the internal storage of an already-frozen string. So screw safely, let's just read the header files and find that storage ourselves.
If you're using CPython 3.4 - 3.7 (it's different for older versions, and who knows for the future), a string literal from a module that's made of pure ASCII is going to be stored using the compact ASCII format, which means the struct ends early and the buffer of ASCII bytes follows immediately in memory. This will break (as in probably segfault) if you put a non-ASCII character in the string, or certain kinds of non-literal strings, but you can read up on the other 4 ways to access the buffer for different kinds of strings.
To make things slightly easier, I'm using the superhackyinternals project off my GitHub. (It's intentionally not pip-installable because you really shouldn't be using this except to experiment with your local build of the interpreter and the like.)
import ctypes
import internals # https://github.com/abarnert/superhackyinternals/blob/master/internals.py
def print_function():
print ("This cat was scared.")
def main():
for c in print_function.__code__.co_consts:
if isinstance(c, str):
idx = c.find('cat')
if idx != -1:
# Too much to explain here; just guess and learn to
# love the segfaults...
p = internals.PyUnicodeObject.from_address(id(c))
assert p.compact and p.ascii
addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
buf = (ctypes.c_int8 * 3).from_address(addr + idx)
buf[:3] = b'dog'
print_function()
main()
If you want to play with this stuff, int is a whole lot simpler under the covers than str. And it's a lot easier to guess what you can break by changing the value of 2 to 1, right? Actually, forget imagining, let's just do it (using the types from superhackyinternals again):
>>> n = 2
>>> pn = PyLongObject.from_address(id(n))
>>> pn.ob_digit[0]
2
>>> pn.ob_digit[0] = 1
>>> 2
1
>>> n * 3
3
>>> i = 10
>>> while i < 40:
... i *= 2
... print(i)
10
10
10
… pretend that code box has an infinite-length scrollbar.
I tried the same thing in IPython, and the first time I tried to evaluate 2 at the prompt, it went into some kind of uninterruptable infinite loop. Presumably it's using the number 2 for something in its REPL loop, while the stock interpreter isn't?
Monkey-patch print
print is a builtin function so it will use the print function defined in the builtins module (or __builtin__ in Python 2). So whenever you want to modify or change the behavior of a builtin function you can simply reassign the name in that module.
This process is called monkey-patching.
# Store the real print function in another variable otherwise
# it will be inaccessible after being modified.
_print = print
# Actual implementation of the new print
def custom_print(*args, **options):
_print('custom print called')
_print(*args, **options)
# Change the print function globally
import builtins
builtins.print = custom_print
After that every print call will go through custom_print, even if the print is in an external module.
However you don't really want to print additional text, you want to change the text that is printed. One way to go about that is to replace it in the string that would be printed:
_print = print
def custom_print(*args, **options):
# Get the desired seperator or the default whitspace
sep = options.pop('sep', ' ')
# Create the final string
printed_string = sep.join(args)
# Modify the final string
printed_string = printed_string.replace('cat', 'dog')
# Call the default print function
_print(printed_string, **options)
import builtins
builtins.print = custom_print
And indeed if you run:
>>> def print_something():
... print('This cat was scared.')
>>> print_something()
This dog was scared.
Or if you write that to a file:
test_file.py
def print_something():
print('This cat was scared.')
print_something()
and import it:
>>> import test_file
This dog was scared.
>>> test_file.print_something()
This dog was scared.
So it really works as intended.
However, in case you only temporarily want to monkey-patch print you could wrap this in a context-manager:
import builtins
class ChangePrint(object):
def __init__(self):
self.old_print = print
def __enter__(self):
def custom_print(*args, **options):
# Get the desired seperator or the default whitspace
sep = options.pop('sep', ' ')
# Create the final string
printed_string = sep.join(args)
# Modify the final string
printed_string = printed_string.replace('cat', 'dog')
# Call the default print function
self.old_print(printed_string, **options)
builtins.print = custom_print
def __exit__(self, *args, **kwargs):
builtins.print = self.old_print
So when you run that it depends on the context what is printed:
>>> with ChangePrint() as x:
... test_file.print_something()
...
This dog was scared.
>>> test_file.print_something()
This cat was scared.
So that's how you could "hack" print by monkey-patching.
Modify the target instead of the print
If you look at the signature of print you'll notice a file argument which is sys.stdout by default. Note that this is a dynamic default argument (it really looks up sys.stdout every time you call print) and not like normal default arguments in Python. So if you change sys.stdout print will actually print to the different target even more convenient that Python also provides a redirect_stdout function (from Python 3.4 on, but it's easy to create an equivalent function for earlier Python versions).
The downside is that it won't work for print statements that don't print to sys.stdout and that creating your own stdout isn't really straightforward.
import io
import sys
class CustomStdout(object):
def __init__(self, *args, **kwargs):
self.current_stdout = sys.stdout
def write(self, string):
self.current_stdout.write(string.replace('cat', 'dog'))
However this also works:
>>> import contextlib
>>> with contextlib.redirect_stdout(CustomStdout()):
... test_file.print_something()
...
This dog was scared.
>>> test_file.print_something()
This cat was scared.
Summary
Some of these points have already be mentioned by #abarnet but I wanted to explore these options in more detail. Especially how to modify it across modules (using builtins/__builtin__) and how to make that change only temporary (using contextmanagers).
A simple way to capture all output from a print function and then process it, is to change the output stream to something else, e.g. a file.
I'll use a PHP naming conventions (ob_start, ob_get_contents,...)
from functools import partial
output_buffer = None
print_orig = print
def ob_start(fname="print.txt"):
global print
global output_buffer
print = partial(print_orig, file=output_buffer)
output_buffer = open(fname, 'w')
def ob_end():
global output_buffer
close(output_buffer)
print = print_orig
def ob_get_contents(fname="print.txt"):
return open(fname, 'r').read()
Usage:
print ("Hi John")
ob_start()
print ("Hi John")
ob_end()
print (ob_get_contents().replace("Hi", "Bye"))
Would print
Hi John
Bye John
Let's combine this with frame introspection!
import sys
_print = print
def print(*args, **kw):
frame = sys._getframe(1)
_print(frame.f_code.co_name)
_print(*args, **kw)
def greetly(name, greeting = "Hi")
print(f"{greeting}, {name}!")
class Greeter:
def __init__(self, greeting = "Hi"):
self.greeting = greeting
def greet(self, name):
print(f"{self.greeting}, {name}!")
You'll find this trick prefaces every greeting with the calling function or method. This might be very useful for logging or debugging; especially as it lets you "hijack" print statements in third party code.

Will Python automatically detect that the function was never called but defined?

True or False
If a function is defined but never called, then Python automatically detects that and issues a warning
One of the issues with this is that functions in Python are first class objects. So their name can be reassigned. For example:
def myfunc():
pass
a = myfunc
myfunc = 42
a()
We also have closures, where a function is returned by another function and the original name goes out of scope.
Unfortunately it is also perfectly legal to define a function with the same name as an existing one. For example:
def myfunc(): # <<< This code is never called
pass
def myfunc():
pass
myfunc()
So any tracking must include the function's id, not just its name - although that won't help with closures, since the id could get reused. It also won't help if the __name__ attribute of the function is reassigned.
You could track function calls using a decorator. Here I have used the name and the id - the id on its own would not be readable.
import functools
globalDict = {}
def tracecall(f):
#functools.wraps(f)
def wrapper(*args, **kwargs):
global globalDict
key = "%s (%d)" % (f.__name__, id(f))
# Count the number of calls
if key in globalDict:
globalDict[key] += 1
else:
globalDict[key] = 1
return f(*args, **kwargs)
return wrapper
#tracecall
def myfunc1():
pass
myfunc1()
myfunc1()
#tracecall
def myfunc1():
pass
a = myfunc1
myfunc1 = 42
a()
print(globalDict)
Gives:
{'myfunc1 (4339565296)': 2, 'myfunc1 (4339565704)': 1}
But that only gives the functions that have been called, not those that have not!
So where to go from here? I hope you can see that the task is quite difficult given the dynamic nature of python. But I hope the decorator I show above could at least allow you to diagnose the way the code is used.
No it is not. Python is not detect this. If you want to detect which functions are called or not during the run time you can use global set in your program. Inside each function add function name to set. Later you can print your set content and check if the the function is called or not.
False. Ignoring the difficulty and overhead of doing this, there's no reason why it would be useful.
A function that is defined in a module (i.e. a Python file) but not called elsewhere in that module might be called from a different module, so that doesn't deserve a warning.
If Python were to analyse all modules that get run over the course of a program, and print a warning about functions that were not called, it may be that a function was not called because of the input in this particular run e.g. perhaps in a calculator program there is a "multiply" function but the user only asked to sum some numbers.
If Python were to analyse all modules that make up a program and note and print a warning about functions that could not possibly be called (this is impossible but stay with me here) then it would warn about functions that were intended for use in other programs. E.g. if you have two calculator programs, a simple one and an advanced one, maybe you have a central calc.py with utility functions, and then advanced functions like exp and log could not possibly be called when that's used as part of simple program, but that shouldn't cause a warning because they're needed for the advanced program.

Allow calling function to get caller's attribute in Python

I want to create a function that will be called whenever the caller gets arguments of wrong instance, that will print caller's __doc__ attribute and exit. The function is the following:
def checktype(objects,instances):
if not all([isinstance(obj,instance) for
obj,instance in zip(objects,instances)]):
print 'Type Error'
#Get __doc__ from caller
print __doc__
exit()
I got stuck in the step, where I have to get the __doc__ attribute. I know that inspect module can do it, in a way like the following:
name=inspect.stack()[1][3]
possibles=globals().copy()
__doc__= possibles.get(name).__doc__
(you can suggest another one that is compatible with every Python version, including 3.5)
but I think there must be another way. The reason for my scepticism is that the built-in return statement returns something to the caller in an immediate way, so that means there must be a "hook" or a "pipe" accessible by the child function, which is being used as a medium for information exchange with the parent.So an initial question that triggered my interest was:
Is this pipe send-only and no information can be send backwards?
I have not been able to answer this, as the return statement is only briefly explained in the sites I searched. Apart from this, the inspect module, as far as I can tell, saves multiple frames in a stack and runs constantly in the background. For me, this is like I am trying to kill a fly with a minigun. I just need the caller function's name, not the function 10 frames before. If there is not any way to accomplish this, this is, in my opinion, a feature that Python must have. My question is:
What would be the pythonic-programmatic way to get caller's attributes in Python, with universal support ? Excuse me if there is ignorance in my question, I am open to any corrections and "mind-openings". Thank you all for your answers.
I have a few functions that may be related to your issue
import sys
def position(level = 0):
"""return a tuple (code, lasti, lineno) where this function is called
If level > 0, go back up to that level in the calling stack.
"""
frame = sys._getframe(level + 1)
try:
return (frame.f_code, frame.f_lasti, frame.f_lineno)
finally:
del frame
def line(level = 0):
"""return a tuple (lineno, filename, funcname) where this function is called
If level > 0, go back up to that level in the calling stack.
The filename is the name in python's co_filename member
of code objects.
"""
code, lasti, lineno = position(level=level+1)
return (lineno, code.co_filename, code.co_name)
def _globals(level = 0):
"""return the globals() where this function is called
If level > 0, go back up to that level in the calling stack.
"""
frame = sys._getframe(level + 1)
try:
return frame.f_globals
finally:
del frame

How do I perform some operation on the output of a function in Python?

I am trying to make a function's output behave as if it's my input. The goal is to make a new output from the old output.
I have some code that looks like this:
def func():
BLOCK OF CODE
func()
There is no return statement in the function and no parameters within the parenthesis.
When I type func() to call my function as shown above, I get the desired output, which is a bunch of printed statements. Now I want to do something with that output to get another output.
All I'm trying to do is effectively "pipe" the output of one function into the input of another function (or, if possible, not even worry about creating another function at all, and instead doing something more direct). I looked into Python 3 writing to a pipe
but it did not help me. I also tried defining another function and using the preceding function as a parameter, which did not work either:
def another_func(func):
print another_statement
another_func(func)
I also tried making a closure (which "kind" of worked because at least it printed the same thing that func() would print, but still not very encouraging):
def func():
def another_func():
print another_statement
BLOCK OF CODE
another_func()
Finally, I tried designing both a decorator and a nested function to accomplish this, but I have no parameters in my function, which really threw off my code (didn't print anything at all).
Any advice on how to manipulate a function's output like as if it is your input so that it's possible to create a new output?
You could achieve this by redirecting stdout using a decorator:
from StringIO import StringIO
import sys
def pipe(f):
def decorated(*args, **kwargs):
old,sys.stdout = sys.stdout,StringIO()
try:
result = f(*args, **kwargs)
output = sys.stdout.getvalue()
finally:
sys.stdout = old
return result, output
return decorated
You could then get the result, output pair from any decorated function, eg:
#pipe
def test(x):
print x
return 0
test(3) -> (0, '3\n')
However, I can't think of a good reason why you'd want to do this.
(Actually, that's not quite true; it is handy when writing unit tests for user IO, such as when testing student assignments in a software engineering course. I seriously doubt that that's what the OP is trying to do, though.)
Return the desired value(s) from the function - instead of printing the values on the console, return them as strings, numbers, lists or any other type that makes sense. Otherwise, how do you expect to "connect" the output of a function as the input to another, if there is no output to begin with?
Of course, printing on the console doesn't count as output unless you're planning to eventually use OS pipes or a similar mechanism to connect two programs on the console, but keep things simple! just use the function's return values and worry about pipes later if and only if that's necessary for your problem in particular.
After reading the comments: "connecting" two functions by printing on the console from one and reading from the console from the other would be a really bad idea in this case, first you have to grasp the way functions return values to each other, trust me on this one: you have to rethink your program! even though other answers (strictly speaking) answer your original question, that's absolutely not what you should do.
just for fun ... because OP asked for it
import StringIO
import sys
def func1():
for i in range(1,10):
print "some stuff %d"%i
def func2(func):
old_std = sys.stdout
sys.stdout = StringIO.StringIO()
try:
func()
return sys.stdout.getvalue().splitlines()
finally:
sys.stdout = old_std
print func2(func1)
You need to return a value from your function. This can be used to assign the value into another variable.
Say I define some function doubleThis that will double the input
def doubleThis(x):
print 'this is x :', x
return x * 2 # note the return keyword
Now I can call the function with 3, and it returns 6 as expected
>>> doubleThis(3)
this is x : 3
6
Now I have another function subtractOne that returns the input value, minus 1.
def subtractOne(i):
print 'this is i :', i
return i - 1
Now comes the answer to your question. Note that we can call the first function as the input to the second, due to the fact that it has a return value.
>>> subtractOne(doubleThis(3))
this is x : 3
this is i : 6
5

Categories

Resources