cprofile on python module - python

I am trying to profile a reasonably sized python project using cprofile.
I am usually invoking my python app as a module something like:
python -m cabon.apps.detector -i input_image.png
Now howo can I use cprofile from the command line. I see that the cProfile itself is invoked as a module with -m and how can this be combined with my python app which is also invoked as a module?

The files cProfile and profile can also be invoked as a script to profile another script. For example:
python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)
As mentioned in the documentation, we can specify that a module is being profiled by using additional -m. First for the cProfile and then the actual module:
python -m cProfile -m cabon.apps.detector -i input_image.png

Related

How to run cprofile with already a -m existing in command line?

Usually if you have a script foo.py you can easily profile it as follows:
python -m cProfile foo.py
However let's imagine I am already running foo as a module with -m:
python -m path.foo
In this case is there a clean way to profile this execution? I have tried:
python -m cProfile -m path.foo
Clearly it did not work but you get what I am trying to do so how do I do it?

Python doctest does not run on files named as signal.py

Problem
I'm using python 3.6.6 on Fedora 28. I have a project structure as follows :
test/__init__.py
test/signal.py
test/notsignal.py
If I run $ python3 -m doctest -v test/signal.py
I get:
10 items had no tests:
signal
signal.Handlers
signal.ItimerError
signal.Sigmasks
signal.Signals
signal._enum_to_int
signal._int_to_enum
signal.struct_siginfo
signal.struct_siginfo.__reduce__
signal.struct_siginfo.__repr__
0 tests in 10 items.
0 passed and 0 failed.
Test passed.
which, to me, clearly shows that doctest is trying to run on the built-in signal module. By renaming the file I was able to run docset. Am I missing something or is this a bug?
To reproduce
You may use the following shell script.
#!/bin/sh
mkdir -p test
touch test/__init__.py
echo -e ""'"'""'"'""'"'"\n>>> _ = print(f'Doctest at {__name__} was run.')\n"'"'""'"'""'"'"" > test/signal.py
cp test/signal.py test/notsignal.py
python3 -m doctest -v test/signal.py
python3 -m doctest -v test/notsignal.py
If you look at the doctest source, you can see that doctest tries to import the modules that you pass to it.
It's very likely that the standard library's signal module has already been imported:
$ python -c 'import sys;import doctest;print("signal" in sys.modules)'
True
When doctest tries the import the Python interpreter finds that there is already a module named "signal" in sys.modules and returns that rather than your signal module.
Perhaps this is a bug - maybe doctest could be smarter about how it imports - but in practice I think the best course of action is to rename your module. In general, having modules with the same names as standard library modules almost always causes problems.

Python: How to run tests made with unittest

This is the structure of my project, and I would like to run the test that I have made from the command line.
I am using the following command:
python test_hotel.py
However I am getting the following error
ImportError: No module named 'hotel'
What can I do to solve this problem, and is there a way to execute the whole tests in a project from the command line.
Thanks in advance.
For running unittest from commandline, you should use this command:
python -m unittest tests.test_hotel
You need to make sure that you have followed the rules in writing unittests (https://docs.python.org/2/library/unittest.html)
As #shahram kalantari said to run a tests the command line is:
python -m unittest tests.test_hotel
If one wants to run the whole tests the command line is:
python -m unittest discover tests
If you want more information about what tests were run the -v flag should be included:
python -m unittest discover tests -v

Can I run line_profiler over a pytest test?

I have identified some long running pytest tests with
py.test --durations=10
I would like to instrument one of those tests now with something like line_profiler or cprofile. I really want to get the profile data from the test itself as the pytest setup or tear down could well be part of what is slow.
However given how line_profiler or cprofile is typically involved it isn't clear to me how to make them work with pytest.
Run pytest like this:
python3 -m cProfile -o profile -m pytest
You can even pass in optional arguments:
python3 -m cProfile -o profile -m pytest tests/worker/test_tasks.py -s campaigns
This will create a binary file called profile in your current directory. This can be analyzed with pstats:
import pstats
p = pstats.Stats('profile')
p.strip_dirs()
p.sort_stats('cumtime')
p.print_stats(50)
This will print the 50 lines with the longest cumulative duration.
To get cProfile and line_profiler to work with py.test code, I did two things:
Extended the py.test test code with a call to pytest.main(), which made it executable with the python interpreter as the main driver:
# pytest_test.py:
#profile # for line_profiler only
def test_example():
x = 3**32
assert x == 1853020188851841
# for profiling with cProfile and line_profiler
import pytest
pytest.main(__file__)
Now you can run this test without py.test as the main driver using other tools:
$ kernprof.py -l pytest_test.py
$ python -m line_profiler pytest_test.py.lprof
or
$ python -m cProfile pytest_test.py
To profile py.test-specific functions such as pytest_funcarg*() with line_profiler I split them in two to avoid confusion between py.test and line_profiler:
def pytest_funcarg__foo(request):
return foo(request)
#profile
def foo(request):
...
The same method works for memory_profiler.
Have you tried the pytest-profiling plugin?
I recently wrote pytest-line-profiler that may be useful. It's not battle tested, so please give me feedback (and help).
This also works with pyinstrument:
pyinstrument -m pytest test.py

Passing arguments to modules in IPython when using run -m

I just installed the git master branch of IPython. The following:
In [1]: run -m my_packages.my_module -verbosity 20
returns an error:
UsageError: option -v not recognized ( allowed: "nidtN:b:pD:l:rs:T:em:G" )
Even though the following works:
$ python -m my_packages.my_module -verbosity 20
I am using argparse as follows:
parser = argparse.ArgumentParser(description='my_program')
parser.add_argument('-verbosity', help='Verbosity', required=True)
Any thoughts why?
Add -- to stop the command-line parsing at a certain point:
In [1]: %run -m my_packages.my_module -- -verbosity 20
This is standard behavior used by argparse for adding extra positional arguments.

Categories

Resources