5

My very simple example project contains:

addtest/
  setup.py
  addtest/
    __init__.py
    __main__.py
    app.py

My app.py is just:

def main():
    raise SystemExit("Command line entry point called.")

My __main__.py is just:

from addtest.app import main
main()

My setup.py contains:

from setuptools import setup, find_packages

setup(
    name='AddTest',
    version='1.0',
    packages=find_packages(),

    entry_points={
        'console_scripts': ['addtest = addtest.app:main']
    },
)

I would expect that running python setup.py test would do nothing, since no unit tests are written. However, running it in a clean virtualenv (Python 3.6.6 on Ubuntu 18.04.1) gives me:

$ python setup.py test
running test
running egg_info
writing AddTest.egg-info/PKG-INFO
writing dependency_links to AddTest.egg-info/dependency_links.txt
writing entry points to AddTest.egg-info/entry_points.txt
writing top-level names to AddTest.egg-info/top_level.txt
reading manifest file 'AddTest.egg-info/SOURCES.txt'
writing manifest file 'AddTest.egg-info/SOURCES.txt'
running build_ext
Command line entry point called.

Note the Command line entry point called. which means it's invoking the console script it generates from my __main__.py (or maybe just calling python -m addtest).

Why is setup.py calling the console script when I want it to run tests? Further inspection of the script's execution shows that sys.argv is ['setup.py','test'] - why?

1
  • Regarding sys.argv sys.argv[0] gives the name of the script being called, and argv provides a list of all the arguments passed to the script so python setup.py test gives you ['setup.py', 'test']. docs.python.org/3/library/sys.html#sys.argv Commented Sep 28, 2018 at 6:37

3 Answers 3

2

The test scanner in setuptools will look for tests in any *.py file found in your sub-directories, except for __init__.py. Yes, this includes __main__.py, it will call __import__() on it, causing its main suite to be executed.

If you want to be able to run python -m addtest and have that run your __main__.py code, you may want to add the standard 'run only if this is really main' protection:

if __name__ == "__main__":
   ...

(then, if you do python -m the code will run, but it won't run if the file is loaded by setup.py test)

Sign up to request clarification or add additional context in comments.

Comments

1

The setuptools docs explains how setuptools scans for unit tests by default.

Since, as you say, no unit tests are written or specified, setuptools can be using default behavior.

A couple references from the setuptools docs that elaborates on this as well as specifies how to set up test suites are below:

  1. test_loader If you would like to use a different way of finding tests to run than what setuptools normally uses, you can specify a module name and class name in this argument.
    ...
    The module name and class name must be separated by a :. The default value of this argument is "setuptools.command.test:ScanningLoader". If you want to use the default unittest behavior, you can specify "unittest:TestLoader" as your test_loader argument instead. This will prevent automatic scanning of submodules and subpackages.

  2. ... test_suite A string naming a unittest.TestCase subclass (or a package or module containing one or more of them, or a method of such a subclass), or naming a function that can be called with no arguments and returns a unittest.TestSuite.

    If the named suite is a module, and the module has an additional_tests() function, it is called and the results are added to the tests to be run. If the named suite is a package, any submodules and subpackages are recursively added to the overall test suite.

    Specifying this argument enables use of the test command to run the specified test suite, e.g. via setup.py test. See the section on the test command below for more details.
    ...

         setup(
         # ...
         test_suite="my_package.tests.test_all"
     )

This, in conjunction with another answer on this thread leaves you with at least a couple of options to ensure that python setup.py test doesn't run the console script:

  1. Configure how setuptools looks for test suites.
  2. Add if __name__ == "__main__": around main()

Yet another option may be given by the unit testing library you're using. For example, Pytest has an integration guide for setuptools that replaces the test command with its own.


Regarding the sysargs

sys.argv is ['setup.py','test'] because you invoked python with the args setup.py test

4 Comments

Can you elaborate on "you haven't defined test()"? I'm struggling to find anything resembling this in the Setuptools docs. I was planning to use Py.test rather than the unittest module, and I think they have some configuration tips for this scenario.
@detly typo, sorry. I meant you hadn't defined additional_tests() - but I was looking at your question as I wrote it. Editing answer now with the additional reference
Thanks for the clarification. Re. sysargs confusion: for some reason I figured the "main" script had been invoked as a subprocess, I couldn't figure out why else main() would be called. Now I see that it was imported, which ran the unguarded main() and, as you say, sysargs is trivially going to be what it is.
Hope you don't mind, I added a third option that is what I actually went with. However, I'm using Pytest, which I didn't mention in the question — so it may not be applicable to everyone who reads this, but I expect it might help a lot of folk who are wondering the same thing.
0

I think you have to specify the entry point for test in your setup.py. Otherwise it passes it to the main.py.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.