Skip to content

Commit

Permalink
implement and document new invocation mechanisms, see doc/usage.txt
Browse files Browse the repository at this point in the history
also rename pytest._core to pytest.main for convenience.
  • Loading branch information
hpk42 committed Nov 5, 2010
1 parent 6a734ef commit d108235
Show file tree
Hide file tree
Showing 22 changed files with 228 additions and 106 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ Changes between 1.3.4 and 2.0.0dev0
----------------------------------------------

- pytest-2.0 is now its own package and depends on pylib-2.0
- new ability: python -m pytest / python -m pytest.main ability
- new python invcation: pytest.main(args, plugins) to load
some custom plugins early.
- try harder to run unittest test suites in a more compatible manner
by deferring setup/teardown semantics to the unittest package.
- introduce a new way to set config options via ini-style files,
Expand Down
1 change: 1 addition & 0 deletions doc/apiref.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
py.test reference documentation
================================================


.. toctree::
:maxdepth: 2

Expand Down
28 changes: 13 additions & 15 deletions doc/builtin.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@

pytest builtin helpers
py.test builtin helpers
================================================

builtin py.test.* helpers
-----------------------------------------------------

You can always use an interactive Python prompt and type::

import pytest
help(pytest)

to get an overview on available globally available helpers.

.. automodule:: pytest
:members:

builtin function arguments
-----------------------------------------------------
Expand Down Expand Up @@ -54,17 +66,3 @@ You can ask for available builtin or project-custom
* ``pop(category=None)``: return last warning matching the category.
* ``clear()``: clear list of warnings


builtin py.test.* helpers
-----------------------------------------------------

You can always use an interactive Python prompt and type::

import pytest
help(pytest)

to get an overview on available globally available helpers.

.. automodule:: pytest
:members:

6 changes: 3 additions & 3 deletions doc/customize.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ builtin configuration file options
.. confval:: norecursedirs

Set the directory basename patterns to avoid when recursing
for test discovery. The individual (fnmatch-style) patterns are
applied to the basename of a directory to decide if to recurse into it.
for test discovery. The individual (fnmatch-style) patterns are
applied to the basename of a directory to decide if to recurse into it.
Pattern matching characters::

* matches everything
Expand All @@ -68,7 +68,7 @@ builtin configuration file options
[!seq] matches any char not in seq

Default patterns are ``.* _* CVS {args}``. Setting a ``norecurse``
replaces the default. Here is a customizing example for avoiding
replaces the default. Here is a customizing example for avoiding
a different set of directories::

# content of setup.cfg
Expand Down
6 changes: 3 additions & 3 deletions doc/features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ no-boilerplate testing with Python
----------------------------------

- automatic, fully customizable Python test discovery
- :pep:`8` consistent testing style
- allows simple test functions
- allows fully :pep:`8` compliant coding style
- write simple test functions and freely group tests
- ``assert`` statement for your assertions
- powerful parametrization of test functions
- rely on powerful traceback and assertion reporting
Expand All @@ -25,8 +25,8 @@ extensive plugin and customization system
mature command line testing tool
--------------------------------------

- powerful :ref:`usage` possibilities
- used in many projects, ranging from 10 to 10K tests
- autodiscovery of tests
- simple well sorted command line options
- runs on Unix, Windows from Python 2.4 up to Python 3.1 and 3.2
- is itself tested extensively on a CI server
Expand Down
17 changes: 11 additions & 6 deletions doc/goodpractises.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,21 @@ You can always run your tests by pointing to it::
...

.. _`package name`:
.. note::

.. note::

Test modules are imported under their fully qualified name as follows:

* ``basedir`` = first upward directory not containing an ``__init__.py``
* find ``basedir`` -- this is the first "upward" directory not
containing an ``__init__.py``

* perform ``sys.path.insert(0, basedir)``.
* perform ``sys.path.insert(0, basedir)`` to make the fully
qualified test module path importable.

