Python: Indent print output from class - python

How can I indent the print output on the command line from a class that is called? I can't edit the class file to add tabs to each print().
So I would call the imported class in mypythonthing.py:
print('Calling class')
MyClass()
All the print output would then be indented, or have something prepended to it.
e.g.
$ python mypythonthing.py
$ Running your python script...
$ Calling class
$ > The print output from MyClass is indented
$ > Exiting MyClass
$

Patch the built-in print function to prefix each line with your indentation.
import builtins
def print(*args, **kwargs):
builtins.print(" > ", *args, **kwargs)

If you can put the code that should be indented inside (one or more) functions, then you can use a decorator to wrap these functions.
Then any invocation of print inside these function will be indented.
Also, you will only need to declare this function in your main script, and not anywhere else.
Example -
import builtins
import another # for demo purposes only
# This will override the default `print` function.
# Invoking it as a decorator will automatically perform
# initialisation and cleanup. There is also never a need
# to modify this.
def indent(f):
def closure():
old = builtins.print
builtins.print = lambda x, *args, **kwargs: old("\t>", x, *args, **kwargs)
f()
builtins.print = old
return closure
some_number = "100"
# Example function, note decorator usage.
# This function may **not** take any parameters!
# It may however, use any variables declared before it.
#indent
def indentedStuffGoesHere():
print("Inside `indentedStuffGoesHere`")
print(some_number)
another.Foo().bar()
another.stuff()
print("entering special block")
indentedStuffGoesHere()
print("done")
another.py
def stuff():
print("TESTING stuff")
class Foo:
def bar(self):
print("HELLO FROM FOO")
Output:
entering special block
> Inside `indentedStuffGoesHere`
> 100
> HELLO FROM FOO
> TESTING stuff
done

i think what you might be looking for is textwrap:
textwrap docs
so as an example:
wrapper = textwrap.TextWrapper(width=preferredWidth, subsequent_indent='\t')
message = "asdf" * 50
print wrapper.fill(message)

Related

How to get the caller's class definition line number?

There are some packages which has some methods like subscribe or add which let user adds a customized callback function. For debug purpose and curiosity, I would like to know which function and which class in this package actually called my callback function later. So it would be nice if I have the line number of the class.
Minimal working example
# test.py
import inspect
class Foo: # line 5
def caller(self):
print("Hello from caller")
b=Bar()
b.func()
class Bar:
def func(self):
print("Hello from func")
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__.__name__
the_method = stack[1][0].f_code.co_name
# Need some help here to get value 5
# To do
# ...
print(f"Called by {the_class}.{the_method}()")
f = Foo()
f.caller()
Output:
Hello from caller
Hello from func
Called by Foo.caller()
Q: Inside func, how to get value 5 which is line number of definition of class Foo? Ideally by inspect or other traceback magic, not by searching the string in file.

Python - tie built in function to created function

I want to keep track of the last time my python program printed something to the console.
I created this function:
def updateLastPrintTime():
global lastPrintTime
lastPrintTime = time.time()
And I'm calling it after each print statement.
This works fine, however, I have a lot of print statements and I want to update lastPrintTime after each and every printing.
If print was not a built in function, this is what I would do:
def print():
updateLastPrintTime()
# rest of 'print' code ...
But I can't figure out how to do that with a built-in function, especially since they are written in C.
Any help would be appreciated.
Based on this answer: overload print python
You could do something like this:
from __future__ import print_function
import time
last_print_time = time.time() # initialise global var
try:
import __builtin__
except ImportError:
# Python 3
import builtins as __builtin__
# overload the print function
def print(*args, **kwargs):
global last_print_time
last_print_time = time.time() # update variable
return __builtin__.print(*args, **kwargs) # print the message
You can assign the builtins print to another name and then you can override print
_print = print
def print(*args, **kwargs):
_print("Hello,", *args, **kwargs)
print("world!")
Alternatively, you can also get the builtins print from the builtins module e.g.
import builtins
def print(*args, **kwargs):
builtins.print("Hello,", *args, **kwargs)
print("world!")

Call a Function by alias in a Decorator

The current code I have, allows the function to call the wrapper decorator, and uses the function name in its code. However, I'm looking for a way to give the function a 'alias' in a way as an argument. Here's the current code:
import os, sys
# Take user input
message = input('type command: ')
# Command wrapper
ALLCOMMANDS = {}
def command(function):
ALLCOMMANDS[function.__name__] = function
return function
# Commands
#command
def foo():
print("bar")
#command
def goo():
print('ber')
# Run appropriate command
if message in ALLCOMMANDS:
ALLCOMMANDS[message]()
For example I would want to be able to call the function by a name such as '!foo' from the user input, so maybe the argument would look like #command(name='!foo'), I just don't know where to go from there to use that argument in the decorator since it already has an argument.
I attempted
# Command wrapper
ALLCOMMANDS = {}
def command(name):
ALLCOMMANDS[name] = name
return name
but keep getting errors and I assume I am missing something
You should read up a bit more on python decorators. You're getting an error with:
def command(name):
ALLCOMMANDS[name] = name
return name
Because of the return name.
Decorators are just syntactic sugar. This:
#command
def foo():
print('bar')
Is equivalent to:
def foo():
print('bar')
foo = command(foo)
From this you can see why your original decorator works. At the end you return function.
Things get a little tricker when you have a decorator that takes arguments. Desugared the following:
#command('nickname')
def foo():
print('bar')
Looks like this:
def foo():
print('bar')
foo = command('nickname')(foo)
So, to write a decorator that takes arguments, the decorator needs to return a function that takes the function to decorate as an argument:
def command(nickname):
def wrapped(f):
ALLCOMMANDS[nickname] = f
return f
return wrapped
Also consider making ALLCOMMANDS an attribute on your command instead of a global (UPPER_SNAKE is usually reserved for constants):
def command(nickname):
def wrapped(f):
command._functions[nickname] = f
return f
return wrapped
command._functions = {}

