__PRETTY_FUNCTION equivalent in Python - python-3.x

g++ has this nice variable PRETTY_FUNCTION that contains the name of the function called. For functions it produces the prototype (e.g., "void foo(long)"). For member functions in classes, the name includes the class name (e.g., "void Foo::foo(long)").
Is there an equivalent in Python. I have been playing around with "sys._getframe()" which gets close, but there doesn't seem to be a similarly simple mechanism that includes the class name when it is a member function.
I like to use this in error handlers.
Surely someone has a magical one-liner for this...
TIA,
-Joe

Example Python Code
This is about the closest I can get right now. Search for "<<< here".
Typing Foo.CLNAME is kind of silly. It would be nice if this could somehow be collapsed to an external function and stay outside of the class. There must be a way to do this in Python in a way similar to the way LINE and NAME work.
The implementations of those two are based on code I got from here:
How to determine file, function and line number?
Nice stuff!
-Joe
=====
#!/usr/bin/env python
# import system modules
#
import os
import sys
# define a hack to get the function name
#
class __MYNAME__(object):
def __repr__(self):
try:
raise Exception
except:
return str(sys.exc_info()[2].tb_frame.f_back.f_code.co_name)
def __init__(self):
pass
__NAME__ = __MYNAME__()
# define a hack to get the line number in a program
#
class __MYLINE__(object):
def __repr__(self):
try:
raise Exception
except:
return str(sys.exc_info()[2].tb_frame.f_back.f_lineno)
__LINE__ = __MYLINE__()
# use these in a function call
#
def joe():
print("[FUNCTION] name: %s, line: %s" %
(__NAME__, __LINE__)) # <<< here
# use these in a class member function
#
class Foo():
def __init__(self):
Foo.__CLNAME__ = self.__class__.__name__
def joe(self):
print("[CLASS] name: %s::%s, line: %s" %
(Foo.__CLNAME__, __NAME__, __LINE__)) # <<< here
#--------------------------------
# test all this in a main program
#--------------------------------
def main(argv):
# main program
#
print("[MAIN PROGRAM] name: %s, line: %s" %
(__NAME__, __LINE__)) # <<< here
# function call
#
joe()
# class member function
#
foo = Foo()
foo.joe()
# exit gracefully
#
sys.exit(os.EX_OK)
#
# end of main
# begin gracefully
#
if __name__ == "__main__":
main(sys.argv[0:])
#
# end of file

Related

How to call a variable within a function if it runs under a Class

How to call a variable within a function:
What is the Right approach:
Should define the variable before class or
We can define it under the class or function
Sample Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
timeStamp = time.strftime("%Y%m%d%H%M%S") # <-- Is this right Approach
class Scanner:
INFO = 0
DEBUG = 3
timeStamp = time.strftime("%Y%m%d%H%M%S") # <-- ?
def __init__(self, config_file, verbose=False):
""" Constructor """
def ask_passwords(self):
def ldap_init(self):
def hosts_module_scanner(self):
def users_module_scanner(self):
def ldap_reporting(self, user_list):
self.write_report(failed_users, "users_ldap_report-{}.txt".format(timeStamp))
def option_parser(prog_version):
if __name__ == '__main__':
scanner.ask_passwords()
scanner.ldap_init()
scanner.hosts_module_scanner()
scanner.users_module_scanner()
Note: In the above example it doesn't work if i define under class.
You can call variables within a class, using the syntax:
self.variable_name = # whatever you're assigning the variable.
As for where abouts in the class, your best bet is within the def init_() bit.
edit:
As a more verbose answer. you'll define the variables in the init method as shown below. Using self.variable in a class, but outside the methods (class functions) will throw a "self is not defined" error.
class Scanner:
def __init__(self, config_file, verbose=False):
""" Constructor """
self.INFO = 0
self.DEBUG = 3
self.timeStamp = time.strftime("%Y%m%d%H%M%S")
#declare rest of variables here
#other class methods go here

how to dynamically access class Instance Attribute python [duplicate]