* ``import path.to.test_module``
* ``import path.to.test_module`` where the path is determined
by converting path separators into "." files. This means
you must follow the convention of having directory and file
names map to the import names.

.. _standalone:
.. _`genscript method`:
Expand All @@ -94,7 +99,7 @@ Generating a py.test standalone Script
-------------------------------------------

If you are a maintainer or application developer and want others
to easily run tests you can generate a completely standalone "py.test"
to easily run tests you can generate a completely standalone "py.test"
script::

py.test --genscript=runtests.py
Expand Down
9 changes: 6 additions & 3 deletions doc/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ py.test: no-boilerplate testing with Python

.. todolist::


.. note::
version 2.0 introduces ``pytest`` as the main Python import name
but for historic reasons ``py.test`` remains fully valid and
represents the same package.

Welcome to ``py.test`` documentation:

.. toctree::
.. toctree::
:maxdepth: 2

overview
Expand All @@ -27,4 +31,3 @@ Indices and tables
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

2 changes: 1 addition & 1 deletion doc/overview.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Overview and Introduction

features.txt
getting-started.txt
cmdline.txt
usage.txt
goodpractises.txt
faq.txt

2 changes: 1 addition & 1 deletion doc/test/plugin/cov.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ However easy_install does not provide an uninstall facility.

.. IMPORTANT::

Ensure that you manually delete the init_cov_core.pth file in your site-packages directory.
Ensure that you manually delete the init_covmain.pth file in your site-packages directory.

This file starts coverage collection of subprocesses if appropriate during site initialisation
at python startup.
Expand Down
62 changes: 58 additions & 4 deletions doc/cmdline.txt → doc/usage.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@

.. _cmdline:
.. _usage:

Usage and Invocations
==========================================

Using the interactive command line
===============================================

.. _cmdline:

Getting help on version, option names, environment vars
-----------------------------------------------------------
Expand All @@ -22,6 +25,57 @@ To stop the testing process after the first (N) failures::
py.test -x # stop after first failure
py.test -maxfail=2 # stop after two failures

calling pytest from Python code
----------------------------------------------------

.. versionadded: 2.0

You can invoke ``py.test`` from Python code directly::

pytest.main()

this acts as if you would call "py.test" from the command line.
It will not raise ``SystemExit`` but return the exitcode instead.
You can pass in options and arguments::

pytest.main(['x', 'mytestdir'])

or pass in a string::

pytest.main("-x mytestdir")

You can specify additional plugins to ``pytest.main``::

# content of myinvoke.py
import pytest
class MyPlugin:
def pytest_addoption(self, parser):
raise pytest.UsageError("hi from our plugin")

pytest.main(plugins=[MyPlugin()])

Running it will exit quickly::

$ python myinvoke.py
ERROR: hi from our plugin

calling pytest through ``python -m pytest``
-----------------------------------------------------

.. versionadded: 2.0

You can invoke testing through the Python interpreter from the command line::

python -m pytest.main [...]

Python2.7 and Python3 introduced specifying packages to "-m" so there
you can also type::

python -m pytest [...]

All of these invocations are equivalent to the ``py.test [...]`` command line invocation.


Modifying Python traceback printing
----------------------------------------------

Expand All @@ -40,7 +94,7 @@ Dropping to PDB (Python Debugger) on failures

.. _PDB: http://docs.python.org/library/pdb.html

Python comes with a builtin Python debugger called PDB_. ``py.test``
Python comes with a builtin Python debugger called PDB_. ``py.test``
allows to drop into the PDB prompt via a command line option::

py.test --pdb
Expand Down
6 changes: 2 additions & 4 deletions pytest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

__all__ = ['config', 'cmdline']

from pytest import _core as cmdline
from pytest import main as cmdline
UsageError = cmdline.UsageError

def __main__():
raise SystemExit(cmdline.main())
main = cmdline.main
4 changes: 4 additions & 0 deletions pytest/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import pytest