Idiomatic way to inject parameters with python decorators

So, this is a 2 part question -
Is there an idiomatic way in python to inject a parameter into the function signature when using a decorator?
For example:
def _mydecorator(func):
def wrapped(someval, *args, **kwargs):
do_something(someval)
return func(*args, **kwargs)
return wrapped
#_mydecorator
def foo(thisval, thatval=None):
do_stuff()
The reason around this is when using SaltStack's runner modules You define funcs within the module, and you can call those functions via the 'salt-run' command. If the above example was a Salt runner module call 'bar', I could then run:
salt-run bar.foo aval bval
The salt-run imports the module and calls the function with the arguments you've given on the command line. Any function in the module that begins with a _ or that is in a class is ignored and cannot be run via salt-run.
So, I wanted to define something like a timeout decorator to control how long the function can run for.
I realize I could do something like:
#timeout(30)
def foo():
...
But I wanted to make that value configurable, so that I could run something like:
salt-run bar.foo 30 aval bval
salt-run bar.foo 60 aval bval
The above decorator works, but it feels like a hack, since it's changing the signature of the function and the user has no idea, unless they look at the decorator.
I have another case where I want to make a decorator for taking care of 'prechecks' before the functions in the Salt runner execute. However, the precheck needs a piece of information from the function it's decorating. Here's an example:
def _precheck(func):
def wrapper(*args, **kwargs):
ok = False
if len(args) > 0:
ok = run_prechecks(args[0])
else:
ok = run_prechecks(kwargs['record_id'])
if ok:
func(*args, **kwargs)
return wrapper
#_precheck
def foo(record_id, this_val):
do_stuff()
This also seems hackish, since it requires that the function that's being decorated, a) has a parameter called 'record_id' and that b) it's the first argument.
Now, because I'm writing all these functions, it's not a huge deal, but seems like there's probably a better way of doing this ( like not using decorators to try and solve this )
The way to dynamically define decorator arguments is not using the syntactic sugar (#). Like this:
func = dec(dec_arguments)(func_name)(func_arguments)
import json
import sys
foo = lambda record_id, thatval=None: do_stuff(record_id, thatval)
def do_stuff(*args, **kwargs):
# python3
print(*args, json.dumps(kwargs))
def _mydecorator(timeout):
print('Timeout: %s' % timeout)
def decorator(func):
def wrapped(*args, **kwargs):
return func(*args, **kwargs)
return wrapped
return decorator
if __name__ == '__main__':
_dec_default = 30
l_argv = len(sys.argv)
if l_argv == 1:
# no args sent
sys.exit('Arguments missing')
elif l_argv == 2:
# assuming record_id is a required argument
_dec_arg = _dec_default
_args = 1
else:
# three or more args: filename 1 2 [...]
# consider using optional keyword argument `timeout`
# otherwise in combination with another optional argument it's a recipe for disaster
# if only two arguments will be given - with current logic it will be tested for `timeoutedness`
try:
_dec_arg = int(sys.argv[1])
_args = 2
except (ValueError, IndexError):
_dec_arg = _dec_default
_args = 1
foo = _mydecorator(_dec_arg)(foo)(*sys.argv[_args:])
There is no idiomatic way to do this in python 3.7 as far as I know. Indeed #functools.wraps only works when you do not modify the signature (see what does functools.wraps do ?)
However there is a way to do the same as #functools.wraps (exposing the full signature, preserving the __dict__ and docstring): #makefun.wraps. With this drop-in replacement for #wraps, you can edit the exposed signature.
from makefun import wraps
def _mydecorator(func):
#wraps(func, prepend_args="someval")
def wrapped(someval, *args, **kwargs):
print("wrapper executes with %r" % someval)
return func(*args, **kwargs)
return wrapped
#_mydecorator
def foo(thisval, thatval=None):
"""A foo function"""
print("foo executes with thisval=%r thatval=%r" % (thisval, thatval))
# let's check the signature
help(foo)
# let's test it
foo(5, 1)
Yields:
Help on function foo in module __main__:
foo(someval, thisval, thatval=None)
A foo function
wrapper executes with 5
foo executes with thisval=1 thatval=None
You can see that the exposed signature contains the prepended argument.
The same mechanism applies for appending and removing arguments, as well as editing signatures more deeply. See makefun documentation for details (I'm the author by the way ;) )

Override a function' sub-function from a decorator?

Let's consider this piece of code where I would like to create bar dynamically with a decorator
def foo():
def bar():
print "I am bar from foo"
print bar()
def baz():
def bar():
print "I am bar from baz"
print bar()
I thought I could create bar from the outside with a decorator:
def bar2():
print "I am super bar from foo"
setattr(foo, 'bar', bar2)
But the result is not what I was expecting (I would like to get I am super bar from foo:
>>> foo()
I am bar from foo
Is it possible to override a sub-function on an existing function with a decorator?
The actual use case
I am writing a wrapper for a library and to avoid boilerplate code I would like to simplify my work.
Each library function has a prefix lib_ and returns an error code. I would like to add the prefix to the current function and treat the error code. This could be as simple as this:
def call():
fname = __libprefix__ + inspect.stack()[1][3]
return_code = getattr(__lib__, fname)(*args)
if return_code < 0: raise LibError(fname, return_code)
def foo():
call()
The problem is that call might act differently in certain cases. Some library functions do not return an error_code so it would be easier to write it like
this:
def foo():
call(check_status=True)
Or much better in my opinion (this is the point where I started thinking about decorators):
#LibFunc(check_status=True)
def foo():
call()
In this last example I should declare call inside foo as a sub-function created dynamically by the decorator itself.
The idea was to use something like this:
class LibFunc(object):
def __init__(self,**kwargs):
self.kwargs = kwargs
def __call__(self, original_func):
decorator_self = self
def wrappee( *args, **kwargs):
def call(*args):
fname = __libprefix__ + original_func.__name__
return_code = getattr(__lib__, fname)(*args)
if return_code < 0: raise LibError(fname, return_code)
print original_func
print call
# <<<< The part that does not work
setattr(original_func, 'call', call)
# <<<<
original_func(*args,**kwargs)
return wrappee
Initially I was tempted to call the call inside the decorator itself to minimize the writing:
#LibFunc():
foo(): pass
Unfortunately, this is not an option since other things should sometime be done before and after the call:
#LibFunc():
foo(a,b):
value = c_float()
call(a, pointer(value), b)
return value.value
Another option that I thought about was to use SWIG, but again this is not an option because I will need to rebuild the existing library with the SWIG wrapping functions.
And last but not least, I may get inspiration from SWIG typemaps and declare my wrapper as this:
#LibFunc(check_exit = true, map = ('<a', '>c_float', '<c_int(b)')):
foo(a,b): pass
This looks like the best solution to me, but this is another topic and another question...
Are you married to the idea of a decorator? Because if your goal is bunch of module-level functions each of which wraps somelib.lib_somefunctionname, I don't see why you need one.
Those module-level names don't have to be functions, they just have to be callable. They could be a bunch of class instances, as long as they have a __call__ method.
I used two different subclasses to determine how to treat the return value:
#!/usr/bin/env python3
import libtowrap # Replace with the real library name.
class Wrapper(object):
'''
Parent class for all wrapped functions in libtowrap.
'''
def __init__(self, name):
self.__name__ = str(name)
self.wrapped_name = 'lib_' + self.__name__
self.wrapped_func = getattr(libtowrap, self.wrapped_name)
self.__doc__ = self.wrapped_func.__doc__
return
class CheckedWrapper(Wrapper):
'''
Wraps functions in libtowrap that return an error code that must
be checked. Negative return values indicate an error, and will
raise a LibError. Successful calls return None.
'''
def __call__(self, *args, **kwargs):
error_code = self.wrapped_func(*args, **kwargs)
if error_code < 0:
raise LibError(self.__name__, error_code)
return
class UncheckedWrapper(Wrapper):
'''
Wraps functions in libtowrap that return a useful value, as
opposed to an error code.
'''
def __call__(self, *args, **kwargs):
return self.wrapped_func(*args, **kwargs)
strict = CheckedWrapper('strict')
negative_means_failure = CheckedWrapper('negative_means_failure')
whatever = UncheckedWrapper('whatever')
negative_is_ok = UncheckedWrapper('negative_is_ok')
Note that the wrapper "functions" are assigned while the module is being imported. They are in the top-level module namespace, and not hidden by any if __name__ == '__main__' test.
They will behave like functions for most purposes, but there will be minor differences. For example, I gave each instance a __name__ that matches the name they're assigned to, not the lib_-prefixed name used in libtowrap... but I copied the original __doc__, which might refer to a prefixed name like lib_some_other_function. Also, testing them with isinstance will probably surprise people.
For more about decorators, and for many more annoying little discrepancies like the ones I mentioned above, see Graham Dumpleton's half-hour lecture "Advanced Methods for Creating Decorators" (PyCon US 2014; slides). He is the author of the wrapt module (Python Package Index; Git Hub; Read the Docs), which corrects all(?) of the usual decorator inconsistencies. It might solve your problem entirely (except for the old lib_-style names showing up in __doc__).

Categories

Resources