How do I call a function, using a string with the function's name? For example:
import foo
func_name = "bar"
call(foo, func_name) # calls foo.bar()
Given a module foo with method bar:
import foo
bar = getattr(foo, 'bar')
result = bar()
getattr can similarly be used on class instance bound methods, module-level methods, class methods... the list goes on.
Using locals(), which returns a dictionary with the current local symbol table:
locals()["myfunction"]()
Using globals(), which returns a dictionary with the global symbol table:
globals()["myfunction"]()
Based on Patrick's solution, to get the module dynamically as well, import it using:
module = __import__('foo')
func = getattr(module, 'bar')
func()
Just a simple contribution. If the class that we need to instance is in the same file, we can use something like this:
# Get class from globals and create an instance
m = globals()['our_class']()
# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')
# Call it
func()
For example:
class A:
def __init__(self):
pass
def sampleFunc(self, arg):
print('you called sampleFunc({})'.format(arg))
m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')
# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')
And, if not a class:
def sampleFunc(arg):
print('you called sampleFunc({})'.format(arg))
globals()['sampleFunc']('sample arg')
Given a string, with a complete python path to a function, this is how I went about getting the result of said function:
import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()
The best answer according to the Python programming FAQ would be:
functions = {'myfoo': foo.bar}
mystring = 'myfoo'
if mystring in functions:
functions[mystring]()
The primary advantage of this technique is that the strings do not need to match the names of the functions. This is also the primary technique used to emulate a case construct
The answer (I hope) no one ever wanted
Eval like behavior
getattr(locals().get("foo") or globals().get("foo"), "bar")()
Why not add auto-importing
getattr(
locals().get("foo") or
globals().get("foo") or
__import__("foo"),
"bar")()
In case we have extra dictionaries we want to check
getattr(next((x for x in (f("foo") for f in
[locals().get, globals().get,
self.__dict__.get, __import__])
if x)),
"bar")()
We need to go deeper
getattr(next((x for x in (f("foo") for f in
([locals().get, globals().get, self.__dict__.get] +
[d.get for d in (list(dd.values()) for dd in
[locals(),globals(),self.__dict__]
if isinstance(dd,dict))
if isinstance(d,dict)] +
[__import__]))
if x)),
"bar")()
For what it's worth, if you needed to pass the function (or class) name and app name as a string, then you could do this:
myFnName = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn = getattr(app,myFnName)
Try this. While this still uses eval, it only uses it to summon the function from the current context. Then, you have the real function to use as you wish.
The main benefit for me from this is that you will get any eval-related errors at the point of summoning the function. Then you will get only the function-related errors when you call.
def say_hello(name):
print 'Hello {}!'.format(name)
# get the function by name
method_name = 'say_hello'
method = eval(method_name)
# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)
As this question How to dynamically call methods within a class using method-name assignment to a variable [duplicate] marked as a duplicate as this one, I am posting a related answer here:
The scenario is, a method in a class want to call another method on the same class dynamically, I have added some details to original example which offers some wider scenario and clarity:
class MyClass:
def __init__(self, i):
self.i = i
def get(self):
func = getattr(MyClass, 'function{}'.format(self.i))
func(self, 12) # This one will work
# self.func(12) # But this does NOT work.
def function1(self, p1):
print('function1: {}'.format(p1))
# do other stuff
def function2(self, p1):
print('function2: {}'.format(p1))
# do other stuff
if __name__ == "__main__":
class1 = MyClass(1)
class1.get()
class2 = MyClass(2)
class2.get()
Output (Python 3.7.x)
function1: 12
function2: 12
none of what was suggested helped me. I did discover this though.
<object>.__getattribute__(<string name>)(<params>)
I am using python 2.66
Hope this helps
Although getattr() is elegant (and about 7x faster) method, you can get return value from the function (local, class method, module) with eval as elegant as x = eval('foo.bar')(). And when you implement some error handling then quite securely (the same principle can be used for getattr). Example with module import and class:
# import module, call module function, pass parameters and print retured value with eval():
import random
bar = 'random.randint'
randint = eval(bar)(0,100)
print(randint) # will print random int from <0;100)
# also class method returning (or not) value(s) can be used with eval:
class Say:
def say(something='nothing'):
return something
bar = 'Say.say'
print(eval(bar)('nice to meet you too')) # will print 'nice to meet you'
When module or class does not exist (typo or anything better) then NameError is raised. When function does not exist, then AttributeError is raised. This can be used to handle errors:
# try/except block can be used to catch both errors
try:
eval('Say.talk')() # raises AttributeError because function does not exist
eval('Says.say')() # raises NameError because the class does not exist
# or the same with getattr:
getattr(Say, 'talk')() # raises AttributeError
getattr(Says, 'say')() # raises NameError
except AttributeError:
# do domething or just...
print('Function does not exist')
except NameError:
# do domething or just...
print('Module does not exist')
In python3, you can use the __getattribute__ method. See following example with a list method name string:
func_name = 'reverse'
l = [1, 2, 3, 4]
print(l)
>> [1, 2, 3, 4]
l.__getattribute__(func_name)()
print(l)
>> [4, 3, 2, 1]
Nobody mentioned operator.attrgetter yet:
>>> from operator import attrgetter
>>> l = [1, 2, 3]
>>> attrgetter('reverse')(l)()
>>> l
[3, 2, 1]
>>>
getattr calls method by name from an object.
But this object should be parent of calling class.
The parent class can be got by super(self.__class__, self)
class Base:
def call_base(func):
"""This does not work"""
def new_func(self, *args, **kwargs):
name = func.__name__
getattr(super(self.__class__, self), name)(*args, **kwargs)
return new_func
def f(self, *args):
print(f"BASE method invoked.")
def g(self, *args):
print(f"BASE method invoked.")
class Inherit(Base):
#Base.call_base
def f(self, *args):
"""function body will be ignored by the decorator."""
pass
#Base.call_base
def g(self, *args):
"""function body will be ignored by the decorator."""
pass
Inherit().f() # The goal is to print "BASE method invoked."
i'm facing the similar problem before, which is to convert a string to a function. but i can't use eval() or ast.literal_eval(), because i don't want to execute this code immediately.
e.g. i have a string "foo.bar", and i want to assign it to x as a function name instead of a string, which means i can call the function by x() ON DEMAND.
here's my code:
str_to_convert = "foo.bar"
exec(f"x = {str_to_convert}")
x()
as for your question, you only need to add your module name foo and . before {} as follows:
str_to_convert = "bar"
exec(f"x = foo.{str_to_convert}")
x()
WARNING!!! either eval() or exec() is a dangerous method, you should confirm the safety.
WARNING!!! either eval() or exec() is a dangerous method, you should confirm the safety.
WARNING!!! either eval() or exec() is a dangerous method, you should confirm the safety.
You means get the pointer to an inner function from a module
import foo
method = foo.bar
executed = method(parameter)
This is not a better pythonic way indeed is possible for punctual cases
This is a simple answer, this will allow you to clear the screen for example. There are two examples below, with eval and exec, that will print 0 at the top after cleaning (if you're using Windows, change clear to cls, Linux and Mac users leave as is for example) or just execute it, respectively.
eval("os.system(\"clear\")")
exec("os.system(\"clear\")")

Python click option based logging in decorator

Fresh start. I have a CLI application that uses click for handling argument parsing. For the main "executable" script I have a defined verbosity flag (-v, -vv, -vvv, ...) that controls logging verbosity. I want to "trace" function calls for specific functions. Down below is a sample that hopefully will make it clear.
import click
import logging
import functools
class MyLogger(object):
def __init__(self):
self.__logger = None
def init_logger(self, name, verbosity):
logging_levels = {0: logging.CRITICAL,
1: logging.ERROR,
2: logging.INFO,
3: logging.DEBUG}
logging.basicConfig(level=logging_levels.get(verbosity, logging.WARNING))
self.__logger = logging.getLogger(name)
#property
def logger(self):
return self.__logger
myLogger = MyLogger()
class TraceFunction(object):
def __init__(self, logger):
self.logger = logger
def __call__(self, function):
name = function.__name__
#functools.wraps(function)
def wrapped(*args, **kwargs):
self.logger.debug(f'{name}({list(*args)}, {dict(**kwargs)})')
result = function(*args, **kwargs)
self.logger.debug(f'{result}')
return result
return wrapped
# (1) #TraceFunction(myLogger.logger)
def echo(message):
return message.upper()
#click.command('echo')
#click.option('-e', '--echo', 'message', required=True, type=str)
def echo_command(message):
myLogger.logger.info('echo_command')
return echo(message)
#click.group()
#click.option('-v', 'verbosity', count=True)
def main(verbosity: int):
myLogger.init_logger(__name__, verbosity)
# (2) TraceFunction(myLogger.logger)(echo)
myLogger.logger.info('main')
if __name__ == '__main__':
main.add_command(echo_command)
main()
The above if executed will correctly produce the following output:
script.py -vv echo -e "Hello World"
INFO: __main__:main
INFO: __main__:echo_command
I want to "trace" the function: echo. More precisely I want to log the actual function call with the actual arguments and the returned value. Okay, a bit more than that but I needed a minimal sample. For this purpose I tried two things, labeled with (1) and (2) placed in comments.
#TraceFunction(myLogger.logger)
def echo(message):
return message.upper()
It flat out doesn't work as with my original question python will execute TraceFunction.call(echo) before in "main" I call init_logger that essentially would configure the logger itself. As a result in TraceFunction.call the logger is None and I get:
AttributeError: 'NoneType' object has no attribute 'debug'
Fine, I can register it later on, at least I thought with (2). Well the exception surely went away, however "wrapped" defined in call is never invoked and well once again nothing gets logged other than the already shown
script.py -vvv echo -e "Hello World"
INFO: __main__:main
INFO: __main__:echo_command
#Update
Going by afterburner's answer things go a bit further but it doesn't do what it's supposed to:
script.py -vvv echo -e "Hello World"
DEBUG:__main__:echo(['F','o','o'],{})
DEBUG:__main__:FOO
INFO: __main__:main
INFO: __main__:echo_command
Which well is expected. The expected output on the other hand would be:
script.py -vvv echo -e "Hello World"
INFO: __main__:main
INFO: __main__:echo_command
DEBUG:__main__:echo(['Hello World'],{})
DEBUG:__main__:HELLO WORLD
So, the main issue I can see is that you're not calling the wrapped function.
TraceFunction(myLogger.logger)(echo)
# vs
TraceFunction(myLogger.logger)(echo)()
I have also made a couple of changes to your code, but the main issue was the fact the wrapped function was never getting invoked.
class MyLogger(object):
def __init__(self):
self.__logger = None
def init_logger(self, name, verbosity):
# extract log level based on verbosity flag
logging_levels = [logging.CRITICAL, logging.INFO, logging.DEBUG]
logging.basicConfig(level=logging_levels[verbosity])
self.__logger = logging.getLogger(name)
#property
def logger(self):
return self.__logger
myLogger = MyLogger()
class TraceFunction(object):
def __init__(self, logger):
self.logger = logger
def __call__(self, function):
name = function.__name__
#functools.wraps(function)
def wrapped(*args, **kwargs):
# improved the formatting of arguments
nicely_formatted_args = ', '.join(args)
nicely_formatted_kwargs = ', '.join(kwargs)
arguments = nicely_formatted_args
if nicely_formatted_kwargs != '':
arguments = f'{arguments}, {nicely_formatted_kwargs}'
self.logger.debug(f'{name}({arguments})')
result = function(*args, **kwargs)
self.logger.debug(f'{result}')
return result
return wrapped
# (1) #TraceFunction(myLogger.logger)
def echo(message):
return message.upper()
#click.command('echo')
#click.option('-e', '--echo', 'message', required=True, type=str)
def echo_command(message):
myLogger.logger.info('echo_command')
return echo(message)
#click.group()
#click.option('-v', 'verbosity', count=True) # <- made verbosity a count argument so you can extract all of your levels based on -v -vv -vvv etc.
def main(verbosity):
myLogger.init_logger(__name__, verbosity)
# (2)
# Invoking the function with argument 'Foo'
TraceFunction(myLogger.logger)(echo)("Foo")
def run_logging():
main.add_command(echo_command)
main()
if __name__ == '__main__':
run_logging()
I managed to get it working but it sure is ugly... at least in its current form. The only needed change was:
#click.group()
#click.option('-v', 'verbosity', count=True)
def main(verbosity: int = 0):
global echo
myLogger.init_logger(__name__, verbosity)
echo = TraceFunction(myLogger.logger)(echo) # <<< !!!
myLogger.logger.info('main')
In doing so the output becomes:
INFO:__main__:main
INFO:__main__:echo_command
TRACE:__main__:echo(['Hello World'], {})
TRACE:__main__:HELLO WORLD
So the answer was, that I completely missed:
TraceFunction(myLogger.logger)(echo)
is fine, but I needed to assign it to the original echo function:
echo = TraceFunction(myLogger.logger)(echo)

Calling class level variables using "#pytest.mark.parametrize" fixture

I'm trying to iterate a pytest test over a list of values which i generate inside another method in the test class.
The problem is that i get:
"#pytest.mark.parametrize("number",TestScratch.list_testing)
NameError: name 'TestScratch' is not defined" error when i try to run.I know for a fact that when i pass the list as a hard coded list i.e [0,3,54,90] it works.
Below is my code :
class TestScratch(object):
#classmethod
def setup_class(cls):
cls.list_testing = []
#classmethod
def setup_method(cls):
pass
def test_populate_list(self):
for i in range(100):
self.list_testing.append(i)
#pytest.mark.parametrize("number",TestScratch.list_testing)
def test_pytest_param(self, number):
assert type(number) == int
#classmethod
def teardown_class(cls):
'''
pass
'''
I also tried self.class.list_testing
but i get the same error
Environment details:
Python: 3.6.8
Pytest: 5.2.1
You can't use the class in the class definition. As the decorator is read at import time, e. g. while loading the class definition, and not at runtime, the class is not known at this point. You have to define the list outside the class instead:
import pytest
def populate_list():
test_list = []
for i in range(100):
test_list.append(i)
return test_list
list_testing = populate_list()
class TestScratch:
def test_populate_list(self):
# this will fail if list_testing could not be populated
assert len(list_testing) > 50
#pytest.mark.parametrize("number", list_testing)
def test_pytest_param(self, number):
# this will be skipped if list_testing could not be populated
assert type(number) == int
Any parameter you use in a decorator is read only once at load time, so trying to intialize it at runtime won't work. For example here you can find an explanation how parametrization works and why it is not possible to add parameters at runtime.

How can I redirect hardcoded calls to open to custom files?

I've written some python code that needs to read a config file at /etc/myapp/config.conf . I want to write a unit test for what happens if that file isn't there, or contains bad values, the usual stuff. Lets say it looks like this...
""" myapp.py
"""
def readconf()
""" Returns string of values read from file
"""
s = ''
with open('/etc/myapp/config.conf', 'r') as f:
s = f.read()
return s
And then I have other code that parses s for its values.
Can I, through some magic Python functionality, make any calls that readconf makes to open redirect to custom locations that I set as part of my test environment?
Example would be:
main.py
def _open_file(path):
with open(path, 'r') as f:
return f.read()
def foo():
return _open_file("/sys/conf")
test.py
from unittest.mock import patch
from main import foo
def test_when_file_not_found():
with patch('main._open_file') as mopen_file:
# Setup mock to raise the error u want
mopen_file.side_effect = FileNotFoundError()
# Run actual function
result = foo()
# Assert if result is expected
assert result == "Sorry, missing file"
Instead of hard-coding the config file, you can externalize it or parameterize it. There are 2 ways to do it:
Environment variables: Use a $CONFIG environment variable that contains the location of the config file. You can run the test with an environment variable that can be set using os.environ['CONFIG'].
CLI params: Initialize the module with commandline params. For tests, you can set sys.argv and let the config property be set by that.
In order to mock just calls to open in your function, while not replacing the call with a helper function, as in Nf4r's answer, you can use a custom patch context manager:
from contextlib import contextmanager
from types import CodeType
#contextmanager
def patch_call(func, call, replacement):
fn_code = func.__code__
try:
func.__code__ = CodeType(
fn_code.co_argcount,
fn_code.co_kwonlyargcount,
fn_code.co_nlocals,
fn_code.co_stacksize,
fn_code.co_flags,
fn_code.co_code,
fn_code.co_consts,
tuple(
replacement if call == name else name
for name in fn_code.co_names
),
fn_code.co_varnames,
fn_code.co_filename,
fn_code.co_name,
fn_code.co_firstlineno,
fn_code.co_lnotab,
fn_code.co_freevars,
fn_code.co_cellvars,
)
yield
finally:
func.__code__ = fn_code
Now you can patch your function:
def patched_open(*args):
raise FileNotFoundError
with patch_call(readconf, "open", "patched_open"):
...
You can use mock to patch a module's instance of the 'open' built-in to redirect to a custom function.
""" myapp.py
"""
def readconf():
s = ''
with open('./config.conf', 'r') as f:
s = f.read()
return s
""" test_myapp.py
"""
import unittest
from unittest import mock
import myapp
def my_open(path, mode):
return open('asdf', mode)
class TestSystem(unittest.TestCase):
#mock.patch('myapp.open', my_open)
def test_config_not_found(self):
try:
result = myapp.readconf()
assert(False)
except FileNotFoundError as e:
assert(True)
if __name__ == '__main__':
unittest.main()
You could also do it with a lambda like this, if you wanted to avoid declaring another function.
#mock.patch('myapp.open', lambda path, mode: open('asdf', mode))
def test_config_not_found(self):
...

Resources