if __name__ == '__main__':
raise SystemExit(pytest.main())
2 changes: 1 addition & 1 deletion pytest/hookspec.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" hook specifications for pytest plugins, invoked from _core.py and builtin plugins. """
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """

# -------------------------------------------------------------------------
# Initialization
Expand Down
29 changes: 22 additions & 7 deletions pytest/_core.py → pytest/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"""
pytest PluginManager, basic initialization and tracing.
All else is in pytest/plugin.
(c) Holger Krekel 2004-2010
"""
import sys, os
import inspect
import py
from pytest import hookspec
from pytest import hookspec # the extension point definitions

assert py.__version__.split(".")[:2] >= ['2', '0'], ("installation problem: "
"%s is too old, remove or upgrade 'py'" % (py.__version__))
Expand Down Expand Up @@ -375,23 +380,33 @@ def pcall(self, plugins, **kwargs):
mc = MultiCall(methods, kwargs, firstresult=self.firstresult)
return mc.execute()

pluginmanager = PluginManager(load=True) # will trigger default plugin importing
_preinit = [PluginManager(load=True)] # triggers default plugin importing

def main(args=None):
global pluginmanager
def main(args=None, plugins=None):
if args is None:
args = sys.argv[1:]
hook = pluginmanager.hook
elif not isinstance(args, (tuple, list)):
args = py.std.shlex.split(str(args))
if _preinit:
_pluginmanager = _preinit.pop(0)
else: # subsequent calls to main will create a fresh instance
_pluginmanager = PluginManager(load=True)
hook = _pluginmanager.hook
try:
if plugins:
for plugin in plugins:
_pluginmanager.register(plugin)
config = hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args)
pluginmanager=_pluginmanager, args=args)
exitstatus = hook.pytest_cmdline_main(config=config)
except UsageError:
e = sys.exc_info()[1]
sys.stderr.write("ERROR: %s\n" %(e.args[0],))
exitstatus = 3
pluginmanager = PluginManager(load=True)
return exitstatus

class UsageError(Exception):
""" error in py.test usage or invocation"""

if __name__ == '__main__':
raise SystemExit(main())
2 changes: 1 addition & 1 deletion pytest/plugin/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import py
import sys, os
from pytest._core import PluginManager
from pytest.main import PluginManager
import pytest


Expand Down
8 changes: 6 additions & 2 deletions pytest/plugin/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
funcargs and support code for testing py.test's own functionality.
"""

import py
import py, pytest
import sys, os
import re
import inspect
import time
from fnmatch import fnmatch
from pytest.plugin.session import Collection
from py.builtin import print_
from pytest._core import HookRelay
from pytest.main import HookRelay

def pytest_addoption(parser):
group = parser.getgroup("pylib")
Expand Down Expand Up @@ -401,6 +401,10 @@ def popen(self, cmdargs, stdout, stderr, **kw):
#print "env", env
return py.std.subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw)

def pytestmain(self, *args, **kwargs):
ret = pytest.main(*args, **kwargs)
if ret == 2:
raise KeyboardInterrupt()
def run(self, *cmdargs):
return self._run(*cmdargs)

Expand Down
2 changes: 1 addition & 1 deletion pytest/plugin/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ def hasinit(obj):


def getfuncargnames(function):
# XXX merge with _core.py's varnames
# XXX merge with main.py's varnames
argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0]
startindex = py.std.inspect.ismethod(function) and 1 or 0
defaults = getattr(function, 'func_defaults',
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def main():
)

def cmdline_entrypoints(versioninfo, platform, basename):
target = 'pytest:__main__'
target = 'pytest:main'
if platform.startswith('java'):
points = {'py.test-jython': target}
else:
Expand All @@ -66,4 +66,4 @@ def make_entry_points():
return {'console_scripts': l}

if __name__ == '__main__':
main()
main()
Loading

0 comments on commit d108235

Please sign in to comment.