I have a code snippet. Can anyone tell me whether class.main calls the initi method automatically? I cannot find a main method defined here, but calling to main. What is TwitterStreamWarcIter.main calling?
#!/usr/bin/env python3
from __future__ import absolute_import
from sfmutils.warc_iter import BaseWarcIter
from dateutil.parser import parse as date_parse
class TwitterStreamWarcIter(BaseWarcIter):
def __init__(self, filepaths, limit_user_ids=None):
BaseWarcIter.__init__(self, filepaths)
self.limit_user_ids = limit_user_ids
def _select_record(self, url):
return url.startswith("https://stream.twitter.com/1.1")
def _item_iter(self, url, json_obj):
# Only want statuses, not deletes, stall_warnings, etc.
if "id_str" in json_obj:
yield "twitter_status", json_obj["id_str"], date_parse(json_obj["created_at"]), json_obj
else:
yield None, None, None, json_obj
#staticmethod
def item_types():
return ["twitter_status"]
#property
def line_oriented(self):
return True
def _select_item(self, item):
if not self.limit_user_ids or item.get("user", {}).get("id_str") in self.limit_user_ids:
return True
return False
if __name__ == "__main__":
TwitterStreamWarcIter.main(TwitterStreamWarcIter)
No it doesn't call the __init__ method automatically, it must be that TwitterStreamWarcIter.main calls the main function defined in the superclass BaseWarcIter which code you haven't provided. TwitterStreamWarcIter inherits this function and it is called by the piece of code TwitterStreamWarcIter.main(TwitterStreamWarcIter)
Related
You can get the function name and line with sys._getframe().f_code.co_name and sys._getframe().f_lineno.
I'd like a wrapper around these (awkward) values, something like:
def fn(): return sys._getframe().f_code.co_name
def line(): return sys._getframe().f_lineno
but that doesn't work.
For example, the following code
import sys
def fn(): return sys._getframe().f_code.co_name
def line(): return sys._getframe().f_lineno
def main():
print(sys._getframe().f_code.co_name, fn())
print(sys._getframe().f_lineno, line())
main()
should return
main main
8 8
but instead it returns
main fn
8 4
How can I achieve the desired effect?
EDIT: Turns out you can do it just relying on sys, by passing parameter 1 to sys._getframe to get the frame below the current one fn. According to python documentation:
sys._getframe([depth])
Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default for depth is zero, returning the frame at the top of the call stack.
Your code will look like this:
import sys
def fn(): return sys._getframe(1).f_code.co_name
def line(): return sys._getframe(1).f_lineno
def main():
print(sys._getframe().f_code.co_name, fn())
print(sys._getframe().f_lineno, line())
main()
Output
main main
8 8
Second way:
sys._getframe().f_code.co_name will return the current function, which is always fn. To get the frame below the current one, use traceback:
import sys
import inspect
def fn(): return inspect.stack()[-2].function
def line(): return inspect.stack()[-2].lineno
def main():
print(sys._getframe().f_code.co_name, fn())
print(sys._getframe().f_lineno, line())
main()
Output
main main
9 9
I have fixture which create mocker.Mock instead of gui.Menu object during initialization of gui.Buttons. Reference is stored in Buttons.menu attribute. In my test I check if proper function is called in gui.Buttons.add. Parametrized test worked well until I met condition where method from gui.Menu should be called. Now there is a mock.
import pytest
from project import gui
#pytest.fixture
def buttons(mocker):
mocker.patch('project.gui.tk.Frame.__init__', return_value=None)
mocker.patch('project.gui.tk.Button')
return gui.Buttons(mocker.Mock())
#pytest.mark.parametrize('value,patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data'),
(True, 'pytest.Mock.show_error'),
))
def test_add_calls_function(buttons, value, patched, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
mocked.assert_called_once()
With real object I could write (True, 'project.gui.Menu.show_error') inside #pytest.mark.parametrize instead of (True, 'pytest.Mock.show_error') which doesn't work and produces ModuleNotFoundError: No module named 'pytest.Mock'.
I wonder if it is possible to patch created mock object in my fixture to make it work like other parametrized examples. Is it even possible? Correct me please if way how I understand it is wrong.
Tested code looks like:
import tkinter as tk
import tkinter.messagebox as msg
from project.connection import Database
def show_no_connection():
msg.showerror('Error', 'Could not perform operation. Try again later.')
class Menu(tk.Tk):
def __init__(self):
super().__init__()
self.form = Form()
def show_error(self, message):
self.form.clear()
msg.showerror('Error', message)
class Form(tk.Frame):
def clear(self):
print('Clearing...')
def get(self):
return {'Title': 'Test', 'ISBN': 87327837823}
class Buttons(tk.Frame):
def __init__(self, menu):
super().__init__(menu)
self.menu = menu
def process_data(self, data, operation):
operation(data)
def add(self):
data = self.menu.form.get()
exists = self.exist_check(data.get('ISBN', None))
if exists is None:
show_no_connection()
else:
if exists:
self.menu.show_error(
'Record with set ISBN already exists in database.')
else:
self.process_data(data, Database().add)
#staticmethod
def exist_check(number):
if number:
return Database().search({'ISBN': number})
return False
Displayed error:
=================================== FAILURES ===================================
_________ test_add_calls_function[True-project.gui.Gui.show_error] _________
buttons = <[AttributeError("'Buttons' object has no attribute '_w'") raised in repr()] Buttons object at 0x7f840114aa10>
value = True, patched = 'project.gui.Gui.show_error'
mocker = <pytest_mock.plugin.MockFixture object at 0x7f840114ab90>
#pytest.mark.parametrize('value,patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data'),
(True, 'project.gui.Gui.show_error'),
))
def test_add_calls_function(buttons, value, patched, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
> mocked.assert_called_once()
E AssertionError: Expected 'show_error' to have been called once. Called 0 times.
tests/test_gui_buttons.py:88: AssertionError
I don't see a possibility to handle this in the same test - you probably will need a separate test for the last call. The problem is that the menu is already mocked, and you need that specific menu mock to do the test for the function call (the function will be called from that mock instance).
Here is a possible working implementation:
import pytest
# don't use "from project import gui" here to not make a copy in the test module
# that would be used instead of the mocked one
import project.gui
#pytest.fixture
def menu_mock(mocker):
# gives the possibility to access the menu mock
# we need the return_value to get the instance instead of the class
return mocker.patch('project.gui.Menu').return_value
#pytest.fixture
def buttons(mocker, menu_mock):
mocker.patch('project.gui.tk.Frame.__init__', return_value=None)
mocker.patch('project.gui.tk.Button')
return project.gui.Buttons(menu_mock)
#pytest.mark.parametrize('value, patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data')
))
def test_add_calls_function(buttons, value, patched, mocker):
# unchanged except for the missing parametrize case
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
mocked.assert_called_once()
def test_add_calls_show_error(buttons, menu_mock, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=True)
buttons.add()
# you now have access to the mocked menu instance
menu_mock.show_error.assert_called_once()
I am trying to debug a method in a class. So in the iterative console I have imported my class using the line below.
from email_reader import MyClass
I then thought I just had to set an instance of my class like below.
ma_cls = MyClass('MyFolder')
Then I could call the function get_email like below,
ma_cls.get_email(filename, date_from, date_to)
When I run it the breakpoints never get hit and all that is returned is below.
Out[353]:
What am I doing wrong?
class MyClass:
def __init__(self,
outlook_folder: str):
self.__outlook_folder = outlook_folder
def get_email(self,
csv_filename: str,
emails_since: dt.datetime,
emails_to: dt.datetime = None,
unread_only: bool = False
):
breakpoint()
# some logic
if __name__ == "__main__":
breakpoint()
sse = MyClass("MyFolder")
for wt in sse.get_email(
'some_file_name.CSV',
emails_since=dt.datetime(2020, 2, 4),
emails_to=dt.datetime(2020, 2, 5),
unread_only=False):
pass
Code block in
if __name__ == "__main__":
is executed only when the script is run directly (when you directly execute the script that contains your MyClass). If you are importing the above file then everything that is inside the above if-statement is simply ignored.
I'm new to mock and really strugling with it. Mostly in documentation and most of SO pages it shows how to get the mock result_value, but I want to check if the values I'm getting from methods are correct, not the result_value's. Here's the example:
#!/usr/bin/env python
class Example:
def one(self):
return 1
def two(self, one):
print(one + 1) # basically any void method, ex: result = one + 1 and check result value if correct
def main(self):
self.two(self.one())
if __name__ == '__main__':
e = Example()
e.main()
Test:
#!/usr/bin/env python
import unittest
import example
from mock import patch
class Example(unittest.TestCase):
def test_one(self):
self.assertEqual(1, et.one())
def test_two(self):
with patch('example.Example.two'):
self.assertEqual(2, et.two(et.one())) # ..the part I'm stuck
# whick ofc throws AssertionError: 2 != <MagicMock name='two()' id='blablabla'>
def test_main(self):
# unknown part..
if __name__ == '__main__':
et = example.Example()
unittest.main()
How to achieve void method check with unittest?
UPDATE:
so the print I figured out with chepner's help:
def test_twoi3(self):
mock_print = MagicMock()
with patch('sys.stdout', mock_print):
print(2)
expected = call.write('2')
self.assertEqual(mock_print.mock_calls[0], expected)
and for main I'm not quite sure if it is a good solution...:
def test_main(self):
with patch ('example.Example.main') as m:
et.main(et.two(1))
m.assert_called_with(et.two(1))
but I want to check not by passing the methods and values, but if main calls other two methods. How to achieve this?
You don't need to mock anything (directly, anyway); you want to capture standard output and verify that it is what you expect.
from contextlib import redirect_stdout
from io import StringIO
def test_two(self):
stdout = StringIO()
with redirect_stdout(stdout):
et.two(et.one())
self.assertEqual(stdout.getvalue(), "2\n")
Or, you can mock the print and check that it is called with the expected arguments.
def test_two(self):
with patch('__builtin__.print') as p:
et.two(et.one())
p.assert_called_with(2)
I have figured out how to test if main methods have been called. Test looks like this:
#!/usr/bin/env python
import unittest
import example
from mock import patch, MagicMock, call
class Example(unittest.TestCase):
def setUp(self):
self.et = example.Example()
def test_one(self):
self.assertEqual(1, self.et.one())
def test_two(self):
mock_print = MagicMock()
with patch('sys.stdout', mock_print):
print(2)
expected = call.write('2')
self.assertEqual(mock_print.mock_calls[0], expected)
def test_main(self):
self.et.two = MagicMock(side_effect=self.et.two)
self.et.one = MagicMock(side_effect=self.et.one)
self.et.main()
self.et.one.assert_called()
self.et.two.assert_called()
self.et.one.__str__ = self.et.one
self.assertEqual(1, int(self.et.one))
if __name__ == '__main__':
unittest.main()
Upon mocking methods that are in main (all of them) and calling main methods one and two have been successfully called. For one you can return value by using __str__
Python: How to get the caller's method name in the called method?
Assume I have 2 methods:
def method1(self):
...
a = A.method2()
def method2(self):
...
If I don't want to do any change for method1, how to get the name of the caller (in this example, the name is method1) in method2?
inspect.getframeinfo and other related functions in inspect can help:
>>> import inspect
>>> def f1(): f2()
...
>>> def f2():
... curframe = inspect.currentframe()
... calframe = inspect.getouterframes(curframe, 2)
... print('caller name:', calframe[1][3])
...
>>> f1()
caller name: f1
this introspection is intended to help debugging and development; it's not advisable to rely on it for production-functionality purposes.
Shorter version:
import inspect
def f1(): f2()
def f2():
print 'caller name:', inspect.stack()[1][3]
f1()
(with thanks to #Alex, and Stefaan Lippen)
This seems to work just fine:
import sys
print sys._getframe().f_back.f_code.co_name
I would use inspect.currentframe().f_back.f_code.co_name. Its use hasn't been covered in any of the prior answers which are mainly of one of three types:
Some prior answers use inspect.stack but it's known to be too slow.
Some prior answers use sys._getframe which is an internal private function given its leading underscore, and so its use is implicitly discouraged.
One prior answer uses inspect.getouterframes(inspect.currentframe(), 2)[1][3] but it's entirely unclear what [1][3] is accessing.
import inspect
from types import FrameType
from typing import cast
def demo_the_caller_name() -> str:
"""Return the calling function's name."""
# Ref: https://stackoverflow.com/a/57712700/
return cast(FrameType, cast(FrameType, inspect.currentframe()).f_back).f_code.co_name
if __name__ == '__main__':
def _test_caller_name() -> None:
assert demo_the_caller_name() == '_test_caller_name'
_test_caller_name()
Note that cast(FrameType, frame) is used to satisfy mypy.
Acknowlegement: comment by 1313e for an answer.
I've come up with a slightly longer version that tries to build a full method name including module and class.
https://gist.github.com/2151727 (rev 9cccbf)
# Public Domain, i.e. feel free to copy/paste
# Considered a hack in Python 2
import inspect
def caller_name(skip=2):
"""Get a name of a caller in the format module.class.method
`skip` specifies how many levels of stack to skip while getting caller
name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
An empty string is returned if skipped levels exceed stack height
"""
stack = inspect.stack()
start = 0 + skip
if len(stack) < start + 1:
return ''
parentframe = stack[start][0]
name = []
module = inspect.getmodule(parentframe)
# `modname` can be None when frame is executed directly in console
# TODO(techtonik): consider using __main__
if module:
name.append(module.__name__)
# detect classname
if 'self' in parentframe.f_locals:
# I don't know any way to detect call from the object method
# XXX: there seems to be no way to detect static method call - it will
# be just a function call
name.append(parentframe.f_locals['self'].__class__.__name__)
codename = parentframe.f_code.co_name
if codename != '<module>': # top level usually
name.append( codename ) # function or a method
## Avoid circular refs and frame leaks
# https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack
del parentframe, stack
return ".".join(name)
Bit of an amalgamation of the stuff above. But here's my crack at it.
def print_caller_name(stack_size=3):
def wrapper(fn):
def inner(*args, **kwargs):
import inspect
stack = inspect.stack()
modules = [(index, inspect.getmodule(stack[index][0]))
for index in reversed(range(1, stack_size))]
module_name_lengths = [len(module.__name__)
for _, module in modules]
s = '{index:>5} : {module:^%i} : {name}' % (max(module_name_lengths) + 4)
callers = ['',
s.format(index='level', module='module', name='name'),
'-' * 50]
for index, module in modules:
callers.append(s.format(index=index,
module=module.__name__,
name=stack[index][3]))
callers.append(s.format(index=0,
module=fn.__module__,
name=fn.__name__))
callers.append('')
print('\n'.join(callers))
fn(*args, **kwargs)
return inner
return wrapper
Use:
#print_caller_name(4)
def foo():
return 'foobar'
def bar():
return foo()
def baz():
return bar()
def fizz():
return baz()
fizz()
output is
level : module : name
--------------------------------------------------
3 : None : fizz
2 : None : baz
1 : None : bar
0 : __main__ : foo
You can use decorators, and do not have to use stacktrace
If you want to decorate a method inside a class
import functools
# outside ur class
def printOuterFunctionName(func):
#functools.wraps(func)
def wrapper(self):
print(f'Function Name is: {func.__name__}')
func(self)
return wrapper
class A:
#printOuterFunctionName
def foo():
pass
you may remove functools, self if it is procedural
An alternative to sys._getframe() is used by Python's Logging library to find caller information. Here's the idea:
raise an Exception
immediately catch it in an Except clause
use sys.exc_info to get Traceback frame (tb_frame).
from tb_frame get last caller's frame using f_back.
from last caller's frame get the code object that was being executed in that frame.
In our sample code it would be method1 (not method2) being executed.
From code object obtained, get the object's name -- this is caller method's name in our sample.
Here's the sample code to solve example in the question:
def method1():
method2()
def method2():
try:
raise Exception
except Exception:
frame = sys.exc_info()[2].tb_frame.f_back
print("method2 invoked by: ", frame.f_code.co_name)
# Invoking method1
method1()
Output:
method2 invoked by: method1
Frame has all sorts of details, including line number, file name, argument counts, argument type and so on. The solution works across classes and modules too.
Code:
#!/usr/bin/env python
import inspect
called=lambda: inspect.stack()[1][3]
def caller1():
print "inside: ",called()
def caller2():
print "inside: ",called()
if __name__=='__main__':
caller1()
caller2()
Output:
shahid#shahid-VirtualBox:~/Documents$ python test_func.py
inside: caller1
inside: caller2
shahid#shahid-VirtualBox:~/Documents$
I found a way if you're going across classes and want the class the method belongs to AND the method. It takes a bit of extraction work but it makes its point. This works in Python 2.7.13.
import inspect, os
class ClassOne:
def method1(self):
classtwoObj.method2()
class ClassTwo:
def method2(self):
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 4)
print '\nI was called from', calframe[1][3], \
'in', calframe[1][4][0][6: -2]
# create objects to access class methods
classoneObj = ClassOne()
classtwoObj = ClassTwo()
# start the program
os.system('cls')
classoneObj.method1()
Hey mate I once made 3 methods without plugins for my app and maybe that can help you, It worked for me so maybe gonna work for you too.
def method_1(a=""):
if a == "method_2":
print("method_2")
if a == "method_3":
print("method_3")
def method_2():
method_1("method_2")
def method_3():
method_1("method_3")
method_2()