././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0394313 nose2-0.12.0/0000775002342000234200000000000014264564615012621 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/AUTHORS0000664002342000234200000000021114176405443013656 0ustar00sirosensirosenJason Pellerin Augie Fackler Arve Knudsen Wouter Overmeire Omer Katz Ilya Kurnosov Philip Thiem Aloys Baillet Stephen Rosen Stefan Holek ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1647581698.0 nose2-0.12.0/MANIFEST.in0000664002342000234200000000047214215015002014333 0ustar00sirosensiroseninclude AUTHORS include tox.ini include unittest.cfg include README.rst include license.txt recursive-include nose2/tests/functional/support *.py *.txt *.cfg *.rst *.json *.egg .coveragerc recursive-include docs *.inc *.py *.rst Makefile graft bin global-exclude __pycache__ global-exclude *~ global-exclude *.pyc ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0394313 nose2-0.12.0/PKG-INFO0000664002342000234200000001446114264564615013724 0ustar00sirosensirosenMetadata-Version: 2.1 Name: nose2 Version: 0.12.0 Summary: unittest2 with plugins, the successor to nose Home-page: https://github.com/nose-devs/nose2 Maintainer: Stephen Rosen Maintainer-email: dev@nose2.io Keywords: unittest,testing,tests Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Operating System :: OS Independent Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Testing Provides-Extra: coverage_plugin Provides-Extra: dev License-File: AUTHORS .. image:: https://results.pre-commit.ci/badge/github/nose-devs/nose2/main.svg :target: https://results.pre-commit.ci/latest/github/nose-devs/nose2/main :alt: pre-commit.ci status .. image:: https://github.com/nose-devs/nose2/workflows/build/badge.svg?event=push :alt: build status :target: https://github.com/nose-devs/nose2/actions?query=workflow%3Abuild .. image:: https://readthedocs.org/projects/nose2/badge/ :target: https://nose2.io/ :alt: Documentation .. image:: https://img.shields.io/pypi/v/nose2.svg :target: https://pypi.org/project/nose2/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/pyversions/nose2.svg :alt: Supported Python Versions :target: https://pypi.org/project/nose2/ .. image:: https://img.shields.io/badge/Mailing%20list-discuss%40nose2.io-blue.svg :target: https://groups.google.com/a/nose2.io/forum/#!forum/discuss :alt: Join discuss@nose2.io Welcome to nose2 ================ ``nose2`` is the successor to ``nose``. It's ``unittest`` with plugins. ``nose2`` is a new project and does not support all of the features of ``nose``. See `differences`_ for a thorough rundown. nose2's purpose is to extend ``unittest`` to make testing nicer and easier to understand. nose2 vs pytest --------------- ``nose2`` may or may not be a good fit for your project. If you are new to Python testing, we encourage you to also consider `pytest`_, a popular testing framework. Quickstart ---------- Because ``nose2`` is based on unittest, you can start from the Python Standard Library's `documentation for unittest `_ and then use nose2 to add value on top of that. ``nose2`` looks for tests in Python files whose names start with ``test`` and runs every test function it discovers. Here's an example of a simple test, written in typical unittest style: .. code-block:: python # in test_simple.py import unittest class TestStrings(unittest.TestCase): def test_upper(self): self.assertEqual("spam".upper(), "SPAM") You can then run this test like so:: $ nose2 -v test_upper (test_simple.TestStrings) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK However, ``nose2`` supports more testing configuration and provides more tools than ``unittest`` on its own. For example, this test exercises just a few of ``nose2``'s features: .. code-block:: python # in test_fancy.py from nose2.tools import params @params("Sir Bedevere", "Miss Islington", "Duck") def test_is_knight(value): assert value.startswith('Sir') and then run this like so:: $ nose2 -v --pretty-assert test_fancy.test_is_knight:1 'Sir Bedevere' ... ok test_fancy.test_is_knight:2 'Miss Islington' ... FAIL test_fancy.test_is_knight:3 'Duck' ... FAIL ====================================================================== FAIL: test_fancy.test_is_knight:2 'Miss Islington' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Miss Islington' value.startswith = ====================================================================== FAIL: test_fancy.test_is_knight:3 'Duck' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Duck' value.startswith = ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (failures=2) Full Docs --------- Full documentation for ``nose2`` is available at `docs.nose2.io`_ Versions and Support -------------------- Changelog and Version Scheme ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nose2 versions are numbered `0.MAJOR.MINOR`. Minor releases contain bugfixes or smaller features. Major features or backwards incompatible changes are done in major releases. For a full description of all past versions and changes, see the `changelog`_. Python Versions ~~~~~~~~~~~~~~~ nose2 supports all currently supported Python versions. It also will continue to support Python 2 for as long as it remains feasible and a significant percentage of nose2 users are using Python 2. Contributing ------------ If you want to make contributions, please read the `contributing`_ guide. .. _differences: https://docs.nose2.io/en/latest/differences.html .. _changelog: https://docs.nose2.io/en/latest/changelog.html .. _pytest: http://pytest.readthedocs.io/en/latest/ .. _contributing: https://github.com/nose-devs/nose2/blob/main/contributing.rst .. _docs.nose2.io: https://docs.nose2.io/en/latest/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/README.rst0000664002342000234200000001217714264464446014321 0ustar00sirosensirosen.. image:: https://results.pre-commit.ci/badge/github/nose-devs/nose2/main.svg :target: https://results.pre-commit.ci/latest/github/nose-devs/nose2/main :alt: pre-commit.ci status .. image:: https://github.com/nose-devs/nose2/workflows/build/badge.svg?event=push :alt: build status :target: https://github.com/nose-devs/nose2/actions?query=workflow%3Abuild .. image:: https://readthedocs.org/projects/nose2/badge/ :target: https://nose2.io/ :alt: Documentation .. image:: https://img.shields.io/pypi/v/nose2.svg :target: https://pypi.org/project/nose2/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/pyversions/nose2.svg :alt: Supported Python Versions :target: https://pypi.org/project/nose2/ .. image:: https://img.shields.io/badge/Mailing%20list-discuss%40nose2.io-blue.svg :target: https://groups.google.com/a/nose2.io/forum/#!forum/discuss :alt: Join discuss@nose2.io Welcome to nose2 ================ ``nose2`` is the successor to ``nose``. It's ``unittest`` with plugins. ``nose2`` is a new project and does not support all of the features of ``nose``. See `differences`_ for a thorough rundown. nose2's purpose is to extend ``unittest`` to make testing nicer and easier to understand. nose2 vs pytest --------------- ``nose2`` may or may not be a good fit for your project. If you are new to Python testing, we encourage you to also consider `pytest`_, a popular testing framework. Quickstart ---------- Because ``nose2`` is based on unittest, you can start from the Python Standard Library's `documentation for unittest `_ and then use nose2 to add value on top of that. ``nose2`` looks for tests in Python files whose names start with ``test`` and runs every test function it discovers. Here's an example of a simple test, written in typical unittest style: .. code-block:: python # in test_simple.py import unittest class TestStrings(unittest.TestCase): def test_upper(self): self.assertEqual("spam".upper(), "SPAM") You can then run this test like so:: $ nose2 -v test_upper (test_simple.TestStrings) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK However, ``nose2`` supports more testing configuration and provides more tools than ``unittest`` on its own. For example, this test exercises just a few of ``nose2``'s features: .. code-block:: python # in test_fancy.py from nose2.tools import params @params("Sir Bedevere", "Miss Islington", "Duck") def test_is_knight(value): assert value.startswith('Sir') and then run this like so:: $ nose2 -v --pretty-assert test_fancy.test_is_knight:1 'Sir Bedevere' ... ok test_fancy.test_is_knight:2 'Miss Islington' ... FAIL test_fancy.test_is_knight:3 'Duck' ... FAIL ====================================================================== FAIL: test_fancy.test_is_knight:2 'Miss Islington' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Miss Islington' value.startswith = ====================================================================== FAIL: test_fancy.test_is_knight:3 'Duck' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Duck' value.startswith = ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (failures=2) Full Docs --------- Full documentation for ``nose2`` is available at `docs.nose2.io`_ Versions and Support -------------------- Changelog and Version Scheme ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nose2 versions are numbered `0.MAJOR.MINOR`. Minor releases contain bugfixes or smaller features. Major features or backwards incompatible changes are done in major releases. For a full description of all past versions and changes, see the `changelog`_. Python Versions ~~~~~~~~~~~~~~~ nose2 supports all currently supported Python versions. It also will continue to support Python 2 for as long as it remains feasible and a significant percentage of nose2 users are using Python 2. Contributing ------------ If you want to make contributions, please read the `contributing`_ guide. .. _differences: https://docs.nose2.io/en/latest/differences.html .. _changelog: https://docs.nose2.io/en/latest/changelog.html .. _pytest: http://pytest.readthedocs.io/en/latest/ .. _contributing: https://github.com/nose-devs/nose2/blob/main/contributing.rst .. _docs.nose2.io: https://docs.nose2.io/en/latest/ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9834316 nose2-0.12.0/docs/0000775002342000234200000000000014264564615013551 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/Makefile0000664002342000234200000001075213365700060015201 0ustar00sirosensirosen# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nose2.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nose2.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/nose2" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nose2" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989444.0 nose2-0.12.0/docs/changelog.rst0000664002342000234200000003247014264564504016235 0ustar00sirosensirosenChangelog ========= nose2 uses semantic versioning (currently in 0.x) and the popular "keep a changelog" format (v1.0.0). nose2 tries not to break backwards compatibility in any release. Until v1.0, versions are numbered `0.MAJOR.MINOR`. Major releases introduce new functionality or contain necessary breaking changes. Minor releases are primarily used for bugfix or small features which are unlikely to break users' testsuites. 0.12.0 (2022-07-16) ------------------- .. note:: The 0.12.x series will be the final releases of ``nose2`` which support Python 2. Changed ~~~~~~~ * Passing ``--junit-xml-path`` now implies ``--junit-xml`` when using the junitxml plugin. This means that the ``--junit-xml`` flag can be omitted when ``--junit-xml-path`` is specified. (:issue:`521`) * Remove the dependency on ``coverage``. Use of the coverage plugin now requires that you either install ``coverage`` independently, or use the extra, ``nose2[coverage_plugin]``. As a result, ``nose2`` no longer has any strict dependencies * Remove the dependency on ``six``, instead using a vendored copy. This ensures that the dependency for ``nose2`` doesn't conflict with application dependencies Removed ~~~~~~~ * ``nose2`` no longer provides an entry-point named based on the current python version, e.g. ``nose2-3.8`` on python3.8 . Only the ``nose2`` command is provided. * Remove support for ``setup.py test`` on ``nose2`` itself. This usage is deprecated by setuptools. Developers contributing to ``nose2`` are encouraged to use ``tox`` to run ``nose2``'s testsuite, per the contributing guide. 0.11.0 (2022-02-12) ------------------- This is the first version of `nose2` using `sphinx-issues` to credit contributors in the changelog. Added ~~~~~ * Test classes now have their short description (first line of docstring) printed in verbose output * The junitxml plugin now sets ``timestamp`` on each ``testcase`` node as an ISO-8601 timestamp. Thanks to :user:`deeplow` for the contribution! Changed ~~~~~~~ * Drop support for Python 3.5 * Python 3.10 is now officially supported. Python 3.11-dev will be supported on a best-effort basis. Thanks to :user:`hugovk` and :user:`tirkarthi` for their contributions! * ``nose2`` source code is now autoformatted with ``black`` and ``isort`` * ``nose2`` has switched its main development branch from ``master`` to ``main`` * Releases are now published using `build `_ Fixed ~~~~~ * Add support for test classes when running with the multiprocessing plugin. Thanks to :user:`ltfish` for the initial contribution and :user:`stefanholek` for the refinement to this change! * Various documentation fixes 0.10.0 (2021-01-27) ------------------- Added ~~~~~ * Support for subtests! Notes for plugin authors about subtest support: * Subtest failures will produce a ``TestOutcomeEvent`` with ``outcome = "subtest"`` * Subtest events can be failures, but they do not indicate success -- the containing test will send a success event if no subtests fail Changed ~~~~~~~ * Drop support for Python 3.4 * Python 3.8 and 3.9 are now officially supported * Improve helptext for the multiprocess plugin's ``-N`` option * When run with reduced verbosity (e.g. with ``-q``), ``nose2`` will no longer print an empty line before test reports Fixed ~~~~~ * The plugin registry will no longer contain duplicate plugins and or base ``event.Plugin`` instances * Fix function test case implementation of ``id``, ``__str__``, and ``__repr__``. This removes the injected ``transplant_class.`` from reporting output * Doctest loading will now skip ``setup.py`` files in the project root * Class methods decorated (e.g. with ``mock.patch``) are no longer incorrectly picked up by the function loader 0.9.2 (2020-02-02) ------------------ Added ~~~~~ * Add ``--junit-xml-path`` to the junit plugin argument list Fixed ~~~~~ * It is now possible to use the multiprocess and coverage plugins together, as long as all of the coverage config is put into the config file * Minor changes to be compatible with newer pythons (3.8, 3.9) 0.9.1 (2019-04-02) ------------------ Changed ~~~~~~~ * the prof plugin now uses ``cProfile`` instead of ``hotshot`` for profiling, and therefore now supports python versions which do not include ``hotshot`` * skipped tests now include the user's reason in junit XML's ``message`` field Fixed ~~~~~ * the prettyassert plugin mishandled multi-line function definitions * Using a plugin's CLI flag when the plugin is already enabled via config no longer errors -- it is a no-op instead 0.9.0 (2019-03-17) ------------------ Added ~~~~~ * nose2.plugins.prettyassert, enabled with ``--pretty-assert``, which pretty-prints AssertionErrors generated by ``assert`` statements Changed ~~~~~~~ * Update trove classifier to "beta" from "alpha" status * Cleanup code for EOLed python versions Removed ~~~~~~~ * Dropped support for ``distutils``. Installation now requires ``setuptools`` Fixed ~~~~~ * Result reporter respects failure status set by other plugins * JUnit XML plugin now includes the skip reason in its output 0.8.0 (2018-07-31) ------------------ Added ~~~~~ * Add code to enable plugins to documentation Removed ~~~~~~~ * Dropped support for python 3.3 Fixed ~~~~~ * For junitxml plugin use test module in place of classname if no classname exists 0.7.4 (2018-02-17) ------------------ Added ~~~~~ * Setup tools invocation now handles coverage Changed ~~~~~~~ * Running ``nose2`` via ``setuptools`` will now trigger ``CreateTestsEvent`` and ``CreatedTestSuiteEvent`` Fixed ~~~~~ * Respect ``fail_under`` in converage config * Avoid infinite recursion when loading setuptools from zipped egg * Manpage now renders reproducibly * MP doc build now reproducible 0.7.3 (2017-12-13) ------------------ Added ~~~~~ * support for python 3.6. Fixed ~~~~~ * Tests failing due to .coveragerc not in MANIFEST 0.7.2 (2017-11-14) ------------------ Includes changes from version ``0.7.1``, never released. Fixed ~~~~~ * Proper indentation of test with docstring in layers * MP plugin now calls startSubprocess in subprocess Changed ~~~~~~~ * Add Makefile to enable "quickstart" workflow * Removed bootstrap.sh and test.sh Fixed ~~~~~ * Automatically create .coverage file during coverage reporting * Better handling of import failures 0.7.0 (2017-11-05) ------------------ Note: v0.7.0 drops several unsupported python versions Added ~~~~~ * Add layer fixture events and hooks * junit-xml: add logs in "system-out" * Give full exc_info to loader.failedLoadTests Changed ~~~~~~~ * Replace cov-core with coverage in the coverage plugin * Give better error when cannot import a testname * Better errors when tests fail to load * Allow combination of MP and OutputBuffer plugins on Python 3 Removed ~~~~~~~ * Dropped unsupported Python 2.6, 3.2, 3.3 * ``nose2.compat`` is removed because it is no longer needed. If you have ``from nose2.compat import unittest`` in your code, you will need to replace it with ``import unittest``. Fixed ~~~~~ * Prevent crashing from UnicodeDecodeError * Fix unicode stream encoding 0.6.5 (2016-06-29) ------------------ Added ~~~~~ * Add `nose2.__version__` 0.6.4 (2016-03-15) ------------------ Fixed ~~~~~ * MP will never spawn more processes than there are tests. e.g. When running only one test, only one process is spawned 0.6.3 (2016-03-01) ------------------ Changed ~~~~~~~ * Add support for python 3.4, 3.5 0.6.2 (2016-02-24) ------------------ Fixed ~~~~~ * fix the coverage plugin tests for coverage==3.7.1 0.6.1 (2016-02-23) ------------------ Fixed ~~~~~ * missing test files added to package. 0.6.0 (2016-02-21) ------------------ Added ~~~~~ * Junit XML report support properties * Add a `createdTestSuite` event, fired after test loading Changed ~~~~~~~ * Improve test coverage * Improve CI * When test loading fails, print the traceback Fixed ~~~~~ * Junit-xml plugin fixed on windows * Ensure tests are importable before trying to load them * Fail test instead of skipping it, when setup fails * Make the ``collect`` plugin work with layers * Fix coverage plugin to take import-time coverage into account 0.5.0 (2014-09-14) ------------------ Added ~~~~~ * with_setup and with_teardown decorators to set the setup & teardown on a function * dundertests plugin to skip tests with `__test__ == False` * `cartesian_params` decorator * coverage plugin * EggDiscoveryLoader for discovering tests within Eggs * Support `params` with `such` * Include logging output in junit XML Changed ~~~~~~~ * `such` errors early if Layers plugin is not loaded * Allow use of `nose2.main()` from within a test module Fixed ~~~~~ * Such DSL ignores two `such.A` with the same description * Record skipped tests as 'skipped' instead of 'skips' * Result output failed on unicode characters * Fix multiprocessing plugin on Windows * Ensure plugins write to the event stream * multiprocessing could lock master proc and fail to exit * junit report path was sensitive to changes in cwd * Test runs would crash if a TestCase `__init__` threw an exception * Plugin failures no longer crash the whole test run * Handle errors in test setup and teardown * Fix reporting of xfail tests * Log capture was waiting too long to render mutable objects to strings * Layers plugin was not running testSetUp/testTearDown from higher `such` layers 0.4.7 (2013-08-13) ------------------ Added ~~~~~ * start-dir config option. Thanks to Stéphane Klein. * Help text for verbose flag. Thanks to Tim Sampson. * Added badges to README. Thanks to Omer Katz. Changed ~~~~~~~ * Updated six version requirement to be less Restrictive. Thanks to Stéphane Klein. * Cleaned up numerous PEP8 violations. Thanks to Omer Katz. Fixed ~~~~~ * Fixed broken import in collector.py. Thanks to Shaun Crampton. * Fixed processes command line option in mp plugin. Thanks to Tim Sampson. * Fixed handling of class fixtures in multiprocess plugin. Thanks to Tim Sampson. * Fixed intermittent test failure caused by nondeterministic key ordering. Thanks to Stéphane Klein. * Fixed syntax error in printhooks. Thanks to Tim Sampson. * Fixed formatting in changelog. Thanks to Omer Katz. * Fixed typos in docs and examples. Thanks to Tim Sampson. 0.4.6 (2013-04-07) ------------------ Changed ~~~~~~~ * Docs note support for python 3.3. Thanks Omer Katz for the bug report. Fixed ~~~~~ * Fixed DeprecationWarning for compiler package on python 2.7. Thanks Max Arnold. * Fixed lack of timing information in junitxml exception reports. Thanks Viacheslav Dukalskiy. * Cleaned up junitxml xml output. Thanks Philip Thiem. 0.4.5 (2012-12-16) ------------------ Fixed ~~~~~ * Fixed broken interaction between attrib and layers plugins. They can now be used together. Thanks @fajpunk. * Fixed incorrect calling order of layer setup/teardown and test setup/test teardown methods. Thanks again @fajpunk for tests and fixes. 0.4.4 (2012-11-26) ------------------ Fixed ~~~~~ * Fixed sort key generation for layers. 0.4.3 (2012-11-21) ------------------ Fixed ~~~~~ * Fixed packaging for non-setuptools, pre-python 2.7. Thanks to fajpunk for the patch. 0.4.2 (2012-11-19) ------------------ Added ~~~~~ * Added ``uses`` method to ``such.Scenario`` to allow use of externally-defined layers in such DSL tests. Fixed ~~~~~ * Fixed unpredictable ordering of layer tests. 0.4.1 (2012-06-18) ------------------ Includes changes from version ``0.4``, never released. Fixed ~~~~~ * Fixed packaging bug. Added ~~~~~ * nose2.plugins.layers to support Zope testing style fixture layers. * nose2.tools.such, a spec-like DSL for writing tests with layers. * nose2.plugins.loader.loadtests to support the unittest2 load_tests protocol. 0.3 (2012-04-15) ---------------- Added ~~~~~ * nose2.plugins.mp to support distributing test runs across multiple processes. * nose2.plugins.testclasses to support loading tests from ordinary classes that are not subclasses of unittest.TestCase. * ``nose2.main.PluggableTestProgram`` now accepts an ``extraHooks`` keyword argument, which allows attaching arbitrary objects to the hooks system. Changed ~~~~~~~ * The default script target was changed from ``nose2.main`` to ``nose2.discover``. The former may still be used for running a single module of tests, unittest-style. The latter ignores the ``module`` argument. Thanks to @dtcaciuc for the bug report (#32). Fixed ~~~~~ * Fixed bug that caused Skip reason to always be set to ``None``. 0.2 (2012-02-06) ---------------- Added ~~~~~ * nose2.plugins.junitxml to support jUnit XML output * nose2.plugins.attrib to support test filtering by attributes Changed ~~~~~~~ * Added afterTestRun hook and moved result report output calls to that hook. This prevents plugin ordering issues with the stopTestRun hook (which still exists, and fires before afterTestRun). Fixed ~~~~~ * Fixed bug in loading of tests by name that caused ImportErrors to be silently ignored. * Fixed missing __unittest flag in several modules. Thanks to Wouter Overmeire for the patch. * Fixed module fixture calls for function, generator and param tests. * Fixed passing of command-line argument values to list options. Before this fix, lists of lists would be appended to the option target. Now, the option target list is extended with the new values. Thanks to memedough for the bug report. 0.1 (2012-01-19) ---------------- Initial release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1644711876.0 nose2-0.12.0/docs/conf.py0000664002342000234200000000145414202047704015037 0ustar00sirosensirosenimport os import sys sys.path.insert(0, os.path.abspath("..")) import nose2 # noqa:E402 extensions = [ "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx.ext.coverage", "sphinx.ext.ifconfig", "sphinx.ext.viewcode", "sphinx_issues", "nose2.sphinxext", ] source_suffix = ".rst" master_doc = "index" project = "nose2" copyright = "2010-2022, Jason Pellerin, Stephen Rosen" version = release = nose2._version.__version__ exclude_patterns = ["_build"] templates_path = ["_templates"] # theme html_theme = "sphinx_rtd_theme" # sphinx-issues github_user = "nose-devs" github_repo = "nose2" issues_github_path = f"{github_user}/{github_repo}" # intersphinx intersphinx_mapping = { "python": ("http://docs.python.org/", None), } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1644082647.0 nose2-0.12.0/docs/configuration.rst0000664002342000234200000001552314177532727017162 0ustar00sirosensirosenConfiguring nose2 ================= Configuration Files ------------------- nose2 can be configured via standard, ini-style config files. The default files are ``unittest.cfg`` and ``nose2.cfg`` in the start directory. The ini format has sections marked off by brackets ("``[unittest]``") and ``key = value`` pairs within those sections. When the value is a list, put each value into its own line with proper indentation :: key_expecting_list = value1 value2 Two command line options, :option:`-c` and :option:`--no-user-config` may be used to determine which config files are loaded. .. cmdoption :: -c CONFIG, --config CONFIG Config files to load. Default behavior is to look for ``unittest.cfg`` and ``nose2.cfg`` in the start directory, as well as any user config files (unless :option:`--no-user-config` is selected). .. cmdoption :: --no-user-config Do not load user config files. If not specified, in addition to the standard config files and any specified with :option:`-c`, nose2 will look for ``.unittest.cfg`` and ``.nose2.cfg`` in the user's $HOME directory. Configuring Test Discovery ~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``[unittest]`` section of nose2 config files is used to configure nose2 itself. The following options are available to configure test discovery: .. rst:configvar :: start-dir This option configures the default directory to start discovery. The default value is ``"."`` (the current directory where nose2 is executed). This directory is where nose2 will start looking for tests. .. rst:configvar :: code-directories This option configures nose2 to add the named directories to sys.path and the discovery path. Use this if your project has code in a location other than the top level of the project, or the directories ``lib`` or ``src``. The value here may be a list: put each directory on its own line in the config file. .. rst:configvar :: test-file-pattern This option configures how nose detects test modules. It is a file glob. .. rst:configvar :: test-method-prefix This option configures how nose detects test functions and methods. The prefix set here will be matched (via simple string matching) against the start of the name of each method in test cases and each function in test modules. Examples: .. code-block :: ini [unittest] start-dir = tests code-directories = source more_source test-file-pattern = *_test.py test-method-prefix = t Specifying Plugins to Load ~~~~~~~~~~~~~~~~~~~~~~~~~~ To avoid loading any plugins, use the :option:`--no-plugins` option. Beware, though: nose2 does all test discovery and loading via plugins, so unless you are patching in a custom test loader and runner, when run with :option:`--no-plugins`, nose2 will do nothing. .. cmdoption :: --no-plugins Do not load any plugins. *This kills the nose2.* To specify plugins to load beyond the builtin plugins automatically loaded, add a :config:`plugins` entry under the ``[unittest]`` section in a config file. .. rst:configvar :: plugins List of plugins to load. Put one plugin module on each line. To exclude some plugins that would otherwise be loaded, add an :config:`exclude-plugins` entry under the ``[unittest]`` section in a config file. .. rst:configvar :: exclude-plugins List of plugins to exclude. Put one plugin module on each line. .. note :: It bears repeating that in both :config:`plugins` and :config:`exclude-plugins` entries, you specify the plugin *module*, not the plugin *class*. The module is specified by the (dot-separated) *fully qualified* name. Examples: .. code-block :: ini [unittest] plugins = myproject.plugins.frobulate otherproject.contrib.plugins.derper exclude-plugins = nose2.plugins.loader.functions nose2.plugins.outcomes Configuring Plugins ------------------- Most plugins specify a config file section that may be used to configure the plugin. If nothing else, any plugin that specifies a config file section can be set to automatically register by including ``always-on = True`` in its config: .. code-block :: ini [my-plugin] always-on = True Plugins may accept any number of other config values, which may be booleans, strings, integers or lists. A polite plugin will document these options somewhere. Plugins that want to make use of nose2's `Sphinx`_ extension as detailed in :doc:`dev/documenting_plugins` *must* extract all of their config values in their ``__init__`` methods. .. _Sphinx : http://sphinx.pocoo.org/ Test Runner Tips and Tweaks --------------------------- Running Tests in a Single Module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use ``nose2.main`` in the same way that ``unittest.main`` (and ``unittest2.main``) have historically worked: to run the tests in a single module. Just put a block like the following at the end of the module:: if __name__ == '__main__': import nose2 nose2.main() Then *run the module directly* -- In other words, do not run the ``nose2`` script. Rolling Your Own Runner ~~~~~~~~~~~~~~~~~~~~~~~ You can take more control over the test runner by foregoing the ``nose2`` script and rolling your own. To do that, you just need to write a script that calls ``nose2.discover``, for instance:: if __name__ == '__main__': import nose2 nose2.discover() You can pass several keyword arguments to ``nose2.discover``, all of which are detailed in the documentation for :class:`nose2.main.PluggableTestProgram`. Altering the Default Plugin Set ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To add plugin *modules* to the list of those automatically loaded, you can pass a list of module names to add (the ``plugins``) argument or exclude (``excludedPlugins``). You can also subclass :class:`nose2.main.PluggableTestProgram` and set the class-level ``defaultPlugins`` and ``excludePlugins`` attributes to alter plugin loading. When Loading Plugins from Modules is not Enough ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **None of which will help** if you need to register a plugin *instance* that you've loaded yourself. For that, use the ``extraHooks`` keyword argument to ``nose2.discover``. Here, you pass in a list of 2-tuples, each of which contains a hook name and a plugin *instance* to register for that hook. This allows you to register plugins that need runtime configuration that is not easily passed in through normal channels -- and also to register *objects that are not nose2 plugins* as hook targets. Here's a trivial example:: if __name__ == '__main__': import nose2 class Hello(object): def startTestRun(self, event): print("hello!") nose2.discover(extraHooks=[('startTestRun', Hello())]) This can come in handy when integrating with other systems that expect you to provide a test runner that they execute, rather than executing tests yourself (django, for instance). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/contents.rst.inc0000664002342000234200000000110413365700060016667 0ustar00sirosensirosenUser's Guide ============ .. toctree:: :maxdepth: 2 getting_started usage configuration differences plugins tools changelog Plugin Developer's Guide ======================== .. toctree :: :maxdepth: 2 dev/writing_plugins dev/documenting_plugins dev/event_reference dev/hook_reference dev/session_reference dev/plugin_class_reference Developer's Guide ================= .. toctree:: :maxdepth: 2 dev/contributing dev/internals Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/decorators.rst0000664002342000234200000000037313641442730016442 0ustar00sirosensirosen========== Decorators ========== nose2 ships with various decorators that assist you to write your tests. Setup & Teardown ================ .. autofunction :: nose2.tools.decorators.with_setup .. autofunction :: nose2.tools.decorators.with_teardown././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9834316 nose2-0.12.0/docs/dev/0000775002342000234200000000000014264564615014327 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/dev/contributing.rst0000664002342000234200000000347514176405443017574 0ustar00sirosensirosenContributing to nose2 ===================== Please do! nose2 cannot move forward without contributions from the testing community. If you're unsure how to get started, feel free to ask for help from the nose2 community via the `mailing list `_. The Basics ---------- nose2 is hosted on `github`_ and use GitHub for issue tracking. Please report issues and make feature requests here: https://github.com/nose-devs/nose2/issues Submit changes as GitHub Pull Requests. Code Contributions ------------------ The main rule is: *code changes should include tests.* If you aren't sure how to add tests, or you don't know why existing tests fail on your changes, that's okay! Submit your patch and ask for help testing it. Local Dev Requirements ++++++++++++++++++++++ To run the tests you must have `tox`_ installed. Optional but useful tools include ``make`` and `pre-commit`_. Running Tests +++++++++++++ To run all tests: :: $ tox To run linting checks: :: $ tox -e lint You can also use ``make test`` and ``make lint`` for these. Linting +++++++ nose2 uses `black`_, `isort`_, and `flake8`_ to enforce linting and code style rules, and `pre-commit`_ to run these tools. For the best development experience, we recommend setting up integrations with your editor and git. Running ``pre-commit`` as a git hook is optional. To configure it, you must have ``pre-commit`` installed and run: .. code-block:: bash $ pre-commit install .. note:: If you need to bypass pre-commit hooks after setting this up, you can commit with ``--no-verify`` .. _github: https://github.com/nose-devs/nose2 .. _tox: http://pypi.python.org/pypi/tox .. _black: https://black.readthedocs.io/ .. _isort: https://pycqa.github.io/isort/ .. _flake8: https://flake8.pycqa.org/ .. _pre-commit: https://pre-commit.com/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/documenting_plugins.rst0000664002342000234200000000244713365700060021130 0ustar00sirosensirosen=================== Documenting plugins =================== You should do it. Nobody will use your plugins if you don't. Or if they do use them, they will curse you whenever things go wrong. One easy way to document your plugins is to use nose2's `Sphinx`_ extension, which provides an ``autoplugin`` directive that will produce decent reference documentation from your plugin classes. To use it, add ``nose2.sphinxext`` to the ``extensions`` list in the ``conf.py`` file in your docs directory. Then add an ``autoplugin`` directive to a ``*.rst`` file, like this:: .. autoplugin :: mypackage.plugins.PluginClass This will produce output that includes the config vars your plugin loads in ``__init__``, as well as any command line options your plugin registers. This is why you *really* should extract config vars and register command-line options in ``__init__``. The output will also include an ``autoclass`` section for your plugin class, so you can put more narrative documentation in the plugin's docstring for users to read. Of course you can, and should, write some words before the reference docs explaining what your plugin does and how to use it. You can put those words in the ``*.rst`` file itself, or in the docstring of the module where your plugin lives. .. _Sphinx : http://sphinx.pocoo.org/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/event_reference.rst0000664002342000234200000000023613365700060020204 0ustar00sirosensirosenEvent reference =============== .. automodule :: nose2.events :members: :undoc-members: :exclude-members: Hook, Plugin, PluginInterface, PluginMeta ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/exceptions.rst0000664002342000234200000000014313365700060017223 0ustar00sirosensirosen================ nose2.exceptions ================ .. automodule :: nose2.exceptions :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/dev/hook_reference.rst0000664002342000234200000004246214176405443020042 0ustar00sirosensirosenHook reference ============== .. note :: Hooks are listed here in order of execution. Pre-registration Hooks ---------------------- .. function :: pluginsLoaded(self, event) :param event: :class:`nose2.events.PluginsLoadedEvent` The ``pluginsLoaded`` hook is called after all config files have been read, and all plugin classes loaded. Plugins that register automatically (those that call :meth:`nose2.events.Plugin.register` in ``__init__`` or have ``always-on = True`` set in their config file sections) will have already been registered with the hooks they implement. Plugins waiting for command-line activation will not yet be registered. Plugins can use this hook to examine or modify the set of loaded plugins, inject their own hook methods using :meth:`nose2.events.PluginInterface.addMethod`, or take other actions to set up or configure themselves or the test run. Since ``pluginsLoaded`` is a pre-registration hook, it is called for *all plugins* that implement the method, whether they have registered or not. Plugins that do not automatically register themselves should limit their actions in this hook to configuration, since they may not actually be active during the test run. .. function :: handleArgs(self, event) :param event: :class:`nose2.events.CommandLineArgsEvent` The ``handleArgs`` hook is called after all arguments from the command line have been parsed. Plugins can use this hook to handle command-line arguments in non-standard ways. They should not use it to try to modify arguments seen by other plugins, since the order in which plugins execute in a hook is not guaranteed. Since ``handleArgs`` is a pre-registration hook, it is called for *all plugins* that implement the method, whether they have registered or not. Plugins that do not automatically register themselves should limit their actions in this hook to configuration, since they may not actually be active during the test run. Standard Hooks -------------- These hooks are called for registered plugins only. .. function :: createTests(self, event) :param event: A :class:`nose2.events.CreateTestsEvent` instance Plugins can take over test loading by returning a test suite and setting ``event.handled`` to True. .. function :: loadTestsFromNames(self, event) :param event: A :class:`nose2.events.LoadFromNamesEvent` instance Plugins can return a test suite or list of test suites and set ``event.handled`` to ``True`` to prevent other plugins from loading tests from the given names, or append tests to ``event.extraTests``. Plugins can also remove names from ``event.names`` to prevent other plugins from acting on those names. .. function :: loadTestsFromName(self, event) :param event: A :class:`nose2.events.LoadFromNameEvent` instance Plugins can return a test suite and set ``event.handled`` to ``True`` to prevent other plugins from loading tests from the given name, or append tests to ``event.extraTests``. .. function :: handleFile(self, event) :param event: A :class:`nose2.events.HandleFileEvent` instance Plugins can use this hook to load tests from files that are not Python modules. Plugins may either append tests to ``event.extraTest``, or, if they want to prevent other plugins from processing the file, set ``event.handled`` to True and return a test case or test suite. .. function :: matchPath(self, event) :param event: A :class:`nose2.events.MatchPathEvent` instance Plugins can use this hook to prevent python modules from being loaded by the test loader or force them to be loaded by the test loader. Set ``event.handled`` to ``True`` and return ``False`` to cause the loader to skip the module. Set ``event.handled`` to ``True`` and return ``True`` to cause the loader to load the module. .. function :: loadTestsFromModule(self, event) :param event: A :class:`nose2.events.LoadFromModuleEvent` instance Plugins can use this hook to load tests from test modules. To prevent other plugins from loading from the module, set ``event.handled`` and return a test suite. Plugins can also append tests to ``event.extraTests`` -- usually that's what you want to do, since that will allow other plugins to load their tests from the module as well. See also :ref:`this warning ` about test cases not defined in the module. .. function :: loadTestsFromTestCase(self, event) :param event: A :class:`nose2.events.LoadFromTestCaseEvent` instance Plugins can use this hook to load tests from a :class:`unittest.TestCase`. To prevent other plugins from loading tests from the test case, set ``event.handled`` to ``True`` and return a test suite. Plugins can also append tests to ``event.extraTests`` -- usually that's what you want to do, since that will allow other plugins to load their tests from the test case as well. .. function :: getTestCaseNames(self, event) :param event: A :class:`nose2.events.GetTestCaseNamesEvent` instance Plugins can use this hook to limit or extend the list of test case names that will be loaded from a :class:`unittest.TestCase` by the standard nose2 test loader plugins (and other plugins that respect the results of the hook). To force a specific list of names, set ``event.handled`` to ``True`` and return a list: this exact list will be the only test case names loaded from the test case. Plugins can also extend the list of names by appending test names to ``event.extraNames``, and exclude names by appending test names to ``event.excludedNames``. .. function :: runnerCreated(self, event) :param event: A :class:`nose2.events.RunnerCreatedEvent` instance Plugins can use this hook to wrap, capture or replace the test runner. To replace the test runner, set ``event.runner``. .. function :: resultCreated(self, event) :param event: A :class:`nose2.events.ResultCreatedEvent` instance Plugins can use this hook to wrap, capture or replace the test result. To replace the test result, set ``event.result``. .. function :: startTestRun(self, event) :param event: A :class:`nose2.events.StartTestRunEvent` instance Plugins can use this hook to take action before the start of the test run, and to replace or wrap the test executor. To replace the executor, set ``event.executeTests``. This must be a callable that takes two arguments: the top-level test and the test result. To prevent the test executor from running at all, set ``event.handled`` to ``True``. .. function :: startLayerSetup(self, event) :param event: A :class:`nose2.events.StartLayerSetupEvent` instance (only available in suites with layers). Plugins can use this hook to take action before the start of the ``setUp`` in a layer. .. function :: stopLayerSetup(self, event) :param event: A :class:`nose2.events.StopLayerSetupEvent` instance (only available in suites with layers). Plugins can use this hook to take action after ``setUp`` finishes, in a layer. .. function :: startLayerSetupTest(self, event) :param event: A :class:`nose2.events.StartLayerSetupTestEvent` instance (only available in suites with layers). Plugins can use this hook to take action before the start of ``testSetUp`` in a layer. .. function :: stopLayerSetupTest(self, event) :param event: A :class:`nose2.events.StopLayerSetupTestEvent` instance (only available in suites with layers). Plugins can use this hook to take action after ``testSetUp`` finishes, in a layer. .. function :: startTest(self, event) :param event: A :class:`nose2.events.StartTestEvent` instance Plugins can use this hook to take action immediately before a test runs. .. function :: reportStartTest(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to produce output for the user at the start of a test. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: describeTest(self, event) :param event: A :class:`nose2.events.DescribeTestEvent` instance Plugins can use this hook to alter test descriptions. To return a nonstandard description for a test, set ``event.description``. Be aware that other plugins may have set this also! .. function :: setTestOutcome(self, event) :param event: A :class:`nose2.events.TestOutcomeEvent` instance Plugins can use this hook to alter test outcomes. Plugins can ``event.outcome`` to change the outcome of the event, tweak, change or remove ``event.exc_info``, set or clear ``event.expected``, and so on. .. function :: testOutcome(self, event) :param event: A :class:`nose2.events.TestOutcomeEvent` instance Plugins can use this hook to take action based on the outcome of tests. Plugins *must not* alter test outcomes in this hook: that's what :func:`setTestOutcome` is for. Here, plugins may only react to the outcome event, not alter it. .. function :: reportSuccess(self, event) :param event: A :class:`nose2.events.LoadFromNamesEvent` instance Plugins can use this hook to report test success to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportError(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report a test error to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportFailure(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report test failure to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportSkip(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report a skipped test to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportExpectedFailure(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report an expected failure to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportUnexpectedSuccess(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report an unexpected success to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. .. function :: reportOtherOutcome(self, event) :param event: A :class:`nose2.events.ReportTestEvent` instance Plugins can use this hook to report a custom test outcome to the user. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. To prevent other plugins from reporting to the user, set ``event.handled`` to ``True``. nose2 will never produce this event by itself. It only gets triggered if a plugin creates a test result with an unrecognized outcome. .. function :: stopTest(self, event) :param event: A :class:`nose2.events.StopTestEvent` instance Plugins can use this hook to take action after a test has completed running and reported its outcome. .. function :: startLayerTeardownTest(self, event) :param event: A :class:`nose2.events.StartLayerTeardownTestEvent` instance (only available in suites with layers). Plugins can use this hook to take action before the start of ``testTearDown()`` in a layer. .. function :: stopLayerTeardownTest(self, event) :param event: A :class:`nose2.events.StopLayerTeardownTestEvent` instance (only available in suites with layers). Plugins can use this hook to take action after ``testTearDown()`` finishes, in a layer. .. function :: startLayerTeardown(self, event) :param event: A :class:`nose2.events.StartLayerTeardownEvent` instance (only available in suites with layers). Plugins can use this hook to take action before the start of the ``tearDown()`` in a layer. .. function :: stopLayerTeardown(self, event) :param event: A :class:`nose2.events.StopLayerTeardownEvent` instance (only available in suites with layers). Plugins can use this hook to take action after ``tearDown()`` finishes, in a layer. .. function :: stopTestRun(self, event) :param event: A :class:`nose2.events.StopTestRunEvent` instance Plugins can use this hook to take action at the end of a test run. .. function :: afterTestRun(self, event) :param event: A :class:`nose2.events.StopTestRunEvent` instance .. note :: New in version 0.2 Plugins can use this hook to take action *after* the end of a test run, such as printing summary reports like the builtin result reporter plugin :class:`nose2.plugins.result.ResultReporter`. .. function :: resultStop(self, event) :param event: A :class:`nose2.events.ResultStopEvent` instance Plugins can use this hook to *prevent* other plugins from stopping a test run. This hook fires when something calls :meth:`nose2.result.PluggableTestResult.stop`. If you want to prevent this from stopping the test run, set ``event.shouldStop`` to ``False``. .. function :: beforeErrorList(self, event) :param event: A :class:`nose2.events.ReportSummaryEvent` instance Plugins can use this hook to output or modify summary information before the list of errors and failures is output. To modify the categories of outcomes that will be reported, plugins can modify the ``event.reportCategories`` dictionary. Plugins can set, wrap, or capture the output stream by reading or setting ``event.stream``. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. .. function :: outcomeDetail(self, event) :param event: A :class:`nose2.events.OutcomeDetailEvent` instance Plugins can use this hook to add additional elements to error list output. Append extra detail lines to ``event.extraDetail``; these will be joined together with newlines before being output as part of the detailed error/failure message, after the traceback. .. function :: beforeSummaryReport(self, event) :param event: A :class:`nose2.events.ReportSummaryEvent` instance Plugins can use this hook to output or modify summary information before the summary lines are output. To modify the categories of outcomes that will be reported in the summary, plugins can modify the ``event.reportCategories`` dictionary. Plugins can set, wrap or capture the output stream by reading or setting ``event.stream``. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. .. function :: wasSuccessful(self, event) :param event: A :class:`nose2.events.ResultSuccessEvent` instance Plugins can use this hook to mark a test run as successful or unsuccessful. If not plugin marks the run as successful, the default state is failure. To mark a run as successful, set ``event.success`` to ``True``. Be ware that other plugins may set this attribute as well! .. function :: afterSummaryReport(self, event) :param event: A :class:`nose2.events.ReportSummaryEvent` instance Plugins can use this hook to output a report to the user after the summary line is output. If you want to print to the console, write to ``event.stream``. Remember to respect ``self.session.verbosity`` when printing to the console. User Interaction Hooks ---------------------- These hooks are called when plugins want to interact with the user. .. function :: beforeInteraction(event) :param event: A :class:`nose2.events.UserInteractionEvent` Plugins should respond to this hook by getting out of the way of user interaction, if the need to, or setting ``event.handled`` and returning ``False``, if they need to but can't. .. function :: afterInteraction(event) :param event: A :class:`nose2.events.UserInteractionEvent` Plugins can respond to this hook by going back to whatever they were doing before the user stepped in and started poking around. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/internals.rst0000664002342000234200000000034213365700060017042 0ustar00sirosensirosen========= Internals ========= Reference material for things you probably only need to care about if you want to contribute to nose2. .. toctree:: :maxdepth: 2 main exceptions loader result runner utils ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/loader.rst0000664002342000234200000000012313365700060016306 0ustar00sirosensirosen============ nose2.loader ============ .. automodule :: nose2.loader :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/main.rst0000664002342000234200000000011313365700060015763 0ustar00sirosensirosen========== nose2.main ========== .. automodule :: nose2.main :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/plugin_class_reference.rst0000664002342000234200000000060213365700060021543 0ustar00sirosensirosenPlugin class reference ====================== The plugin system in nose2 is based on the plugin system in unittest2's ``plugins`` branch. Plugin base class ----------------- .. autoclass :: nose2.events.Plugin :members: Plugin interface classes ------------------------ .. autoclass :: nose2.events.PluginInterface :members: .. autoclass :: nose2.events.Hook :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/result.rst0000664002342000234200000000012313365700060016356 0ustar00sirosensirosen============ nose2.result ============ .. automodule :: nose2.result :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/runner.rst0000664002342000234200000000012413365700060016352 0ustar00sirosensirosen============ nose2.runner ============ .. automodule :: nose2.runner :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/session_reference.rst0000664002342000234200000000102013365700060020536 0ustar00sirosensirosenSession reference ================= Session ------- In nose2, all configuration for a test run is encapsulated in a ``Session`` instance. Plugins always have the session available as ``self.session``. .. autoclass :: nose2.session.Session :members: Config ------ Configuration values loaded from config file sections are made available to plugins in ``Config`` instances. Plugins that set ``configSection`` will have a ``Config`` instance available as ``self.config``. .. autoclass :: nose2.config.Config :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/dev/utils.rst0000664002342000234200000000011313365700060016177 0ustar00sirosensirosen========== nose2.util ========== .. automodule :: nose2.util :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/dev/writing_plugins.rst0000664002342000234200000001635514176405443020312 0ustar00sirosensirosen=============== Writing Plugins =============== nose2 supports plugins for test collection, selection, observation and reporting -- among other things. There are two basic rules for plugins: * Plugin classes must subclass :class:`nose2.events.Plugin`. * Plugins may implement any of the methods described in the :doc:`hook_reference`. Hello World =========== Here's a basic plugin. It doesn't do anything besides log a message at the start of a test run. .. code-block:: python import logging import os from nose2.events import Plugin log = logging.getLogger('nose2.plugins.helloworld') class HelloWorld(Plugin): configSection = 'helloworld' commandLineSwitch = (None, 'hello-world', 'Say hello!') def startTestRun(self, event): log.info('Hello pluginized world!') To see this plugin in action, save it into an importable module, then add that module to the ``plugins`` key in the ``[unittest]`` section of a config file loaded by nose2, such as ``unittest.cfg``. Then run nose2:: nose2 --log-level=INFO --hello-world And you should see the log message before the first dot appears. Loading plugins =============== As mentioned above, for nose2 to find a plugin, it must be in an importable module, and the module must be listed under the ``plugins`` key in the ``[unittest]`` section of a config file loaded by nose2: .. code-block:: ini [unittest] plugins = mypackage.someplugin otherpackage.thatplugin thirdpackage.plugins.metoo As you can see, plugin *modules* are listed, one per line. All plugin classes in those modules will be loaded -- but not necessarily active. Typically plugins do not activate themselves ("register") without seeing a command-line flag, or ``always-on = True`` in their config file section. Command-line Options ==================== nose2 uses `argparse`_ for command-line argument parsing. Plugins may enable command-line options that register them as active, or take arguments or flags controlling their operation. The most basic thing to do is to set the plugin's ``commandLineSwitch`` attribute, which will automatically add a command-line flag that registers the plugin. To add other flags or arguments, you can use the Plugin methods :meth:`nose2.events.Plugin.addFlag`, :meth:`nose2.events.Plugin.addArgument` or :meth:`nose2.events.Plugin.addOption`. If those don't offer enough flexibility, you can directly manipulate the argument parser by accessing ``self.session.argparse`` or the plugin option group by accessing ``self.session.pluginargs``. Please note though that the *majority* of your plugin's configuration should be done via config file options, not command line options. Config File Options =================== Plugins may specify a config file section that holds their configuration by setting their ``configSection`` attribute. All plugins, regardless of whether they specify a config section, have a ``config`` attribute that holds a :class:`nose2.config.Config` instance. This will be empty of values if the plugin does not specify a config section or if no loaded config file includes that section. Plugins should extract the user's configuration selections from their config attribute in their ``__init__`` methods. Plugins that want to use nose2's `Sphinx`_ extension to automatically document themselves **must** do so. Config file options may be extracted as strings, ints, booleans or lists. You should provide reasonable defaults for all config options. Guidelines ========== Events ------ nose2's plugin API is based on the API in unittest2's ``plugins`` branch (under-development). Its differs from nose's in one major area: what it passes to hooks. Where nose passes a variety of arguments, nose2 *always passes an event*. The events are listed in the :doc:`event_reference`. Here's the key thing about that: *event attributes are read-write*. Unless stated otherwise in the documentation for a hook, you can set a new value for any event attribute, and *this will do something*. Plugins and nose2 systems will see that new value and either use it instead of what was originally set in the event (example: the reporting stream or test executor), or use it to supplement something they find elsewhere (example: extraTests on a test loading event). "Handling" events ~~~~~~~~~~~~~~~~~ Many hooks give plugins a chance to completely handle events, bypassing other plugins and any core nose2 operations. To do this, a plugin sets ``event.handled`` to True and, generally, returns an appropriate value from the hook method. What is an appropriate value varies by hook, and some hooks *can't* be handled in this way. But even for hooks where handling the event doesn't stop all processing, it *will* stop subsequently-loaded plugins from seeing the event. Logging ------- nose2 uses the logging classes from the standard library. To enable users to view debug messages easily, plugins should use ``logging.getLogger()`` to acquire a logger in the ``nose2.plugins`` namespace. .. todo :: more guidelines Recipes ======= * Writing a plugin that monitors or controls test result output Implement any of the ``report*`` hook methods, especially if you want to output to the console. If outputting to file or other system, you might implement :func:`testOutcome` instead. Example: :class:`nose2.plugins.result.ResultReporter` * Writing a plugin that handles exceptions If you just want to handle some exceptions as skips or failures instead of errors, see :class:`nose2.plugins.outcomes.Outcomes`, which offers a simple way to do that. Otherwise, implement :func:`setTestOutcome` to change test outcomes. Example: :class:`nose2.plugins.outcomes.Outcomes` * Writing a plugin that adds detail to error reports Implement :func:`testOutcome` and put your extra information into ``event.metadata``, then implement :func:`outcomeDetail` to extract it and add it to the error report. Examples: :class:`nose2.plugins.buffer.OutputBufferPlugin`, :class:`nose2.plugins.logcapture.LogCapture` * Writing a plugin that loads tests from files other than python modules Implement :func:`handleFile`. Example: :class:`nose2.plugins.doctests.DocTestLoader` * Writing a plugin that loads tests from python modules Implement at least :func:`loadTestsFromModule`. .. _loading-from-module: .. warning :: One thing to beware of here is that if you return tests as dynamically-generated test cases, or instances of a testcase class that is defined *anywhere* but the module being loaded, you *must* use :func:`nose2.util.transplant_class` to make the test case class appear to have originated in that module. Otherwise, module-level fixtures will not work for that test, and may be ignored entirely for the module if there are no test cases that are or appear to be defined there. * Writing a plugin that prints a report Implement :func:`beforeErrorList`, :func:`beforeSummaryReport` or :func:`afterSummaryReport` Example: :class:`nose2.plugins.prof.Profiler` * Writing a plugin that selects or rejects tests Implement :class:`matchPath` or :class:`getTestCaseNames`. Example: :class:`nose2.plugins.loader.parameters.Parameters` .. _argparse : http://pypi.python.org/pypi/argparse/1.2.1 .. _Sphinx : http://sphinx.pocoo.org/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/differences.rst0000664002342000234200000001357114176405443016562 0ustar00sirosensirosenDifferences: nose2 vs nose vs unittest2 ======================================= nose2 is not nose ----------------- What's Different ~~~~~~~~~~~~~~~~ Python Versions ^^^^^^^^^^^^^^^ nose supports Python 2.4 and above, but nose2 only supports Python versions currently supported by the Python team. Test Discovery and Loading ^^^^^^^^^^^^^^^^^^^^^^^^^^ nose loads test modules lazily: tests in the first-loaded module are executed before the second module is imported. *nose2 loads all tests first, then begins test execution*. This has some important implications. First, it means that nose2 does not need a custom importer. nose2 imports test modules with :func:`__import__`. Second, it means that *nose2 does not support all of the test project layouts that nose does*. Specifically, projects that look like this will fail to load tests correctly with nose2:: . `-- tests |-- more_tests | `-- test.py `-- test.py To nose's loader, those two test modules look like different modules. But to nose2's loader, they look the same, and will not load correctly. Test Fixtures ^^^^^^^^^^^^^ nose2 supports only the *same levels of fixtures as unittest2*. This means class level fixtures and module level fixtures are supported, but *package-level fixtures are not*. In addition, unlike nose, nose2 does not attempt to order tests named on the command-line to group those with the same fixtures together. Parameterized and Generator Tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ nose2 supports *more kinds of parameterized and generator tests than nose*, and supports all test generators in test functions, test classes, and in unittest TestCase subclasses. nose supports them only in test functions and test classes that do not subclass unittest.TestCase. See: :doc:`plugins/generators` and :doc:`plugins/parameters` for more. Configuration ^^^^^^^^^^^^^ nose expects plugins to make all of their configuration parameters available as command-line options. *nose2 expects almost all configuration to be done via configuration files*. Plugins should generally have only one command-line option: the option to activate the plugin. Other configuration parameters should be loaded from config files. This allows more repeatable test runs and keeps the set of command-line options small enough for humans to read. See: :doc:`configuration` for more. Plugin Loading ^^^^^^^^^^^^^^ nose uses setuptools entry points to find and load plugins. nose2 does not. Instead, *nose2 requires that all plugins be listed in config files*. This ensures that no plugin is loaded into a test system just by virtue of being installed somewhere, and makes it easier to include plugins that are part of the project under test. See: :doc:`configuration` for more. Limited support for ``python setup.py test`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ nose2 supports setuptools' ``python setup.py test`` command, but via very different means than nose. To avoid the internal complexity forced on nose by the fact that the setuptools test command can't be configured with a custom test runner, when run this way, *nose2 essentially hijacks the test running process*. The "test suite" that :func:`nose2.collector.collector` returns actually *is* a test runner, cloaked inside of a test case. It loads and runs tests as normal, setting up its own test runner and test result, and calls ``sys.exit()`` itself -- completely bypassing the test runner and test result that setuptools/unittest create. This may be incompatible with some projects. Plugin API ^^^^^^^^^^ nose2 implements a new plugin API based on the work done by Michael Foord in unittest2's ``plugins`` branch. This API is greatly superior to the one in nose, especially in how it allows plugins to interact with each other. But it is different enough from the API in nose that supporting nose plugins in nose2 is not practical: *plugins must be rewritten to work with nose2*. See: :doc:`dev/writing_plugins` for more. Missing Plugins ^^^^^^^^^^^^^^^ *nose2 does not include some of the more commonly-used plugins in nose*. Some of nose's builtin plugins could not be ported to nose2 due to differences in internals. See: :doc:`plugins` for information on the plugins built in to nose2. Internals ^^^^^^^^^ nose wraps or replaces everything in unittest. nose2 does a bit less: *it does not wrap TestCases*, and does not wrap the test result class with a result proxy. nose2 does subclass :class:`TestProgram`, and install its own loader, runner, and result classes. It does this unconditionally, rather than allowing arguments to ``TestProgram.__init__()`` to specify the test loader and runner. See :doc:`dev/internals` for more information. License ^^^^^^^ While nose was LGPL, nose2 is BSD licensed. This change was made at the request of the majority of nose contributors. What's the Same ~~~~~~~~~~~~~~~ Philosophy ^^^^^^^^^^ nose2 has the same goals as nose: to extend unittest to make testing nicer and easier to understand. It aims to give developers flexibility, power and transparency, so that common test scenarios require no extra work, and uncommon test scenarios can be supported with minimal fuss and magic. nose2 is not (exactly) unittest2/plugins ---------------------------------------- nose2 is based on the unittest2 ``plugins`` branch, but differs from it in several substantial ways. The *event api not exactly the same* because nose2 can't replace unittest.TestCase, and *does not configure the test run or plugin set globally*. nose2 also has a *wholly different reporting API* from unittest2's plugins, to better support some common cases (like adding extra information to error output). nose2 also *defers more work to plugins* than unittest2: the test loader, runner and result are just plugin callers, and all of the logic of test discovery, running and reporting is implemented in plugins. This means that unlike unittest2, *nose2 includes a substantial set of plugins that are active by default*. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/getting_started.rst0000664002342000234200000000203014176405443017460 0ustar00sirosensirosenGetting started with nose2 ========================== Installation ------------ The recommended way to install nose2 is with `pip`_ :: pip install nose2 Running tests ------------- To run tests in a project, use the ``nose2`` script that is installed with nose2:: nose2 This will find and run tests in all packages in the current working directory, and any sub-directories of the current working directory whose names start with 'test'. To find tests, nose2 looks for modules whose names start with 'test'. In those modules, nose2 will load tests from all :class:`unittest.TestCase` subclasses, as well as functions whose names start with 'test'. .. todo :: ... and other classes whose names start with 'Test'. The ``nose2`` script supports a number of command-line options, as well as extensive configuration via config files. For more information see :doc:`usage` and :doc:`configuration`. .. _pip : http://pypi.python.org/pypi/pip/1.0.2 .. _pypi : http://pypi.python.org/pypi .. _six : http://pypi.python.org/pypi/six/1.1.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/index.rst0000664002342000234200000000010613641442730015376 0ustar00sirosensirosen:orphan: .. include :: ../README.rst .. include :: contents.rst.inc ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/params.rst0000664002342000234200000000021013365700060015542 0ustar00sirosensirosen=================== Parameterized tests =================== .. autofunction :: nose2.tools.params See also: :doc:`plugins/parameters` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9874318 nose2-0.12.0/docs/plugins/0000775002342000234200000000000014264564615015232 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/attrib.rst0000664002342000234200000000653413365700060017244 0ustar00sirosensirosen=============================== Selecting tests with attributes =============================== .. note :: New in version 0.2 Filter tests by attribute, excluding any tests whose attributes do not match any of the specified attributes. Attributes may be simple values or lists, and may be attributes of a test method (or function), a test case class, or the callable yielded by a generator test. Given the following test module, the attrib plugin can be used to select tests in the following ways (and others!): .. note :: All examples assume the attrib plugin has been activated in a config file: .. code-block :: ini [unittest] plugins = nose2.plugins.attrib .. literalinclude :: attrib_example.py :language: python Select tests having an attribute ________________________________ Running nose2 like this:: nose2 -v -A fast Runs these tests:: test_fast (attrib_example.Test) ... ok test_faster (attrib_example.Test) ... ok This selects all tests that define the attribute as any ``True`` value. Select tests that do not have an attribute __________________________________________ Running nose2 like this:: nose2 -v -A '!fast' Runs these tests:: test_slow (attrib_example.Test) ... ok test_slower (attrib_example.Test) ... ok This selects all tests that define the attribute as a ``False`` value, *and those tests that do not have the attribute at all*. Select tests having an attribute with a particular value -------------------------------------------------------- Running nose2 like this:: nose2 -v -A layer=2 Runs these tests:: test_fast (attrib_example.Test) ... ok test_slow (attrib_example.Test) ... ok This selects all tests that define the attribute with a matching value. The attribute value of each test case is converted to a string before comparison with the specified value. Comparison is case-insensitive. Select tests having a value in a list attribute ----------------------------------------------- Running nose2 like this:: nose2 -v -A flags=red Runs these tests:: test_faster (attrib_example.Test) ... ok test_slower (attrib_example.Test) ... ok Since the ``flags`` attribute is a list, this test selects all tests with the value ``red`` in their ``flags`` attribute. Comparison done after string conversion and is case-insensitive. Select tests that do not have a value in a list attribute --------------------------------------------------------- Running nose2 like this:: nose2 -v -A '!flags=red' Runs these tests:: test_fast (attrib_example.Test) ... ok The result in this case can be somewhat counter-intuitive. What the ``attrib`` plugin selects when you negate an attribute that is in a list are only those tests that *have the list attribute* but *without the value* specified. Tests that do not have the attribute at all are *not* selected. Select tests using Python expressions ------------------------------------- For more complex cases, you can use the :option:`-E` command-line option to pass a Python expression that will be evaluated in the context of each test case. Only those test cases where the expression evaluates to ``True`` (and don't raise an exception) will be selected. Running nose2 like this:: nose2 -v -E '"blue" in flags and layer > 2' Runs only one test:: test_slower (attrib_example.Test) ... ok .. autoplugin :: nose2.plugins.attrib.AttributeSelector ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/attrib_example.py0000664002342000234200000000105014176405443020573 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test_fast(self): pass test_fast.fast = 1 test_fast.layer = 2 test_fast.flags = ["blue", "green"] def test_faster(self): pass test_faster.fast = 1 test_faster.layer = 1 test_faster.flags = ["red", "green"] def test_slow(self): pass test_slow.fast = 0 test_slow.slow = 1 test_slow.layer = 2 def test_slower(self): pass test_slower.slow = 1 test_slower.layer = 3 test_slower.flags = ["blue", "red"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/buffer.rst0000664002342000234200000000017413365700060017222 0ustar00sirosensirosen===================== Buffering test output ===================== .. autoplugin :: nose2.plugins.buffer.OutputBufferPlugin ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/collect.rst0000664002342000234200000000024713641442730017403 0ustar00sirosensirosen===================================== Collecting tests without running them ===================================== .. autoplugin :: nose2.plugins.collect.CollectOnly ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/docs/plugins/coverage.rst0000664002342000234200000000233214264464446017560 0ustar00sirosensirosen======================= Test coverage reporting ======================= .. autoplugin :: nose2.plugins.coverage.Coverage Differences From coverage ------------------------- The ``coverage`` tool is the basis for nose2's coverage reporting. nose2 will seek to emulate ``coverage`` behavior whenever possible, but there are known cases where this is not feasible. If you need the exact behaviors of ``coverage``, consider having ``coverage`` invoke ``nose2``. Otherwise, please be aware of the following known differences: - The ``fail_under`` parameter results in an exit status of 2 for ``coverage``, but an exit status of 1 for ``nose2`` Compatibility with mp plugin ---------------------------- The ``coverage`` and ``mp`` plugins may be used in conjunction to enable multiprocess testing with coverage reporting. Special instructions: - Due to the way the plugin is reloaded in subprocesses, command-line options for the ``coverage`` plugin have no effect. If you need to change any ``coverage`` plugin options, use a configuration file. - Do *not* use the ``concurrency`` option within a ``.coveragerc`` file ; this interferes with the ``coverage`` plugin, which automatically handles multiprocess coverage reporting. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/debugger.rst0000664002342000234200000000020313365700060017526 0ustar00sirosensirosen========================== Dropping Into the Debugger ========================== .. autoplugin :: nose2.plugins.debugger.Debugger ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/discovery.rst0000664002342000234200000000020613365700060017754 0ustar00sirosensirosen====================== Loader: Test discovery ====================== .. autoplugin :: nose2.plugins.loader.discovery.DiscoveryLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/doctests.rst0000664002342000234200000000015413641442730017603 0ustar00sirosensirosen================ Loader: Doctests ================ .. autoplugin :: nose2.plugins.doctests.DocTestLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/dundertests.rst0000664002342000234200000000023713365700060020315 0ustar00sirosensirosen================================ Default filter: :attr:`__test__` ================================ .. autoplugin :: nose2.plugins.dundertest.DunderTestFilter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/eggdiscovery.rst0000664002342000234200000000175614176405443020462 0ustar00sirosensirosen========================== Loader: Egg Test discovery ========================== What is Egg Discovery --------------------- Sometimes Python Eggs are marked as zip-safe and they can be installed zipped, instead of unzipped in an ``.egg`` folder. See http://peak.telecommunity.com/DevCenter/PythonEggs for more details. The normal ``nose2.plugins.loader.discovery`` plugin ignores modules located inside zip files. The Egg Discovery plugin allows nose2 to discover tests within these zipped egg files. This plugin requires ``pkg_resources`` (from ``setuptools``) to work correctly. Usage ----- To activate the plugin, include the plugin module in the plugins list in ``[unittest]`` section in a config file:: [unittest] plugins = nose2.plugins.loader.eggdiscovery Or pass the module with the :option:`--plugin` command-line option:: nose2 --plugin=nose2.plugins.loader.eggdiscovery module_in_egg Reference --------- .. autoplugin :: nose2.plugins.loader.eggdiscovery.EggDiscoveryLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/failfast.rst0000664002342000234200000000026013365700060017536 0ustar00sirosensirosen========================================= Stopping After the First Error or Failure ========================================= .. autoplugin :: nose2.plugins.failfast.FailFast ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/functions.rst0000664002342000234200000000020113641442730017754 0ustar00sirosensirosen====================== Loader: Test Functions ====================== .. autoplugin :: nose2.plugins.loader.functions.Functions ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/generators.rst0000664002342000234200000000020513365700060020115 0ustar00sirosensirosen======================= Loader: Test Generators ======================= .. autoplugin :: nose2.plugins.loader.generators.Generators ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/junitxml.rst0000664002342000234200000001122113641442730017622 0ustar00sirosensirosen=========================== Outputting XML Test Reports =========================== .. note :: New in version 0.2 .. autoplugin :: nose2.plugins.junitxml.JUnitXmlReporter Sample output ------------- The XML test report for nose2's sample scenario with tests in a package looks like this: .. code-block :: xml Traceback (most recent call last): File "nose2/plugins/loader/parameters.py", line 162, in func return obj(*argSet) File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 64, in test_params_func assert a == 1 AssertionError Traceback (most recent call last): File "nose2/plugins/loader/parameters.py", line 162, in func return obj(*argSet) File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 69, in test_params_func_multi_arg assert a == b AssertionError Traceback (most recent call last): File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 17, in test_failed assert False, "I failed" AssertionError: I failed Traceback (most recent call last): File "nose2/plugins/loader/parameters.py", line 144, in _method return method(self, *argSet) File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 29, in test_params_method self.assertEqual(a, 1) AssertionError: 2 != 1 Traceback (most recent call last): File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 13, in test_typeerr raise TypeError("oops") TypeError: oops Traceback (most recent call last): File "nose2/plugins/loader/generators.py", line 145, in method return func(*args) File "nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py", line 24, in check assert x == 1 AssertionError ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/layers.rst0000664002342000234200000001722314176405443017263 0ustar00sirosensirosen==================================== Organizing Test Fixtures into Layers ==================================== .. note :: New in version 0.4 Layers allow more flexible organization of test fixtures than test-, class- and module- level fixtures. Layers in nose2 are inspired by and aim to be compatible with the layers used by Zope's testrunner. Using layers, you can do things like: * Implement package-level fixtures by sharing a layer among all test cases in the package. * Share fixtures across tests in different modules without having them run multiple times. * Create a fixture tree deeper than three levels (test, class and module). * Make fixtures available for other packages or projects to use. A layer is a *new-style* class that implements at least a ``setUp`` classmethod: .. code-block:: python class Layer(object): @classmethod def setUp(cls): # ... It may also implement ``tearDown``, ``testSetUp`` and ``testTearDown``, all as classmethods. To assign a layer to a test case, set the test case's ``layer`` property: .. code-block:: python class Test(unittest.TestCase): layer = Layer Note that the layer *class* is assigned, not an instance of the layer. Typically layer classes are not instantiated. Sub-layers ========== Layers may subclass other layers: .. code-block:: python class SubLayer(Layer): @classmethod def setUp(cls): # ... In this case, all tests that belong to the sub-layer also belong to the base layer. For example for this test case: .. code-block:: python class SubTest(unittest.TestCase): layer = SubLayer The ``setUp`` methods from *both* ``SubLayer`` and ``Layer`` will run before any tests are run. The superclass's setup will always run before the subclass's setup. For ``teardown``, the reverse: the subclass's ``teardown`` runs before the superclass's. .. warning:: One important thing to note: layers that subclass other layers *must not* call their superclass's ``setUp``, ``tearDown``, etc. The test runner will take care of organizing tests so that the superclass's methods are called in the right order:: Layer.setUp -> SubLayer.setUp -> Layer.testSetUp -> SubLayer.testSetUp -> TestCase.setUp TestCase.run TestCase.tearDown SubLayer.testTearDown <- Layer.testTearDown <- SubLayer.tearDown <- Layer.tearDown <- If a sublayer calls it superclass's methods directly, *those methods will be called twice*. Layer method reference ====================== .. class:: Layer Not an actual class, but reference documentation for the methods layers can implement. There is no layer base class. Layers must be subclasses of :class:`object` or other layers. .. classmethod:: setUp(cls) The layer's ``setUp`` method is called before any tests belonging to that layer are executed. If no tests belong to the layer (or one of its sub-layers) then the ``setUp`` method will not be called. .. classmethod:: tearDown(cls) The layer's ``tearDown`` method is called after any tests belonging to the layer are executed, if the layer's ``setUp`` method was called and did not raise an exception. It will not be called if the layer has no ``setUp`` method, or if that method did not run or did raise an exception. .. classmethod:: testSetUp(cls[, test]) The layer's ``testSetUp`` method is called before each test belonging to the layer (and its sub-layers). If the method is defined to accept an argument, the test case instance is passed to the method. The method may also be defined to take no arguments. .. classmethod:: testTearDown(cls[, test]) The layer's ``testTearDown`` method is called after each test belonging to the layer (and its sub-layers), if the layer also defines a ``setUpTest`` method and that method ran successfully (did not raise an exception) for this test case. Layers DSL ========== nose2 includes a DSL for setting up layer-using tests called "such". Read all about it here: :doc:`../such_dsl`. Pretty reports ============== The layers plugin module includes a second plugin that alters test report output to make the layer groupings more clear. When activated with the :option:`--layer-reporter` command-line option (or via a config file), test output that normally looks like this:: test (test_layers.NoLayer) ... ok test (test_layers.Outer) ... ok test (test_layers.InnerD) ... ok test (test_layers.InnerA) ... ok test (test_layers.InnerA_1) ... ok test (test_layers.InnerB_1) ... ok test (test_layers.InnerC) ... ok test2 (test_layers.InnerC) ... ok ---------------------------------------------------------------------- Ran 8 tests in 0.001s OK Will instead look like this:: test (test_layers.NoLayer) ... ok Base test (test_layers.Outer) ... ok LayerD test (test_layers.InnerD) ... ok LayerA test (test_layers.InnerA) ... ok LayerB LayerC test (test_layers.InnerC) ... ok test2 (test_layers.InnerC) ... ok LayerB_1 test (test_layers.InnerB_1) ... ok LayerA_1 test (test_layers.InnerA_1) ... ok ---------------------------------------------------------------------- Ran 8 tests in 0.002s OK The layer reporter plugin can also optionally colorize the keywords (by default, 'A', 'having', and 'should') in output from tests defined with the :doc:`such DSL <../such_dsl>`. If you would like to change how the layer is displayed, set the ``description`` attribute. .. code-block:: python class LayerD(Layer): description = '*** This is a very important custom layer description ***' Now the output will be the following:: test (test_layers.NoLayer) ... ok Base test (test_layers.Outer) ... ok *** This is a very important custom layer description *** test (test_layers.InnerD) ... ok LayerA test (test_layers.InnerA) ... ok LayerB LayerC test (test_layers.InnerC) ... ok test2 (test_layers.InnerC) ... ok LayerB_1 test (test_layers.InnerB_1) ... ok LayerA_1 test (test_layers.InnerA_1) ... ok ---------------------------------------------------------------------- Ran 8 tests in 0.002s OK Warnings and Caveats ==================== Test case order and module isolation ------------------------------------ Test cases that use layers will not execute in the same order as test cases that do not. In order to execute the layers efficiently, the test runner must reorganize *all* tests in the loaded test suite to group those having like layers together (and sub-layers under their parents). If you share layers across modules this may result in tests from one module executing interleaved with tests from a different module. Mixing layers with ``setUpClass`` and module fixtures ----------------------------------------------------- **Don't cross the streams.** The implementation of class- and module-level fixtures in unittest2 depends on introspecting the class hierarchy inside of the ``unittest.TestSuite``. Since the suites that the ``layers`` plugin uses to organize tests derive from :class:`unittest.BaseTestSuite` (instead of :class:`unittest.TestSuite`), class- and module- level fixtures in TestCase classes that use layers will be ignored. Mixing layers and multiprocess testing -------------------------------------- In the initial release, *test suites using layers are incompatible with the multiprocess plugin*. This should be fixed in a future release. Plugin reference ================ .. autoplugin :: nose2.plugins.layers ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/loadtests.rst0000664002342000234200000000022513365700060017750 0ustar00sirosensirosen=========================== Loader: load_tests protocol =========================== .. autoplugin :: nose2.plugins.loader.loadtests.LoadTestsLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/logcapture.rst0000664002342000234200000000024513365700060020115 0ustar00sirosensirosen====================== Capturing log messages ====================== .. todo :: Document all the things. .. autoplugin :: nose2.plugins.logcapture.LogCapture ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/mp.rst0000664002342000234200000002352714176405443016404 0ustar00sirosensirosen================================================= Running Tests in Parallel with Multiple Processes ================================================= .. note :: New in version 0.3 Use the ``mp`` plugin to enable distribution of tests across multiple processes. Doing this may speed up your test run if your tests are heavily IO or CPU bound. But it *imposes an overhead cost* that is not trivial, and it *complicates the use of test fixtures* and may *conflict with plugins that are not designed to work with it*. Usage ----- To activate the plugin, include the plugin module in the plugins list in ``[unittest]`` section in a config file:: [unittest] plugins = nose2.plugins.mp Or pass the module with the :option:`--plugin` command-line option:: nose2 --plugin=nose2.plugins.mp Then configure the number of processes to run. You can do that either with the :option:`-N` option:: nose2 -N 2 or by setting ``processes`` in the ``[multiprocess]`` section of a config file:: [multiprocess] processes = 2 .. note :: If you make the plugin always active by setting ``always-on`` in the ``[multiprocess]`` section of a config file, but do not set ``processes`` or pass :option:`-N`, the number of processes defaults to the number of CPUs available. Also note that a value of 0 will set the actual number of processes to the number of CPUs on the computer. Should one wish to specify the use of internet sockets for interprocess communications, specify the ``bind_address`` setting in the ``[multiprocess]`` section of the config file, for example:: [multiprocess] bind_address = 127.0.0.1:1024 This will bind to port 1024 of ``127.0.0.1``. Also:: [multiprocess] bind_address = 127.1.2.3 will bind to any random open port on ``127.1.2.3``. Any internet address or host-name which python can recognize as such, bind, *and* connect is acceptable. While ``0.0.0.0`` can be use for listening, it is not necessarily an address to which the OS can connect. When the port address is ``0`` or omitted, a random open port is used. If the setting is omitted or blank, then sockets are not used unless nose is being executed on Windows. In which case, an address on the loop back interface and a random port are used. Whenever used, processes employ a random shared key for authentication. Guidelines for Test Authors --------------------------- Not every test suite will work well, or work at all, when run in parallel. For some test suites, parallel execution makes no sense. For others, it will expose bugs and ordering dependencies in test cases and test modules. Overhead Cost ~~~~~~~~~~~~~ Starting subprocesses and dispatching tests takes time. A test run that includes a relatively small number of tests that are not I/O or CPU bound (or calling ``time.sleep()``) is likely to be *slower* when run in parallel. As of this writing, for instance, nose2's test suite takes about 10 times as long to run when using ``multiprocessing``, due to the overhead cost. Shared Fixtures ~~~~~~~~~~~~~~~ The individual test processes do not share state or data after launch. This means *tests that share a fixture* -- tests that are loaded from modules where ``setUpModule`` is defined, and tests in test classes that define ``setUpClass`` -- *must all be dispatched to the same process at the same time*. So if you use these kinds of fixtures, your test runs may be less parallel than you expect. Tests Load Twice ~~~~~~~~~~~~~~~~ Test cases may not be pickleable, so nose2 can't transmit them directly to its test runner processes. Tests are distributed by name. This means that *tests always load twice* -- once in the main process, during initial collection, and then again in the test runner process, where they are loaded by name. This may be problematic for some test suites. Random Execution Order ~~~~~~~~~~~~~~~~~~~~~~ Tests do not execute in the same order when run in parallel. Results will be returned in effectively random order, and tests in the same module (*as long as they do not share fixtures*) may execute in any order and in different processes. Some test suites have ordering dependencies, intentional or not, and those that do will fail randomly when run with this plugin. Guidelines for Plugin Authors ----------------------------- The MultiProcess plugin is designed to work with other plugins, but other plugins may have to return the favor, especially if they load tests or care about something that happens *during* test execution. New Methods ~~~~~~~~~~~ The ``MultiProcess`` plugin adds a few plugin hooks that other plugins can use to set themselves up for multiprocess test runs. Plugins don't have to do anything special to register for these hooks; just implement the methods as normal. .. function :: registerInSubprocess(self, event) :param event: :class:`nose2.plugins.mp.RegisterInSubprocessEvent` The ``registerInSubprocess`` hook is called after plugin registration to enable plugins that need to run in subprocesses to register that fact. The most common thing to do, for plugins that need to run in subprocesses, is:: def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) It is not required that plugins append their own class. If for some reason there is a different plugin class, or set of classes, that should run in the test-running subprocesses, add that class or those classes instead. .. function :: startSubprocess(self, event) :param event: :class:`nose2.plugins.mp.SubprocessEvent` The ``startSubprocess`` hook fires in each test-running subprocess after it has loaded its plugins but before any tests are executed. Plugins can customize test execution here in the same way as in :func:`startTestRun`, by setting ``event.executeTests``, and prevent test execution by setting ``event.handled`` to True and returning False. .. function :: stopSubprocess(self, event) :param event: :class:`nose2.plugins.mp.SubprocessEvent` The ``stopSubprocess`` event fires just before each test running subprocess shuts down. Plugins can use this hook for any per-process finalization that they may need to do. The same event instance is passed to ``startSubprocess`` and ``stopSubprocess``, which enables plugins to use that event's metadata to communicate state or other information from the start to the stop hooks, if needed. New Events ~~~~~~~~~~ The ``MultiProcess`` plugin's new hooks come with custom event classes. .. autoclass :: nose2.plugins.mp.RegisterInSubprocessEvent :members: .. autoclass :: nose2.plugins.mp.SubprocessEvent :members: Stern Warning ~~~~~~~~~~~~~ All event attributes, *including ``event.metadata``, must be pickleable*. If your plugin sets any event attributes or puts anything into ``event.metadata``, it is your responsibility to ensure that anything you can possibly put in is pickleable. Do I Really Care? ~~~~~~~~~~~~~~~~~ If you answer *yes* to any of the following questions, then your plugin will not work with multiprocess testing without modification: * Does your plugin load tests? * Does your plugin capture something that happens during test execution? * Does your plugin require user interaction during test execution? * Does your plugin set executeTests in startTestRun? Here's how to handle each of those cases. Loading Tests ^^^^^^^^^^^^^ * Implement :func:`registerInSubprocess` as suggested to enable your plugin in the test runner processes. Capturing Test Execution State ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implement :func:`registerInSubprocess` as suggested to enable your plugin in the test runner processes. * Be wary of setting ``event.metadata`` unconditionally. Your plugin will execute in the main process and in the test runner processes, and will see :func:`setTestOutcome` and :func:`testOutcome` events *in both processes*. If you unconditionally set a key in ``event.metadata``, the plugin instance in the main process will overwrite anything set in that key by the instance in the subprocess. * If you need to write something to a file, implement :func:`stopSubprocess` to write a file in each test runner process. Overriding Test Execution ^^^^^^^^^^^^^^^^^^^^^^^^^ * Implement :func:`registerInSubprocess` as suggested to enable your plugin in the test runner processes and make a note that your plugin is running under a multiprocess session. * When running multiprocess, *do not* set ``event.executeTests`` in :func:`startTestRun` -- instead, set it in :func:`startSubprocess` instead. This will allow the multiprocess plugin to install its test executor in the main process, while your plugin takes over test execution in the test runner subprocesses. Interacting with Users ^^^^^^^^^^^^^^^^^^^^^^ * You are probably safe because as a responsible plugin author you are already firing the interaction hooks (:func:`beforeInteraction`, :func:`afterInteraction`) around your interactive bits, and skipping them when the :func:`beforeInteraction` hook returns ``False`` and sets ``event.handled``. If you're not doing that, start! Possible Issues On Windows -------------------------- On windows, there are a few known bugs with respect to multiprocessing. First, on python 2.X or old versions of 3.X, if the __main__ module accessing nose2 is a __main__.py, an assertion in python code module ``multiprocessing.forking`` may fail. The bug for 3.2 is http://bugs.python.org/issue10845. Secondly, python on windows does not use fork(). It bootstraps from a separate interpreter invocation. In certain contexts, the "value" for a parameter will be taken as a "count" and subprocess use this to build the flag for the command-line. E.g., If this value is 2 billion (like a hash seed), subprocess.py may attempt to built a 2gig string, and possibly throw a MemoryError exception. The related bug is http://bugs.python.org/issue20954. Reference --------- .. autoplugin :: nose2.plugins.mp.MultiProcess ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/outcomes.rst0000664002342000234200000000023713641442730017613 0ustar00sirosensirosen=================================== Mapping exceptions to test outcomes =================================== .. autoplugin :: nose2.plugins.outcomes.Outcomes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/parameters.rst0000664002342000234200000000022113365700060020105 0ustar00sirosensirosen=========================== Loader: Parameterized Tests =========================== .. autoplugin :: nose2.plugins.loader.parameters.Parameters ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/prettyassert.rst0000664002342000234200000000246514176405443020537 0ustar00sirosensirosen============================== Use assert statements in tests ============================== .. autoplugin :: nose2.plugins.prettyassert.PrettyAssert assert statement inspection --------------------------- The prettyassert plugin works by inspecting the stack frame which raised an `AssertionError`. Unlike pytest's assertion rewriting code, it does not modify the built-in `AssertionError`. As a result, it is somewhat limited in its capabilities -- it can only report the *bound* values from that stack frame. That means that this type of statement works well: .. code-block:: python x = f() y = g() assert x == y but this type of statement does not: .. code-block:: python assert f() == g() It will still run, but the prettyassert will tell you that `f` and `g` are functions, not what they evaluated to. This is probably not what you want. attribute resolution -------------------- The assertion inspection will resolve attributes, so that expressions like this will work as well: .. code-block:: python assert x.foo == 1 But note that the attribute `x.foo` will be resolved *twice* in this case, if the assertion fails. Once when the assertion is evaluated, and again when it is inspected. As a result, properties with dynamic values may not behave as expected under prettyassert inspection. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins/printhooks.rst0000664002342000234200000001162114176405443020160 0ustar00sirosensirosen====================== Tracing hook execution ====================== .. autoplugin :: nose2.plugins.printhooks.PrintHooks Sample output ------------- PrintHooks output for a test run that discovers one standard TestCase test in a python module. Hooks that appear indented are called from within other hooks. :: handleArgs: CommandLineArgsEvent(handled=False, args=Namespace(collect_only=None, config=['unittest.cfg', 'nose2.cfg'], debugger=None, fail_fast=None, load_plugins=True, log_level=30, print_hooks=None, profile=None, start_dir='.', testNames=[], top_level_directory=None, user_config=True, verbose=0, with_id=None)) createTests: CreateTestsEvent(loader=, testNames=[], module=) loadTestsFromNames: LoadFromNames(names=[], module=None) handleFile: HandleFileEvent(handled=False, loader=, name='tests.py', path='nose2/tests/functional/support/scenario/one_test/tests.py', pattern='test*.py', topLevelDirectory='nose2/tests/functional/support/scenario/one_test') matchPath: MatchPathEvent(handled=False, name='tests.py', path='nose2/tests/functional/support/scenario/one_test/tests.py', pattern='test*.py') loadTestsFromModule: LoadFromModuleEvent(handled=False, loader=, module=, extraTests=[]) loadTestsFromTestCase: LoadFromTestCaseEvent(handled=False, loader=, testCase=, extraTests=[]) getTestCaseNames: GetTestCaseNamesEvent(handled=False, loader=, testCase=, testMethodPrefix=None, extraNames=[], excludedNames=[], isTestMethod=) handleFile: HandleFileEvent(handled=False, loader=, name='tests.pyc', path='nose2/tests/functional/support/scenario/one_test/tests.pyc', pattern='test*.py', topLevelDirectory='nose2/tests/functional/support/scenario/one_test') runnerCreated: RunnerCreatedEvent(handled=False, runner=) resultCreated: ResultCreatedEvent(handled=False, result=) startTestRun: StartTestRunEvent(handled=False, runner=, suite=]>]>]>, result=, startTime=1327346684.77457, executeTests= at 0x1fccf50>) startTest: StartTestEvent(handled=False, test=, result=, startTime=1327346684.774765) reportStartTest: ReportTestEvent(handled=False, testEvent=, stream=) setTestOutcome: TestOutcomeEvent(handled=False, test=, result=, outcome='passed', exc_info=None, reason=None, expected=True, shortLabel=None, longLabel=None) testOutcome: TestOutcomeEvent(handled=False, test=, result=, outcome='passed', exc_info=None, reason=None, expected=True, shortLabel=None, longLabel=None) reportSuccess: ReportTestEvent(handled=False, testEvent=, stream=) . stopTest: StopTestEvent(handled=False, test=, result=, stopTime=1327346684.775064) stopTestRun: StopTestRunEvent(handled=False, runner=, result=, stopTime=1327346684.77513, timeTaken=0.00056004524230957031) afterTestRun: StopTestRunEvent(handled=False, runner=, result=, stopTime=1327346684.77513, timeTaken=0.00056004524230957031) beforeErrorList: ReportSummaryEvent(handled=False, stopTestEvent=, stream=, reportCategories={'failures': [], 'skipped': [], 'errors': [], 'unexpectedSuccesses': [], 'expectedFailures': []}) ---------------------------------------------------------------------- beforeSummaryReport: ReportSummaryEvent(handled=False, stopTestEvent=, stream=, reportCategories={'failures': [], 'skipped': [], 'errors': [], 'unexpectedSuccesses': [], 'expectedFailures': []}) Ran 1 test in 0.001s wasSuccessful: ResultSuccessEvent(handled=False, result=, success=False) OK afterSummaryReport: ReportSummaryEvent(handled=False, stopTestEvent=, stream=, reportCategories={'failures': [], 'skipped': [], 'errors': [], 'unexpectedSuccesses': [], 'expectedFailures': []}) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/prof.rst0000664002342000234200000000011413365700060016711 0ustar00sirosensirosen========= Profiling ========= .. autoplugin :: nose2.plugins.prof.Profiler ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/result.rst0000664002342000234200000000017313365700060017266 0ustar00sirosensirosen====================== Reporting test results ====================== .. autoplugin :: nose2.plugins.result.ResultReporter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/testcases.rst0000664002342000234200000000017113365700060017744 0ustar00sirosensirosen================== Loader: Test Cases ================== .. autoplugin :: nose2.plugins.loader.testcases.TestCaseLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/plugins/testclasses.rst0000664002342000234200000000020213365700060020276 0ustar00sirosensirosen==================== Loader: Test Classes ==================== .. autoplugin :: nose2.plugins.loader.testclasses.TestClassLoader ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1585858008.0 nose2-0.12.0/docs/plugins/testid.rst0000664002342000234200000000013413641442730017245 0ustar00sirosensirosen============== Using Test IDs ============== .. autoplugin :: nose2.plugins.testid.TestId ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/plugins.rst0000664002342000234200000000357614176405443015772 0ustar00sirosensirosen================= Plugins for nose2 ================= Built in and Loaded by Default ============================== These plugins are loaded by default. To exclude one of these plugins from loading, add the plugin's fully qualified module name to the ``exclude-plugins`` list in a config file's ``[unittest]`` section, or pass the plugin module with the ``--exclude-plugin`` argument on the command line. You can also pass plugin module names to exclude to a :class:`nose2.main.PluggableTestProgram` using the ``excludePlugins`` keyword argument. .. toctree:: :maxdepth: 2 plugins/discovery plugins/functions plugins/generators plugins/parameters plugins/testcases plugins/testclasses plugins/loadtests plugins/dundertests plugins/result plugins/buffer plugins/debugger plugins/failfast plugins/logcapture plugins/coverage plugins/prettyassert Built in but *not* Loaded by Default ==================================== These plugins are available as part of the nose2 package but *are not loaded by default*. To load one of these plugins, add the plugin module name (as dot-separated, fully qualified name) to the ``plugins`` list in a config file's ``[unittest]`` section, or pass the plugin module with the ``--plugin`` argument on the command line. You can also pass plugin module names to a :class:`nose2.main.PluggableTestProgram` using the ``plugins`` keyword argument. .. toctree:: :maxdepth: 2 plugins/junitxml plugins/attrib plugins/mp plugins/layers plugins/doctests plugins/outcomes plugins/collect plugins/testid plugins/prof plugins/printhooks plugins/eggdiscovery Third-party Plugins =================== If you are a plugin author, please add your plugin to the list on the `nose2 wiki`_. If you are looking for more plugins, check that list! .. _nose2 wiki : https://github.com/nose-devs/nose2/wiki/Plugins ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/docs/such_dsl.rst0000664002342000234200000001142314176405443016103 0ustar00sirosensirosen====================================== Such: a Functional-Test Friendly DSL ====================================== .. note :: New in version 0.4 Such is a DSL for writing tests with expensive, nested fixtures -- which typically means functional tests. It requires the layers plugin (see :doc:`plugins/layers`). What does it look like? ======================= Unlike some python testing DSLs, such is just plain old python. .. literalinclude :: ../nose2/tests/functional/support/such/test_such.py :language: python The tests it defines are unittest tests, and can be used with nose2 with just the layers plugin. You also have the option of activating a reporting plugin (:class:`nose2.plugins.layers.LayerReporter`) to provide a more discursive brand of output: .. literalinclude :: ../nose2/tests/functional/support/such/output.txt How does it work? ================= Such uses the things in python that are most like anonymous code blocks to allow you to construct tests with meaningful names and deeply-nested fixtures. Compared to DSLs in languages that do allow blocks, it is a little bit more verbose -- the block-like decorators that mark fixture methods and test cases need to decorate *something*, so each fixture and test case has to have a function definition. You can use the same function name over and over here, or give each function a meaningful name. The set of tests begins with a description of the system under test as a whole, marked with the ``A`` context manager: .. code-block :: python from nose2.tools import such with such.A('system described here') as it: # ... Groups of tests are marked by the ``having`` context manager: .. code-block :: python with it.having('a description of a group'): # ... Within a test group (including the top-level group), fixtures are marked with decorators: .. code-block :: python @it.has_setup def setup(): # ... @it.has_test_setup def setup_each_test_case(): # ... And tests are likewise marked with the ``should`` decorator: .. code-block :: python @it.should('exhibit the behavior described here') def test(case): # ... Test cases may optionally take one argument. If they do, they will be passed the :class:`unittest.TestCase` instance generated for the test. They can use this ``TestCase`` instance to execute assert methods, among other things. Test functions can also call assert methods on the top-level scenario instance, if they don't take the ``case`` argument: .. code-block :: python @it.should("be able to use the scenario's assert methods") def test(): it.assertEqual(something, 'a value') @it.should("optionally take an argument") def test(case): case.assertEqual(case.attribute, 'some value') Finally, to actually generate tests, you **must** call ``createTests`` on the top-level scenario instance: .. code-block :: python it.createTests(globals()) This call generates the :class:`unittest.TestCase` instances for all of the tests, and the layer classes that hold the fixtures defined in the test groups. See :doc:`plugins/layers` for more about test layers. Running tests ------------- Since order is often significant in functional tests, **such DSL tests always execute in the order in which they are defined in the module**. Parent groups run before child groups, and sibling groups and sibling tests within a group execute in the order in which they are defined. Otherwise, tests written in the such DSL are collected and run just like any other tests, with one exception: their names. The name of a such test case is the name of its immediately surrounding group, plus the description of the test, prepended with ``test ####:``, where ``####`` is the test's (``0`` -indexed) position within its group. To run a case individually, you must pass in this full name -- usually you'll have to quote it. For example, to run the case ``should do more things`` defined above (assuming the layers plugin is activated by a config file, and the test module is in the normal path of test collection), you would run nose2 like this:: nose2 "test_such.having an expensive fixture.test 0000: should do more things" That is, for the generated test case, the **group description** is the **class name**, and the **test case description** is the **test case name**. As you can see if you run an individual test with the layer reporter active, all of the group fixtures execute in proper order when a test is run individually:: $ nose2 "test_such.having an expensive fixture.test 0000: should do more things" A system with complex setup having an expensive fixture should do more things ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK Reference ========= .. automodule :: nose2.tools.such :members: A, Scenario ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/docs/tools.rst0000664002342000234200000000025113365700060015424 0ustar00sirosensirosen================= Tools and Helpers ================= Tools for Test Authors ====================== .. toctree :: :maxdepth: 2 decorators params such_dsl ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1644082943.0 nose2-0.12.0/docs/usage.rst0000664002342000234200000001347214177533377015422 0ustar00sirosensirosenUsing nose2 =========== Naming Tests ------------ nose2 will look in each directory under the starting directory, unless the configuration modifies the included paths. Within directories and within any Python packages found in the starting directory and any source directories in the starting directory, nose2 will discover test modules and load tests from them. "Test modules" means any modules whose names start with "test". See the Configuration section for ways to modify searching for tests. Directories nose2 will look in: * Directory that contains an ``__init__.py`` file (a Python package) * Directory name that contains "test" after being lowercased. * Directory name that is either ``lib`` or ``src`` Each of the following test files will be run:: test.py test_views.py test_models.py testThingy.py These files will not be run:: not_a_test.py myapp_test.py some_test_file.py Within test modules, nose2 will load tests from :class:`unittest.TestCase` subclasses, and from test functions (functions whose names begin with "test"). Running Tests ------------- In the simplest case, go to the directory that includes your project source and run ``nose2`` there:: nose2 This will discover tests in packages and test directories under that directory, load them, and run them, then output something like:: ............................................................................. ---------------------------------------------------------------------- Ran 77 tests in 1.897s OK .. todo :: ... and test classes (classes whose names begin with "Test") To change the place discovery starts, or to change the top-level importable directory of the project, use the :option:`-s` and :option:`-t` options. .. cmdoption :: -s START_DIR, --start-dir START_DIR Directory to start discovery. Defaults to the current working directory. This directory is where nose2 will start looking for tests. .. cmdoption :: -t TOP_LEVEL_DIRECTORY, --top-level-directory TOP_LEVEL_DIRECTORY, --project-directory TOP_LEVEL_DIRECTORY Top-level directory of the project. Defaults to the starting directory. This is the directory containing importable modules and packages, and is always prepended to ``sys.path`` before test discovery begins. Specifying Tests to Run ~~~~~~~~~~~~~~~~~~~~~~~ Pass *test names* to nose2 on the command line to run individual test modules, classes, or tests. A test name consists of a *python object part* and, for generator or parameterized tests, an *argument part*. The *python object part* is a dotted name, such as ``pkg1.tests.test_things.SomeTests.test_ok``. The argument part is separated from the python object part by a colon (":") and specifies the *index* of the generated test to select, *starting from 1*. For example, ``pkg1.test.test_things.test_params_func:1`` would select the *first* test generated from the parameterized test ``test_params_func``. Plugins may provide other means of test selection. Running Tests with ``python setup.py test`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nose2 supports distribute/setuptools' ``python setup.py test`` standard for running tests. To use nose2 to run your package's tests, add the following to your setup.py:: setup(... test_suite='nose2.collector.collector', ... ) (Not literally. Don't put the '...' parts in.) Two warnings about running tests this way. One: because the setuptools test command is limited, nose2 returns a "test suite" that actually takes over the test running process completely, bypassing the test result and test runner that call it. This may be incompatible with some packages. Two: because the command line arguments to the test command may not match up properly with nose2's arguments, the nose2 instance started by the collector *does not accept any command line arguments*. This means that it always runs all tests, and that you cannot configure plugins on the command line when running tests this way. As a workaround, when running under the test command, nose2 will read configuration from ``setup.cfg`` if it is present, in addition to ``unittest.cfg`` and ``nose2.cfg``. This enables you to put configuration specific to the setuptools test command in ``setup.cfg`` -- for instance to activate plugins that you would otherwise activate via the command line. Getting Help ------------ Run:: nose2 -h to get help for nose2 itself and all loaded plugins. :: usage: nose2 [-s START_DIR] [-t TOP_LEVEL_DIRECTORY] [--config [CONFIG]] [--no-user-config] [--no-plugins] [--verbose] [--quiet] [-B] [-D] [--collect-only] [--log-capture] [-P] [-h] [testNames [testNames ...]] positional arguments: testNames optional arguments: -s START_DIR, --start-dir START_DIR Directory to start discovery ('.' default) -t TOP_LEVEL_DIRECTORY, --top-level-directory TOP_LEVEL_DIRECTORY, --project-directory TOP_LEVEL_DIRECTORY Top level directory of project (defaults to start dir) --config [CONFIG], -c [CONFIG] Config files to load, if they exist. ('unittest.cfg' and 'nose2.cfg' in start directory default) --no-user-config Do not load user config files --no-plugins Do not load any plugins. Warning: nose2 does not do anything if no plugins are loaded --verbose, -v --quiet -h, --help Show this help message and exit plugin arguments: Command-line arguments added by plugins: -B, --output-buffer Enable output buffer -D, --debugger Enter pdb on test fail or error --collect-only Collect but do not run tests. With '-v', this will output test names --log-capture Enable log capture -P, --print-hooks Print names of hooks in order of execution ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/license.txt0000664002342000234200000000267713365700060015003 0ustar00sirosensirosenCopyright (c) 2012, Jason Pellerin All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --- Portions derived from unittest2. unittest2 is Copyright (c) 2001-2012 Python Software Foundation; All Rights Reserved. See: http://docs.python.org/license.html ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9914317 nose2-0.12.0/nose2/0000775002342000234200000000000014264564615013647 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657988958.0 nose2-0.12.0/nose2/__init__.py0000664002342000234200000000015514264563536015762 0ustar00sirosensirosenfrom nose2.main import discover, main __version__ = "0.12.0" __all__ = ("__version__", "discover", "main") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/__main__.py0000664002342000234200000000030514176405443015732 0ustar00sirosensirosen"""Main entry point""" import sys if sys.argv[0].endswith("__main__.py"): sys.argv[0] = "nose2" __unittest = True if __name__ == "__main__": from nose2 import discover discover() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9914317 nose2-0.12.0/nose2/_vendor/0000775002342000234200000000000014264564615015303 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/_vendor/__init__.py0000664002342000234200000000000014220574143017367 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/_vendor/six.py0000664002342000234200000010336514220574143016455 0ustar00sirosensirosen# Copyright (c) 2010-2020 Benjamin Peterson # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Utilities for writing code that runs on Python 2 and 3""" from __future__ import absolute_import import functools import itertools import operator import sys import types __author__ = "Benjamin Peterson " __version__ = "1.16.0" # Useful for very coarse version differentiation. PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 PY34 = sys.version_info[0:2] >= (3, 4) if PY3: string_types = str, integer_types = int, class_types = type, text_type = str binary_type = bytes MAXSIZE = sys.maxsize else: string_types = basestring, integer_types = (int, long) class_types = (type, types.ClassType) text_type = unicode binary_type = str if sys.platform.startswith("java"): # Jython always uses 32 bits. MAXSIZE = int((1 << 31) - 1) else: # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): def __len__(self): return 1 << 31 try: len(X()) except OverflowError: # 32-bit MAXSIZE = int((1 << 31) - 1) else: # 64-bit MAXSIZE = int((1 << 63) - 1) del X if PY34: from importlib.util import spec_from_loader else: spec_from_loader = None def _add_doc(func, doc): """Add documentation to a function.""" func.__doc__ = doc def _import_module(name): """Import module, returning the module after the last dot.""" __import__(name) return sys.modules[name] class _LazyDescr(object): def __init__(self, name): self.name = name def __get__(self, obj, tp): result = self._resolve() setattr(obj, self.name, result) # Invokes __set__. try: # This is a bit ugly, but it avoids running this again by # removing this descriptor. delattr(obj.__class__, self.name) except AttributeError: pass return result class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): super(MovedModule, self).__init__(name) if PY3: if new is None: new = name self.mod = new else: self.mod = old def _resolve(self): return _import_module(self.mod) def __getattr__(self, attr): _module = self._resolve() value = getattr(_module, attr) setattr(self, attr, value) return value class _LazyModule(types.ModuleType): def __init__(self, name): super(_LazyModule, self).__init__(name) self.__doc__ = self.__class__.__doc__ def __dir__(self): attrs = ["__doc__", "__name__"] attrs += [attr.name for attr in self._moved_attributes] return attrs # Subclasses should override this _moved_attributes = [] class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): super(MovedAttribute, self).__init__(name) if PY3: if new_mod is None: new_mod = name self.mod = new_mod if new_attr is None: if old_attr is None: new_attr = name else: new_attr = old_attr self.attr = new_attr else: self.mod = old_mod if old_attr is None: old_attr = name self.attr = old_attr def _resolve(self): module = _import_module(self.mod) return getattr(module, self.attr) class _SixMetaPathImporter(object): """ A meta path importer to import six.moves and its submodules. This class implements a PEP302 finder and loader. It should be compatible with Python 2.5 and all existing versions of Python3 """ def __init__(self, six_module_name): self.name = six_module_name self.known_modules = {} def _add_module(self, mod, *fullnames): for fullname in fullnames: self.known_modules[self.name + "." + fullname] = mod def _get_module(self, fullname): return self.known_modules[self.name + "." + fullname] def find_module(self, fullname, path=None): if fullname in self.known_modules: return self return None def find_spec(self, fullname, path, target=None): if fullname in self.known_modules: return spec_from_loader(fullname, self) return None def __get_module(self, fullname): try: return self.known_modules[fullname] except KeyError: raise ImportError("This loader does not know module " + fullname) def load_module(self, fullname): try: # in case of a reload return sys.modules[fullname] except KeyError: pass mod = self.__get_module(fullname) if isinstance(mod, MovedModule): mod = mod._resolve() else: mod.__loader__ = self sys.modules[fullname] = mod return mod def is_package(self, fullname): """ Return true, if the named module is a package. We need this method to get correct spec objects with Python 3.4 (see PEP451) """ return hasattr(self.__get_module(fullname), "__path__") def get_code(self, fullname): """Return None Required, if is_package is implemented""" self.__get_module(fullname) # eventually raises ImportError return None get_source = get_code # same as get_code def create_module(self, spec): return self.load_module(spec.name) def exec_module(self, module): pass _importer = _SixMetaPathImporter(__name__) class _MovedItems(_LazyModule): """Lazy loading of moved objects""" __path__ = [] # mark as package _moved_attributes = [ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), MovedAttribute("intern", "__builtin__", "sys"), MovedAttribute("map", "itertools", "builtins", "imap", "map"), MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), MovedAttribute("getoutput", "commands", "subprocess"), MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), MovedAttribute("StringIO", "StringIO", "io"), MovedAttribute("UserDict", "UserDict", "collections"), MovedAttribute("UserList", "UserList", "collections"), MovedAttribute("UserString", "UserString", "collections"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), MovedModule("copyreg", "copy_reg"), MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), MovedModule("html_parser", "HTMLParser", "html.parser"), MovedModule("http_client", "httplib", "http.client"), MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), MovedModule("cPickle", "cPickle", "pickle"), MovedModule("queue", "Queue"), MovedModule("reprlib", "repr"), MovedModule("socketserver", "SocketServer"), MovedModule("_thread", "thread", "_thread"), MovedModule("tkinter", "Tkinter"), MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), MovedModule("tkinter_tix", "Tix", "tkinter.tix"), MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), MovedModule("tkinter_font", "tkFont", "tkinter.font"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), ] # Add windows specific modules. if sys.platform == "win32": _moved_attributes += [ MovedModule("winreg", "_winreg"), ] for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) if isinstance(attr, MovedModule): _importer._add_module(attr, "moves." + attr.name) del attr _MovedItems._moved_attributes = _moved_attributes moves = _MovedItems(__name__ + ".moves") _importer._add_module(moves, "moves") class Module_six_moves_urllib_parse(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_parse""" _urllib_parse_moved_attributes = [ MovedAttribute("ParseResult", "urlparse", "urllib.parse"), MovedAttribute("SplitResult", "urlparse", "urllib.parse"), MovedAttribute("parse_qs", "urlparse", "urllib.parse"), MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), MovedAttribute("urldefrag", "urlparse", "urllib.parse"), MovedAttribute("urljoin", "urlparse", "urllib.parse"), MovedAttribute("urlparse", "urlparse", "urllib.parse"), MovedAttribute("urlsplit", "urlparse", "urllib.parse"), MovedAttribute("urlunparse", "urlparse", "urllib.parse"), MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), MovedAttribute("quote", "urllib", "urllib.parse"), MovedAttribute("quote_plus", "urllib", "urllib.parse"), MovedAttribute("unquote", "urllib", "urllib.parse"), MovedAttribute("unquote_plus", "urllib", "urllib.parse"), MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), MovedAttribute("urlencode", "urllib", "urllib.parse"), MovedAttribute("splitquery", "urllib", "urllib.parse"), MovedAttribute("splittag", "urllib", "urllib.parse"), MovedAttribute("splituser", "urllib", "urllib.parse"), MovedAttribute("splitvalue", "urllib", "urllib.parse"), MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), MovedAttribute("uses_params", "urlparse", "urllib.parse"), MovedAttribute("uses_query", "urlparse", "urllib.parse"), MovedAttribute("uses_relative", "urlparse", "urllib.parse"), ] for attr in _urllib_parse_moved_attributes: setattr(Module_six_moves_urllib_parse, attr.name, attr) del attr Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes _importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), "moves.urllib_parse", "moves.urllib.parse") class Module_six_moves_urllib_error(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_error""" _urllib_error_moved_attributes = [ MovedAttribute("URLError", "urllib2", "urllib.error"), MovedAttribute("HTTPError", "urllib2", "urllib.error"), MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), ] for attr in _urllib_error_moved_attributes: setattr(Module_six_moves_urllib_error, attr.name, attr) del attr Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes _importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), "moves.urllib_error", "moves.urllib.error") class Module_six_moves_urllib_request(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_request""" _urllib_request_moved_attributes = [ MovedAttribute("urlopen", "urllib2", "urllib.request"), MovedAttribute("install_opener", "urllib2", "urllib.request"), MovedAttribute("build_opener", "urllib2", "urllib.request"), MovedAttribute("pathname2url", "urllib", "urllib.request"), MovedAttribute("url2pathname", "urllib", "urllib.request"), MovedAttribute("getproxies", "urllib", "urllib.request"), MovedAttribute("Request", "urllib2", "urllib.request"), MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), MovedAttribute("BaseHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), MovedAttribute("FileHandler", "urllib2", "urllib.request"), MovedAttribute("FTPHandler", "urllib2", "urllib.request"), MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), MovedAttribute("urlretrieve", "urllib", "urllib.request"), MovedAttribute("urlcleanup", "urllib", "urllib.request"), MovedAttribute("URLopener", "urllib", "urllib.request"), MovedAttribute("FancyURLopener", "urllib", "urllib.request"), MovedAttribute("proxy_bypass", "urllib", "urllib.request"), MovedAttribute("parse_http_list", "urllib2", "urllib.request"), MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), ] for attr in _urllib_request_moved_attributes: setattr(Module_six_moves_urllib_request, attr.name, attr) del attr Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes _importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), "moves.urllib_request", "moves.urllib.request") class Module_six_moves_urllib_response(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_response""" _urllib_response_moved_attributes = [ MovedAttribute("addbase", "urllib", "urllib.response"), MovedAttribute("addclosehook", "urllib", "urllib.response"), MovedAttribute("addinfo", "urllib", "urllib.response"), MovedAttribute("addinfourl", "urllib", "urllib.response"), ] for attr in _urllib_response_moved_attributes: setattr(Module_six_moves_urllib_response, attr.name, attr) del attr Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes _importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), "moves.urllib_response", "moves.urllib.response") class Module_six_moves_urllib_robotparser(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_robotparser""" _urllib_robotparser_moved_attributes = [ MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), ] for attr in _urllib_robotparser_moved_attributes: setattr(Module_six_moves_urllib_robotparser, attr.name, attr) del attr Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes _importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), "moves.urllib_robotparser", "moves.urllib.robotparser") class Module_six_moves_urllib(types.ModuleType): """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" __path__ = [] # mark as package parse = _importer._get_module("moves.urllib_parse") error = _importer._get_module("moves.urllib_error") request = _importer._get_module("moves.urllib_request") response = _importer._get_module("moves.urllib_response") robotparser = _importer._get_module("moves.urllib_robotparser") def __dir__(self): return ['parse', 'error', 'request', 'response', 'robotparser'] _importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib") def add_move(move): """Add an item to six.moves.""" setattr(_MovedItems, move.name, move) def remove_move(name): """Remove item from six.moves.""" try: delattr(_MovedItems, name) except AttributeError: try: del moves.__dict__[name] except KeyError: raise AttributeError("no such move, %r" % (name,)) if PY3: _meth_func = "__func__" _meth_self = "__self__" _func_closure = "__closure__" _func_code = "__code__" _func_defaults = "__defaults__" _func_globals = "__globals__" else: _meth_func = "im_func" _meth_self = "im_self" _func_closure = "func_closure" _func_code = "func_code" _func_defaults = "func_defaults" _func_globals = "func_globals" try: advance_iterator = next except NameError: def advance_iterator(it): return it.next() next = advance_iterator try: callable = callable except NameError: def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) if PY3: def get_unbound_function(unbound): return unbound create_bound_method = types.MethodType def create_unbound_method(func, cls): return func Iterator = object else: def get_unbound_function(unbound): return unbound.im_func def create_bound_method(func, obj): return types.MethodType(func, obj, obj.__class__) def create_unbound_method(func, cls): return types.MethodType(func, None, cls) class Iterator(object): def next(self): return type(self).__next__(self) callable = callable _add_doc(get_unbound_function, """Get the function out of a possibly unbound function""") get_method_function = operator.attrgetter(_meth_func) get_method_self = operator.attrgetter(_meth_self) get_function_closure = operator.attrgetter(_func_closure) get_function_code = operator.attrgetter(_func_code) get_function_defaults = operator.attrgetter(_func_defaults) get_function_globals = operator.attrgetter(_func_globals) if PY3: def iterkeys(d, **kw): return iter(d.keys(**kw)) def itervalues(d, **kw): return iter(d.values(**kw)) def iteritems(d, **kw): return iter(d.items(**kw)) def iterlists(d, **kw): return iter(d.lists(**kw)) viewkeys = operator.methodcaller("keys") viewvalues = operator.methodcaller("values") viewitems = operator.methodcaller("items") else: def iterkeys(d, **kw): return d.iterkeys(**kw) def itervalues(d, **kw): return d.itervalues(**kw) def iteritems(d, **kw): return d.iteritems(**kw) def iterlists(d, **kw): return d.iterlists(**kw) viewkeys = operator.methodcaller("viewkeys") viewvalues = operator.methodcaller("viewvalues") viewitems = operator.methodcaller("viewitems") _add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") _add_doc(itervalues, "Return an iterator over the values of a dictionary.") _add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") _add_doc(iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary.") if PY3: def b(s): return s.encode("latin-1") def u(s): return s unichr = chr import struct int2byte = struct.Struct(">B").pack del struct byte2int = operator.itemgetter(0) indexbytes = operator.getitem iterbytes = iter import io StringIO = io.StringIO BytesIO = io.BytesIO del io _assertCountEqual = "assertCountEqual" if sys.version_info[1] <= 1: _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" _assertNotRegex = "assertNotRegexpMatches" else: _assertRaisesRegex = "assertRaisesRegex" _assertRegex = "assertRegex" _assertNotRegex = "assertNotRegex" else: def b(s): return s # Workaround for standalone backslash def u(s): return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") unichr = unichr int2byte = chr def byte2int(bs): return ord(bs[0]) def indexbytes(buf, i): return ord(buf[i]) iterbytes = functools.partial(itertools.imap, ord) import StringIO StringIO = BytesIO = StringIO.StringIO _assertCountEqual = "assertItemsEqual" _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" _assertNotRegex = "assertNotRegexpMatches" _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") def assertCountEqual(self, *args, **kwargs): return getattr(self, _assertCountEqual)(*args, **kwargs) def assertRaisesRegex(self, *args, **kwargs): return getattr(self, _assertRaisesRegex)(*args, **kwargs) def assertRegex(self, *args, **kwargs): return getattr(self, _assertRegex)(*args, **kwargs) def assertNotRegex(self, *args, **kwargs): return getattr(self, _assertNotRegex)(*args, **kwargs) if PY3: exec_ = getattr(moves.builtins, "exec") def reraise(tp, value, tb=None): try: if value is None: value = tp() if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value finally: value = None tb = None else: def exec_(_code_, _globs_=None, _locs_=None): """Execute code in a namespace.""" if _globs_ is None: frame = sys._getframe(1) _globs_ = frame.f_globals if _locs_ is None: _locs_ = frame.f_locals del frame elif _locs_ is None: _locs_ = _globs_ exec("""exec _code_ in _globs_, _locs_""") exec_("""def reraise(tp, value, tb=None): try: raise tp, value, tb finally: tb = None """) if sys.version_info[:2] > (3,): exec_("""def raise_from(value, from_value): try: raise value from from_value finally: value = None """) else: def raise_from(value, from_value): raise value print_ = getattr(moves.builtins, "print", None) if print_ is None: def print_(*args, **kwargs): """The new-style print function for Python 2.4 and 2.5.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): if not isinstance(data, basestring): data = str(data) # If the file has an encoding, encode unicode with it. if (isinstance(fp, file) and isinstance(data, unicode) and fp.encoding is not None): errors = getattr(fp, "errors", None) if errors is None: errors = "strict" data = data.encode(fp.encoding, errors) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") if kwargs: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: if isinstance(arg, unicode): want_unicode = True break if want_unicode: newline = unicode("\n") space = unicode(" ") else: newline = "\n" space = " " if sep is None: sep = space if end is None: end = newline for i, arg in enumerate(args): if i: write(sep) write(arg) write(end) if sys.version_info[:2] < (3, 3): _print = print_ def print_(*args, **kwargs): fp = kwargs.get("file", sys.stdout) flush = kwargs.pop("flush", False) _print(*args, **kwargs) if flush and fp is not None: fp.flush() _add_doc(reraise, """Reraise an exception.""") if sys.version_info[0:2] < (3, 4): # This does exactly the same what the :func:`py3:functools.update_wrapper` # function does on Python versions after 3.2. It sets the ``__wrapped__`` # attribute on ``wrapper`` object and it doesn't raise an error if any of # the attributes mentioned in ``assigned`` and ``updated`` are missing on # ``wrapped`` object. def _update_wrapper(wrapper, wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES): for attr in assigned: try: value = getattr(wrapped, attr) except AttributeError: continue else: setattr(wrapper, attr, value) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) wrapper.__wrapped__ = wrapped return wrapper _update_wrapper.__doc__ = functools.update_wrapper.__doc__ def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES): return functools.partial(_update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) wraps.__doc__ = functools.wraps.__doc__ else: wraps = functools.wraps def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" # This requires a bit of explanation: the basic idea is to make a dummy # metaclass for one level of class instantiation that replaces itself with # the actual metaclass. class metaclass(type): def __new__(cls, name, this_bases, d): if sys.version_info[:2] >= (3, 7): # This version introduced PEP 560 that requires a bit # of extra care (we mimic what is done by __build_class__). resolved_bases = types.resolve_bases(bases) if resolved_bases is not bases: d['__orig_bases__'] = bases else: resolved_bases = bases return meta(name, resolved_bases, d) @classmethod def __prepare__(cls, name, this_bases): return meta.__prepare__(name, bases) return type.__new__(metaclass, 'temporary_class', (), {}) def add_metaclass(metaclass): """Class decorator for creating a class with a metaclass.""" def wrapper(cls): orig_vars = cls.__dict__.copy() slots = orig_vars.get('__slots__') if slots is not None: if isinstance(slots, str): slots = [slots] for slots_var in slots: orig_vars.pop(slots_var) orig_vars.pop('__dict__', None) orig_vars.pop('__weakref__', None) if hasattr(cls, '__qualname__'): orig_vars['__qualname__'] = cls.__qualname__ return metaclass(cls.__name__, cls.__bases__, orig_vars) return wrapper def ensure_binary(s, encoding='utf-8', errors='strict'): """Coerce **s** to six.binary_type. For Python 2: - `unicode` -> encoded to `str` - `str` -> `str` For Python 3: - `str` -> encoded to `bytes` - `bytes` -> `bytes` """ if isinstance(s, binary_type): return s if isinstance(s, text_type): return s.encode(encoding, errors) raise TypeError("not expecting type '%s'" % type(s)) def ensure_str(s, encoding='utf-8', errors='strict'): """Coerce *s* to `str`. For Python 2: - `unicode` -> encoded to `str` - `str` -> `str` For Python 3: - `str` -> `str` - `bytes` -> decoded to `str` """ # Optimization: Fast return for the common case. if type(s) is str: return s if PY2 and isinstance(s, text_type): return s.encode(encoding, errors) elif PY3 and isinstance(s, binary_type): return s.decode(encoding, errors) elif not isinstance(s, (text_type, binary_type)): raise TypeError("not expecting type '%s'" % type(s)) return s def ensure_text(s, encoding='utf-8', errors='strict'): """Coerce *s* to six.text_type. For Python 2: - `unicode` -> `unicode` - `str` -> `unicode` For Python 3: - `str` -> `str` - `bytes` -> decoded to `str` """ if isinstance(s, binary_type): return s.decode(encoding, errors) elif isinstance(s, text_type): return s else: raise TypeError("not expecting type '%s'" % type(s)) def python_2_unicode_compatible(klass): """ A class decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing. To support Python 2 and 3 with a single code base, define a __str__ method returning text and apply this decorator to the class. """ if PY2: if '__str__' not in klass.__dict__: raise ValueError("@python_2_unicode_compatible cannot be applied " "to %s because it doesn't define __str__()." % klass.__name__) klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass # Complete the moves implementation. # This code is at the end of this module to speed up module loading. # Turn this module into a package. __path__ = [] # required for PEP 302 and PEP 451 __package__ = __name__ # see PEP 366 @ReservedAssignment if globals().get("__spec__") is not None: __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable # Remove other six meta path importers, since they cause problems. This can # happen if six is removed from sys.modules and then reloaded. (Setuptools does # this for some reason.) if sys.meta_path: for i, importer in enumerate(sys.meta_path): # Here's some real nastiness: Another "instance" of the six module might # be floating around. Therefore, we can't use isinstance() to check for # the six meta path importer, since the other six instance will have # inserted an importer with different class. if (type(importer).__name__ == "_SixMetaPathImporter" and importer.name == __name__): del sys.meta_path[i] break del i, importer # Finally, add the importer to the meta path import hook. sys.meta_path.append(_importer) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/collector.py0000664002342000234200000000551414176405443016207 0ustar00sirosensirosenimport os import sys import unittest from nose2 import events, loader, runner, session from nose2.main import PluggableTestProgram __unittest = True def collector(): """ This is the entry point used by setuptools, as in:: python setup.py test """ class Test(unittest.TestCase): def run(self, result_): ok = self._collector(result_) sys.exit(not ok) def _get_objects(self): ssn = session.Session() ldr = loader.PluggableTestLoader(ssn) rnr = runner.PluggableTestRunner(ssn) return ssn, ldr, rnr def _collector(self, result_): ssn, ldr, rnr = self._get_objects() ssn.testLoader = ldr ssn.loadConfigFiles( "unittest.cfg", "nose2.cfg", "setup.cfg", os.path.expanduser("~/.unittest.cfg"), os.path.expanduser("~/.nose2.cfg"), ) ssn.setStartDir() ssn.prepareSysPath() ssn.loadPlugins(PluggableTestProgram.defaultPlugins) # TODO: refactor argument parsing to make it possible to feed CLI # args to plugins via this path (currently done in # PluggableTestProgram) # in order to do this, it seems like features in # PluggableTestProgram need to be factored out into some source # from which both it and this dummy test case can invoke them # # this is the disabled feature: # ssn.hooks.handleArgs(events.CommandLineArgsEvent(...)) # # this means that there may be plugins which don't work under # setuptools invocation because they expect to get handleArgs # triggered (e.g. older versions of the coverage plugin) # FIXME: this is all a great-big DRY violation when compared with # PluggableTestProgram # create the testsuite, and make sure the createTests event gets # triggered, as some plugins expect it # just doing `ldr.loadTestsFromNames` works, but leaves some # plugins in the lurch event = events.CreateTestsEvent(ldr, [], None) result = ssn.hooks.createTests(event) if event.handled: test = event else: test = ldr.loadTestsFromNames([], None) # fire the "createdTestSuite" event for plugins to handle # as above, we can get away without this, but some plugins will # expect it event = events.CreatedTestSuiteEvent(test) result = ssn.hooks.createdTestSuite(event) if event.handled: test = result rslt = rnr.run(test) return rslt.wasSuccessful() return Test("_collector") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/config.py0000664002342000234200000000435014176405443015463 0ustar00sirosensirosenTRUE_VALS = set(["1", "t", "true", "on", "yes", "y"]) __unittest = True class Config(object): """Configuration for a plugin or other entities. Encapsulates configuration for a single plugin or other element. Corresponds to a :class:`ConfigParser.Section` but provides an extended interface for extracting items as a certain type. """ def __init__(self, items): self._items = items self._mvd = {} for k, v in items: self._mvd.setdefault(k, []).append(v) def __getitem__(self, key): return self._mvd[key] def as_bool(self, key, default=None): """Get key value as boolean 1, t, true, on, yes and y (case insensitive) are accepted as ``True`` values. All other values are ``False``. """ try: val = self._mvd[key][0].strip() except KeyError: return default except IndexError: # setting = -> False return False return val.lower() in TRUE_VALS def as_int(self, key, default=None): """Get key value as integer""" return self._cast(key, int, default) def as_float(self, key, default=None): """Get key value as float""" return self._cast(key, float, default) def as_str(self, key, default=None): """Get key value as str""" return self._cast(key, str, default) def as_list(self, key, default=None): """Get key value as list. The value is split into lines and returned as a list. Lines are stripped of whitespace, and lines beginning with # are skipped. """ lines = [] try: vlist = self[key] except KeyError: return default for val in vlist: lines.extend( line.strip() for line in val.splitlines() if line.strip() and not line.strip().startswith("#") ) return lines def get(self, key, default=None): """Get key value""" return self.as_str(key, default) def _cast(self, key, type_, default): try: return type_(self._mvd[key][0].strip()) except (KeyError, IndexError): return default ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/events.py0000664002342000234200000011106214264464446015527 0ustar00sirosensirosen# Adapted from unittest2/events.py from the unittest2 plugins branch. # This module contains some code copied from unittest2/events.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import argparse import logging import sys import unittest from nose2 import config, util from nose2._vendor import six log = logging.getLogger(__name__) __unittest = True # FIXME decide on a real rule for camelCase vs under_score and stick with it. # XXX I'd rather move this stuff to Plugin.__init__ and # have __init__ call self.configure() or something after the # initial setup, but that would further break compatibility # with the unittest2 plugins branch Plugin class. class PluginMeta(type): def __call__(cls, *args, **kwargs): session = kwargs.pop("session", None) instance = object.__new__(cls, *args, **kwargs) instance.session = session instance.config = config.Config([]) config_section = getattr(instance, "configSection", None) switch = getattr(instance, "commandLineSwitch", None) if session is not None and config_section is not None: instance.config = session.get(config_section) always_on = instance.config.as_bool("always-on", default=instance.alwaysOn) instance.__init__(*args, **kwargs) if always_on: instance.register() if switch is not None: short_opt, long_opt, help = switch if always_on: # always-on plugins should hide their options help = argparse.SUPPRESS instance.addOption(instance._register_cb, short_opt, long_opt, help) return instance class Plugin(six.with_metaclass(PluginMeta)): """Base class for nose2 plugins All nose2 plugins must subclass this class. .. attribute :: session The :class:`nose2.session.Session` under which the plugin has been loaded. .. attribute :: config The :class:`nose2.config.Config` representing the plugin's config section as loaded from the session's config files. .. attribute :: commandLineSwitch A tuple of (short opt, long opt, help text) that defines a command line flag that activates this plugin. The short opt may be ``None``. If defined, it must be a single upper-case character. Both short and long opt must *not* start with dashes. Example:: commandLineSwitch = ('B', 'buffer-output', 'Buffer output during tests') .. attribute :: configSection The name config file section to load into this plugin's config. .. attribute :: alwaysOn If this plugin should automatically register itself, set alwaysOn to ``True``. Default is ``False``. .. note :: Plugins that use config values from config files and want to use the nose2 sphinx extension to automatically generate documentation *must* extract all config values from ``self.config`` in ``__init__``. Otherwise the extension will not be able to detect the config keys that the plugin uses. """ alwaysOn = False registered = False def register(self): """Register with appropriate hooks. This activates the plugin and enables it to receive events. """ if self.session is None: log.warning("Unable to register %s, no session", self) return self.session.registerPlugin(self) self.registered = True def addMethods(self, *methods): """Add new plugin methods to hooks registry Any plugins that are already registered and implement a method added here will be registered for that method as well. """ for method in methods: self.session.hooks.addMethod(method) for plugin in self.session.plugins: for method in methods: if plugin.registered and hasattr(plugin, method): self.session.hooks.register(method, plugin) def _register_cb(self, *_): if not self.registered: self.register() def addFlag(self, callback, short_opt, long_opt, help_text=None): """Add command-line flag that takes no arguments :param callback: Callback function to run when flag is seen. The callback will receive one empty argument. :param short_opt: Short option. Must be uppercase, no dashes. :param long_opt: Long option. Must not start with dashes :param help_text: Help text for users so they know what this flag does. """ self.addOption(callback, short_opt, long_opt, help_text, nargs=0) def addArgument(self, callback, short_opt, long_opt, help_text=None): """Add command-line option that takes one argument. :param callback: Callback function to run when flag is seen. The callback will receive one argument. :param short_opt: Short option. Must be uppercase, no dashes. :param long_opt: Long option. Must not start with dashes :param help_text: Help text for users so they know what this flag does. """ self.addOption(callback, short_opt, long_opt, help_text, nargs=1) def addOption(self, callback, short_opt, long_opt, help_text=None, nargs=0): """Add command-line option. :param callback: Callback function to run when flag is seen. The callback will receive one argument. The "callback" may also be a list, in which case values submitted on the command line will be appended to the list. :param short_opt: Short option. Must be uppercase, no dashes. :param long_opt: Long option. Must not start with dashes :param help_text: Help text for users so they know what this flag does. :param nargs: Number of arguments to consume from command line. """ if self.session is None: log.warning( "Unable to add option %s/%s for %s, no session", short_opt, long_opt, self, ) return class CB(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): if six.callable(callback): callback(values) elif isinstance(callback, list): callback.extend(values) else: raise ValueError( "Invalid callback %s for plugin option %s", callback, option_string, ) opts = [] if short_opt: if short_opt.lower() == short_opt: raise ValueError("Lowercase short options are reserved: %s" % short_opt) opts.append("-" + short_opt) if long_opt: opts.append("--" + long_opt) self.session.pluginargs.add_argument( *opts, action=CB, help=help_text, const=True, nargs=nargs ) class Hook(object): """A plugin hook Each plugin method in the :class:`nose2.events.PluginInterface` is represented at runtime by a Hook instance that lists the plugins that should be called by that hook. .. attribute :: method The name of the method that this Hook represents. .. attribute :: plugins The list of plugin instances bound to this hook. """ def __init__(self, method): self.method = method self.plugins = [] def __call__(self, event): for plugin in self.plugins[:]: result = getattr(plugin, self.method)(event) if event.handled: return result def append(self, plugin): if plugin not in self.plugins: self.plugins.append(plugin) class PluginInterface(object): """Definition of plugin interface. Instances of this class contain the methods that may be called, and a dictionary of :class:`nose2.events.Hook` instances bound to each method. In a plugin, PluginInterface instance is typically available as self.session.hooks, and plugin hooks may be called on it directly:: event = events.LoadFromModuleEvent(module=the_module) self.session.hooks.loadTestsFromModule(event) .. attribute :: preRegistrationMethods Tuple of methods that are called before registration. .. attribute :: methods Tuple of available plugin hook methods. .. attribute :: hookClass Class to instantiate for each hook. Default: :class:`nose2.events.Hook`. """ preRegistrationMethods = ("pluginsLoaded", "handleArgs") methods = ( "loadTestsFromModule", "loadTestsFromNames", "handleFile", "startLayerSetup", "startLayerSetupTest", "stopLayerSetupTest", "stopLayerSetup", "startTestRun", "startTest", "stopTest", "startLayerTeardown", "startLayerTeardownTest", "stopLayerTeardownTest", "stopLayerTeardown", "loadTestsFromName", "loadTestsFromTestCase", "stopTestRun", "matchPath", "matchDirPath", "getTestCaseNames", "runnerCreated", "resultCreated", "testOutcome", "wasSuccessful", "resultStop", "setTestOutcome", "describeTest", "reportStartTest", "reportError", "reportFailure", "reportSkip", "reportSuccess", "reportExpectedFailure", "reportUnexpectedSuccess", "reportOtherOutcome", "outcomeDetail", "beforeErrorList", "beforeSummaryReport", "afterSummaryReport", "beforeInteraction", "afterInteraction", "createTests", "createdTestSuite", "afterTestRun", "moduleLoadedSuite", "handleDir", # ... etc? ) hookClass = Hook def __init__(self): self.hooks = {} def addMethod(self, method): """Add a method to the available method. This allows plugins to register for this method. :param method: A method name """ self.methods = self.methods + (method,) def register(self, method, plugin): """Register a plugin for a method. :param method: A method name :param plugin: A plugin instance """ self.hooks.setdefault(method, self.hookClass(method)).append(plugin) def __getattr__(self, attr): return self.hooks.setdefault(attr, self.hookClass(attr)) class Event(object): """Base class for all events. .. attribute :: metadata Storage for arbitrary information attached to an event. .. attribute :: handled Set to ``True`` to indicate that a plugin has handled the event, and no other plugins or core systems should process it further. .. attribute :: version Version of the event API. This will be incremented with each release of nose2 that changes the API. """ _attrs = ("handled",) version = "0.4" def __init__(self, **metadata): self.handled = False self.metadata = {} self.metadata.update(metadata) def __str__(self): return "%s(%s)" % (self.__class__.__name__, self._format()) def __repr__(self): return str(self) def _format(self): return ", ".join(["%s=%r" % (k, getattr(self, k, None)) for k in self._attrs]) def __getstate__(self): state = self.__dict__.copy() # FIXME fails for loadTestsFailure if "test" in state: test = state["test"] state["test"] = util.test_name(test) # subtest support if sys.version_info >= (3, 4): if isinstance(test, unittest.case._SubTest): state["metadata"]["subtest"] = (test._message, test.params) if "executeTests" in state: state["executeTests"] = None if "exc_info" in state and state["exc_info"] is not None: ec, ev, tb = state["exc_info"] state["exc_info"] = (ec, ev, util.format_traceback(None, (ec, ev, tb))) clear = ("loader", "result", "runner") for attr in clear: if attr in state: state[attr] = None return state class PluginsLoadedEvent(Event): """Event fired after all plugin classes are loaded. .. attribute :: pluginsLoaded List of all loaded plugin classes """ _attrs = Event._attrs + ("pluginsLoaded",) def __init__(self, pluginsLoaded, **kw): self.pluginsLoaded = pluginsLoaded super(PluginsLoadedEvent, self).__init__(**kw) class RunnerCreatedEvent(Event): """Event fired when test runner is created. .. attribute :: runner Test runner instance. Plugins may replace the test runner by setting this attribute to a new test runner instance. """ _attrs = Event._attrs + ("runner",) def __init__(self, runner, **kw): self.runner = runner super(RunnerCreatedEvent, self).__init__(**kw) class ResultCreatedEvent(Event): """Event fired when test result handler is created. .. attribute :: result Test result handler instance. Plugins may replace the test result by setting this attribute to a new test result instance. """ _attrs = Event._attrs + ("result",) def __init__(self, result, **kw): self.result = result super(ResultCreatedEvent, self).__init__(**kw) class StartLayerSetupEvent(Event): """Event fired before running a layer setup. .. attribute :: layer The current layer instance, for which setup is about to run. """ _attrs = Event._attrs + ("layer",) def __init__(self, layer, **kw): self.layer = layer super(StartLayerSetupEvent, self).__init__(**kw) class StopLayerSetupEvent(Event): """Event fired after running a layer setup. .. attribute :: layer The current layer instance, for which setup just ran. """ _attrs = Event._attrs + ("layer",) def __init__(self, layer, **kw): self.layer = layer super(StopLayerSetupEvent, self).__init__(**kw) class StartLayerSetupTestEvent(Event): """Event fired before test cases setups in layers. .. attribute :: layer The current layer instance. .. attribute :: test The test instance for which the setup is about to run. """ _attrs = Event._attrs + ("layer", "test") def __init__(self, layer, test, **kw): self.layer = layer self.test = test super(StartLayerSetupTestEvent, self).__init__(**kw) class StopLayerSetupTestEvent(Event): """Event fired after test cases setups in layers. .. attribute :: layer The current layer instance. .. attribute :: test The test instance for which the setup just finished. """ _attrs = Event._attrs + ("layer", "test") def __init__(self, layer, test, **kw): self.layer = layer self.test = test super(StopLayerSetupTestEvent, self).__init__(**kw) class StartLayerTeardownEvent(Event): """Event fired before running a layer teardown. .. attribute :: layer The current layer instance, for which teardown is about to run. """ _attrs = Event._attrs + ("layer",) def __init__(self, layer, **kw): self.layer = layer super(StartLayerTeardownEvent, self).__init__(**kw) class StopLayerTeardownEvent(Event): """Event fired after running a layer teardown. .. attribute :: layer The current layer instance, for which teardown just ran. """ _attrs = Event._attrs + ("layer",) def __init__(self, layer, **kw): self.layer = layer super(StopLayerTeardownEvent, self).__init__(**kw) class StartLayerTeardownTestEvent(Event): """Event fired before test cases teardowns in layers. .. attribute :: layer The current layer instance. .. attribute :: test The test instance for which teardown is about to run. """ _attrs = Event._attrs + ("layer", "test") def __init__(self, layer, test, **kw): self.layer = layer self.test = test super(StartLayerTeardownTestEvent, self).__init__(**kw) class StopLayerTeardownTestEvent(Event): """Event fired after test cases teardowns in layers. .. attribute :: layer The current layer instance. .. attribute :: test The test instance for which teardown just ran. """ _attrs = Event._attrs + ("layer", "test") def __init__(self, layer, test, **kw): self.layer = layer self.test = test super(StopLayerTeardownTestEvent, self).__init__(**kw) class StartTestRunEvent(Event): """Event fired when test run is about to start. Test collection is complete before this event fires, but no tests have yet been executed. .. attribute :: runner Test runner .. attribute :: suite Top-level test suite to execute. Plugins can filter this suite, or set event.suite to change which tests execute (or how they execute). .. attribute :: result Test result .. attribute :: startTime Timestamp of test run start .. attribute :: executeTests Callable that will be used to execute tests. Plugins may set this attribute to wrap or otherwise change test execution. The callable must match the signature:: def execute(suite, result): ... To prevent normal test execution, plugins may set ``handled`` on this event to ``True``. When ``handled`` is true, the test executor does not run at all. """ _attrs = Event._attrs + ("runner", "suite", "result", "startTime", "executeTests") def __init__(self, runner, suite, result, startTime, executeTests, **kw): self.suite = suite self.runner = runner self.result = result self.startTime = startTime self.executeTests = executeTests super(StartTestRunEvent, self).__init__(**kw) class StopTestRunEvent(Event): """Event fired when test run has stopped. .. attribute :: runner Test runner .. attribute :: result Test result .. attribute :: stopTime Timestamp of test run stop .. attribute :: timeTaken Number of seconds test run took to execute """ _attrs = Event._attrs + ("runner", "result", "stopTime", "timeTaken") def __init__(self, runner, result, stopTime, timeTaken, **kw): self.runner = runner self.result = result self.stopTime = stopTime self.timeTaken = timeTaken super(StopTestRunEvent, self).__init__(**kw) class StartTestEvent(Event): """Event fired before a test is executed. .. attribute :: test The test case .. attribute :: result Test result .. attribute :: startTime Timestamp of test start """ _attrs = Event._attrs + ("test", "result", "startTime") def __init__(self, test, result, startTime, **kw): self.test = test self.result = result self.startTime = startTime super(StartTestEvent, self).__init__(**kw) class StopTestEvent(Event): """Event fired after a test is executed. .. attribute :: test The test case .. attribute :: result Test result .. attribute :: stopTime Timestamp of test stop """ _attrs = Event._attrs + ("test", "result", "stopTime") def __init__(self, test, result, stopTime, **kw): self.test = test self.result = result self.stopTime = stopTime super(StopTestEvent, self).__init__(**kw) class TestOutcomeEvent(Event): """Event fired when a test completes. .. attribute :: test The test case .. attribute :: result Test result .. attribute :: outcome Description of test outcome. Typically will be one of 'error', 'failed', 'skipped', 'passed', or 'subtest'. .. attribute :: exc_info If the test resulted in an exception, the tuple of (exception class, exception value, traceback) as returned by ``sys.exc_info()``. If the test did not result in an exception, ``None``. .. attribute :: reason For test outcomes that include a reason (``Skips``, for example), the reason. .. attribute :: expected Boolean indicating whether the test outcome was expected. In general, all tests are expected to pass, and any other outcome will have expected as ``False``. The exceptions to that rule are unexpected successes and expected failures. .. attribute :: shortLabel A short label describing the test outcome. (For example, 'E' for errors). .. attribute :: longLabel A long label describing the test outcome (for example, 'ERROR' for errors). Plugins may influence how the rest of the system sees the test outcome by setting ``outcome`` or ``exc_info`` or ``expected``. They may influence how the test outcome is reported to the user by setting ``shortLabel`` or ``longLabel``. """ _attrs = Event._attrs + ( "test", "result", "outcome", "exc_info", "reason", "expected", "shortLabel", "longLabel", ) def __init__( self, test, result, outcome, exc_info=None, reason=None, expected=False, shortLabel=None, longLabel=None, **kw ): self.test = test self.result = result self.outcome = outcome self.exc_info = exc_info self.reason = reason self.expected = expected self.shortLabel = shortLabel self.longLabel = longLabel super(TestOutcomeEvent, self).__init__(**kw) class LoadFromModuleEvent(Event): """Event fired when a test module is loaded. .. attribute :: loader Test loader instance .. attribute :: module The module whose tests are to be loaded .. attribute :: extraTests A list of extra tests loaded from the module. To load tests from a module without interfering with other plugins' loading activities, append tests to extraTests. Plugins may set ``handled`` on this event and return a test suite to prevent other plugins from loading tests from the module. If any plugin sets ``handled`` to ``True``, ``extraTests`` will be ignored. """ _attrs = Event._attrs + ("loader", "module", "extraTests") def __init__(self, loader, module, **kw): self.loader = loader self.module = module self.extraTests = [] super(LoadFromModuleEvent, self).__init__(**kw) class ModuleSuiteEvent(Event): _attrs = Event._attrs + ("loader", "module", "suite") def __init__(self, loader, module, suite, **kw): self.loader = loader self.module = module self.suite = suite super(ModuleSuiteEvent, self).__init__(**kw) class LoadFromTestCaseEvent(Event): """Event fired when tests are loaded from a test case. .. attribute :: loader Test loader instance .. attribute :: testCase The :class:`unittest.TestCase` instance being loaded. .. attribute :: extraTests A list of extra tests loaded from the module. To load tests from a test case without interfering with other plugins' loading activities, append tests to extraTests. Plugins may set ``handled`` on this event and return a test suite to prevent other plugins from loading tests from the test case. If any plugin sets ``handled`` to ``True``, ``extraTests`` will be ignored. """ _attrs = Event._attrs + ("loader", "testCase", "extraTests") def __init__(self, loader, testCase, **kw): self.loader = loader self.testCase = testCase self.extraTests = [] super(LoadFromTestCaseEvent, self).__init__(**kw) class LoadFromNamesEvent(Event): """Event fired to load tests from test names. .. attribute :: loader Test loader instance .. attribute :: names List of test names. May be empty or ``None``. .. attribute :: module Module to load from. May be ``None``. If not ``None``, names should be considered relative to this module. .. attribute :: extraTests A list of extra tests loaded from the tests named. To load tests from test names without interfering with other plugins' loading activities, append tests to extraTests. Plugins may set ``handled`` on this event and return a test suite to prevent other plugins from loading tests from the test names. If any plugin sets ``handled`` to ``True``, ``extraTests`` will be ignored. """ _attrs = Event._attrs + ("loader", "names", "module", "extraTests") def __init__(self, loader, names, module, **kw): self.loader = loader self.names = names self.module = module self.extraTests = [] super(LoadFromNamesEvent, self).__init__(**kw) def __str__(self): return "LoadFromNames(names=%r, module=%r)" % (self.names, self.module) class LoadFromNameEvent(Event): """Event fired to load tests from test names. .. attribute :: loader Test loader instance .. attribute :: name Test name to load .. attribute :: module Module to load from. May be ``None``. If not ``None``, names should be considered relative to this module. .. attribute :: extraTests A list of extra tests loaded from the name. To load tests from a test name without interfering with other plugins' loading activities, append tests to extraTests. Plugins may set ``handled`` on this event and return a test suite to prevent other plugins from loading tests from the test name. If any plugin sets ``handled`` to ``True``, ``extraTests`` will be ignored. """ _attrs = Event._attrs + ("loader", "name", "module", "extraTests") def __init__(self, loader, name, module, **kw): self.loader = loader self.name = name self.module = module self.extraTests = [] super(LoadFromNameEvent, self).__init__(**kw) class HandleFileEvent(Event): """Event fired when a non-test file is examined. .. note :: This event is fired for all processed python files and modules including but not limited to the ones that match the test file pattern. .. attribute :: loader Test loader instance .. attribute :: name File basename .. attribute :: path Full path to file .. attribute :: pattern Current test file match pattern .. attribute :: topLevelDirectory Top-level directory of the test run .. attribute :: extraTests A list of extra tests loaded from the file. To load tests from a file without interfering with other plugins' loading activities, append tests to extraTests. Plugins may set ``handled`` on this event and return a test suite to prevent other plugins from loading tests from the file. If any plugin sets ``handled`` to ``True``, ``extraTests`` will be ignored. """ _attrs = Event._attrs + ("loader", "name", "path", "pattern", "topLevelDirectory") def __init__(self, loader, name, path, pattern, topLevelDirectory, **kw): self.extraTests = [] self.path = path self.loader = loader self.name = name # note: pattern may be None if not called during test discovery self.pattern = pattern self.topLevelDirectory = topLevelDirectory super(HandleFileEvent, self).__init__(**kw) class MatchPathEvent(Event): """Event fired during file matching. Plugins may return ``False`` and set ``handled`` on this event to prevent a file from being matched as a test file, regardless of other system settings. .. attribute :: path Full path to the file .. attribute :: name File basename .. attribute :: pattern Current test file match pattern """ _attrs = Event._attrs + ("name", "path", "pattern") def __init__(self, name, path, pattern, **kw): self.path = path self.name = name self.pattern = pattern super(MatchPathEvent, self).__init__(**kw) class GetTestCaseNamesEvent(Event): """Event fired to find test case names in a test case. Plugins may return a list of names and set ``handled`` on this event to force test case name selection. .. attribute :: loader Test loader instance .. attribute :: testCase The :class:`unittest.TestCase` instance being loaded. .. attribute :: testMethodPrefix Set this to change the test method prefix. Unless set by a plugin, it is ``None``. .. attribute :: extraNames A list of extra test names to load from the test case. To cause extra tests to be loaded from the test case, append the names to this list. Note that the names here must be attributes of the test case. .. attribute :: excludedNames A list of names to exclude from test loading. Add names to this list to prevent other plugins from loading the named tests. .. attribute :: isTestMethod Callable that plugins can use to examine test case attributes to determine whether nose2 thinks they are test methods. """ _attrs = Event._attrs + ( "loader", "testCase", "testMethodPrefix", "extraNames", "excludedNames", "isTestMethod", ) def __init__(self, loader, testCase, isTestMethod, **kw): self.loader = loader self.testCase = testCase self.testMethodPrefix = None self.extraNames = [] self.excludedNames = [] self.isTestMethod = isTestMethod super(GetTestCaseNamesEvent, self).__init__(**kw) class ResultSuccessEvent(Event): """Event fired at end of test run to determine success. This event fires at the end of the test run and allows plugins to determine whether the test run was successful. .. attribute :: result Test result .. attribute :: success Set this to ``True`` to indicate that the test run was successful. If no plugin sets the ``success`` to ``True``, the test run fails. Should be initialized to ``None`` to indicate that the status has not been set yet (so that plugins can always differentiate an explicit failure in an earlier hook from no pass/fail status having been set yet. """ _attrs = Event._attrs + ("result", "success") def __init__(self, result, success, **kw): self.result = result self.success = success super(ResultSuccessEvent, self).__init__(**kw) class ResultStopEvent(Event): """Event fired when a test run is told to stop. Plugins can use this event to prevent other plugins from stopping a test run. .. attribute :: result Test result .. attribute :: shouldStop Set to ``True`` to indicate that the test run should stop. """ _attrs = Event._attrs + ("result", "shouldStop") def __init__(self, result, shouldStop, **kw): self.result = result self.shouldStop = shouldStop super(ResultStopEvent, self).__init__(**kw) class DescribeTestEvent(Event): """Event fired to get test description. .. attribute :: test The test case .. attribute :: description Description of the test case. Plugins can set this to change how tests are described in output to users. .. attribute :: errorList Is the event fired as part of error list output? """ _attrs = Event._attrs + ("test", "description") def __init__(self, test, description=None, errorList=False, **kw): self.test = test self.description = description self.errorList = errorList super(DescribeTestEvent, self).__init__(**kw) class OutcomeDetailEvent(Event): """Event fired to acquire additional details about test outcome. .. attribute :: outcomeEvent A :class:`nose2.events.TestOutcomeEvent` instance holding the test outcome to be described. .. attribute :: extraDetail Extra detail lines to be appended to test outcome output. Plugins can append lines (of strings) to this list to include their extra information in the error list report. """ _attrs = Event._attrs + ("outcomeEvent", "extraDetail") def __init__(self, outcomeEvent, **kw): self.outcomeEvent = outcomeEvent self.extraDetail = [] super(OutcomeDetailEvent, self).__init__(**kw) class ReportSummaryEvent(Event): """Event fired before and after summary report. .. attribute :: stopTestEvent A :class:`nose2.events.StopTestEvent` instance. .. attribute :: stream The output stream. Plugins can set this to change or capture output. .. attribute :: reportCategories Dictionary of report category and test events captured in that category. Default categories include 'errors', 'failures', 'skipped', 'expectedFails', and 'unexpectedSuccesses'. Plugins may add their own categories. """ _attrs = Event._attrs + ("stopTestEvent", "stream", "reportCategories") def __init__(self, stopTestEvent, stream, reportCategories, **kw): self.stopTestEvent = stopTestEvent self.stream = stream self.reportCategories = reportCategories super(ReportSummaryEvent, self).__init__(**kw) class ReportTestEvent(Event): """Event fired to report a test event. Plugins can respond to this event by producing output for the user. .. attribute :: testEvent A test event. In most cases, a :class:`nose2.events.TestOutcomeEvent` instance. For startTest, a :class:`nose2.events.StartTestEvent` instance. .. attribute :: stream The output stream. Plugins can set this to change or capture output. """ _attrs = Event._attrs + ("testEvent", "stream") def __init__(self, testEvent, stream, **kw): self.testEvent = testEvent self.stream = stream super(ReportTestEvent, self).__init__(**kw) class UserInteractionEvent(Event): """Event fired before and after user interaction. Plugins that capture stdout or otherwise prevent user interaction should respond to this event. To prevent the user interaction from occurring, return ``False`` and set ``handled``. Otherwise, turn off whatever you are doing that prevents users from typing/clicking/touching/psionics/whatever. """ def __init__(self, **kw): super(UserInteractionEvent, self).__init__(**kw) class CommandLineArgsEvent(Event): """Event fired after parsing of command line arguments. Plugins can respond to this event by configuring themselves or other plugins or modifying the parsed arguments. .. note :: Many plugins register options with callbacks. By the time this event fires, those callbacks have already fired. So you can't use this event to reliably influence all plugins. .. attribute :: args Args object returned by argparse. """ _attrs = Event._attrs + ("args",) def __init__(self, args, **kw): self.args = args super(CommandLineArgsEvent, self).__init__(**kw) class CreateTestsEvent(Event): """Event fired before test loading. Plugins can take over test loading by returning a test suite and setting ``handled`` on this event. .. attribute :: loader Test loader instance .. attribute :: names List of test names. May be empty or ``None``. .. attribute :: module Module to load from. May be ``None``. If not ``None``, names should be considered relative to this module. """ _attrs = Event._attrs + ("loader", "testNames", "module") def __init__(self, loader, testNames, module, **kw): self.loader = loader self.testNames = testNames self.module = module super(CreateTestsEvent, self).__init__(**kw) class CreatedTestSuiteEvent(Event): """Event fired after test loading. Plugins can replace the loaded test suite by returning a test suite and setting ``handled`` on this event. .. attribute :: suite Test Suite instance """ _attrs = Event._attrs + ("suite",) def __init__(self, suite, **kw): self.suite = suite super(CreatedTestSuiteEvent, self).__init__(**kw) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/exceptions.py0000664002342000234200000000066113365700060016370 0ustar00sirosensirosen# This module contains some code copied from unittest2/ and other code # developed in reference to unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html __unittest = True class TestNotFoundError(Exception): """Raised when a named test cannot be found""" class LoadTestsFailure(Exception): """Raised when a test cannot be loaded""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/loader.py0000664002342000234200000001033114220574143015452 0ustar00sirosensirosen# Adapted from unittest2/loader.py from the unittest2 plugins branch. # This module contains some code copied from unittest2/loader.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import logging import traceback import unittest from nose2 import events from nose2._vendor import six log = logging.getLogger(__name__) __unittest = True class PluggableTestLoader(object): """Test loader that defers all loading to plugins :param session: Test run session. .. attribute :: suiteClass Suite class to use. Default: :class:`unittest.TestSuite`. """ suiteClass = unittest.TestSuite def __init__(self, session): self.session = session def loadTestsFromModule(self, module): """Load tests from module. Fires :func:`loadTestsFromModule` hook. """ evt = events.LoadFromModuleEvent(self, module) result = self.session.hooks.loadTestsFromModule(evt) if evt.handled: suite = result or self.suiteClass() else: suite = self.suiteClass(evt.extraTests) filterevt = events.ModuleSuiteEvent(self, module, suite) result = self.session.hooks.moduleLoadedSuite(filterevt) if result: return result or self.suiteClass() return filterevt.suite def loadTestsFromNames(self, testNames, module=None): """Load tests from test names. Fires :func:`loadTestsFromNames` hook. """ event = events.LoadFromNamesEvent(self, testNames, module) result = self.session.hooks.loadTestsFromNames(event) log.debug("loadTestsFromNames event %s result %s", event, result) if event.handled: suites = result or [] else: if event.names: suites = [self.loadTestsFromName(name, module) for name in event.names] elif module: suites = self.loadTestsFromModule(module) if event.extraTests: suites.extend(event.extraTests) return self.suiteClass(suites) def loadTestsFromName(self, name, module=None): """Load tests from test name. Fires :func:`loadTestsFromName` hook. """ log.debug("loadTestsFromName %s/%s", name, module) event = events.LoadFromNameEvent(self, name, module) result = self.session.hooks.loadTestsFromName(event) if event.handled: suite = result or self.suiteClass() return suite return self.suiteClass(event.extraTests) def failedImport(self, name): """Make test case representing a failed import.""" message = "Failed to import test module: %s" % name if hasattr(traceback, "format_exc"): # Python 2.3 compatibility # format_exc returns two frames of discover.py as well XXX ? message += "\n%s" % traceback.format_exc() return self._makeFailedTest("ModuleImportFailure", name, ImportError(message)) def failedLoadTests(self, name, exception): """Make test case representing a failed test load.""" return self._makeFailedTest("LoadTestsFailure", name, exception) def sortTestMethodsUsing(self, name): """Sort key for test case test methods.""" return name.lower() def discover(self, start_dir=None, pattern=None): """Compatibility shim for ``load_tests`` protocol.""" try: oldsd = self.session.startDir self.session.startDir = start_dir return self.loadTestsFromNames([]) finally: self.session.startDir = oldsd def _makeFailedTest(self, classname, methodname, exception): def testFailure(self): if isinstance(exception, Exception): raise exception else: # exception tuple (type, value, traceback) six.reraise(*exception) attrs = {methodname: testFailure} TestClass = type(classname, (unittest.TestCase,), attrs) return self.suiteClass((TestClass(methodname),)) def __repr__(self): return "<%s>" % self.__class__.__name__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/main.py0000664002342000234200000002673414176405443015154 0ustar00sirosensirosenimport logging import os import sys import unittest from nose2 import events, loader, plugins, runner, session, util log = logging.getLogger(__name__) __unittest = True class PluggableTestProgram(unittest.TestProgram): """TestProgram that enables plugins. Accepts the same parameters as :class:`unittest.TestProgram`, but most of them are ignored as their functions are handled by plugins. :param module: Module in which to run tests. Default: :func:`__main__` :param defaultTest: Default test name. Default: ``None`` :param argv: Command line args. Default: ``sys.argv`` :param testRunner: *IGNORED* :param testLoader: *IGNORED* :param exit: Exit after running tests? :param verbosity: Base verbosity :param failfast: *IGNORED* :param catchbreak: *IGNORED* :param buffer: *IGNORED* :param plugins: List of additional plugin modules to load :param excludePlugins: List of plugin modules to exclude :param extraHooks: List of hook names and plugin *instances* to register with the session's hooks system. Each item in the list must be a 2-tuple of (hook name, plugin instance) .. attribute :: sessionClass The class to instantiate to create a test run configuration session. Default: :class:`nose2.session.Session` .. attribute :: loaderClass The class to instantiate to create a test loader. Default: :class:`nose2.loader.PluggableTestLoader`. .. warning :: Overriding this attribute is the only way to customize the test loader class. Passing a test loader to :func:`__init__` does not work. .. attribute :: runnerClass The class to instantiate to create a test runner. Default: :class:`nose2.runner.PluggableTestRunner`. .. warning :: Overriding this attribute is the only way to customize the test runner class. Passing a test runner to :func:`__init__` does not work. .. attribute :: defaultPlugins List of default plugin modules to load. """ sessionClass = session.Session _currentSession = None loaderClass = loader.PluggableTestLoader runnerClass = runner.PluggableTestRunner defaultPlugins = plugins.DEFAULT_PLUGINS excludePlugins = () # XXX override __init__ to warn that testLoader and testRunner are ignored? def __init__(self, **kw): plugins = kw.pop("plugins", []) exclude = kw.pop("excludePlugins", []) hooks = kw.pop("extraHooks", []) self.defaultPlugins = list(self.defaultPlugins) self.excludePlugins = list(self.excludePlugins) self.extraHooks = hooks self.defaultPlugins.extend(plugins) self.excludePlugins.extend(exclude) super(PluggableTestProgram, self).__init__(**kw) def parseArgs(self, argv): """Parse command line args Parses arguments and creates a configuration session, then calls :func:`createTests`. """ self.session = self.sessionClass() self.__class__._currentSession = self.session self.argparse = self.session.argparse # for convenience # XXX force these? or can it be avoided? self.testLoader = self.loaderClass(self.session) self.session.testLoader = self.testLoader # Parse initial arguments like config file paths, verbosity self.setInitialArguments() # FIXME -h here makes processing stop. cfg_args, argv = self.argparse.parse_known_args(argv[1:]) self.handleCfgArgs(cfg_args) # Parse arguments for plugins (if any) and test names self.argparse.add_argument("testNames", nargs="*") # add help arg now so -h will also print plugin opts self.argparse.add_argument( "-h", "--help", action="help", help=("Show this help message and exit") ) args, argv = self.argparse.parse_known_args(argv) if argv: self.argparse.error("Unrecognized arguments: %s" % " ".join(argv)) self.handleArgs(args) self.createTests() def setInitialArguments(self): """Set pre-plugin command-line arguments. This set of arguments is parsed out of the command line before plugins are loaded. """ self.argparse.add_argument( "-s", "--start-dir", default=None, help="Directory to start discovery ('.' default)", ) self.argparse.add_argument( "-t", "--top-level-directory", "--project-directory", help="Top level directory of project (defaults to start dir)", ) self.argparse.add_argument( "--config", "-c", nargs="?", action="append", default=["unittest.cfg", "nose2.cfg"], help="Config files to load, if they exist. ('unittest.cfg' " "and 'nose2.cfg' in start directory default)", ) self.argparse.add_argument( "--no-user-config", action="store_const", dest="user_config", const=False, default=True, help="Do not load user config files", ) self.argparse.add_argument( "--no-plugins", action="store_const", dest="load_plugins", const=False, default=True, help="Do not load any plugins. Warning: nose2 does not " "do anything if no plugins are loaded", ) self.argparse.add_argument( "--plugin", action="append", dest="plugins", default=[], help="Load this plugin module.", ) self.argparse.add_argument( "--exclude-plugin", action="append", dest="exclude_plugins", default=[], help="Do not load this plugin module", ) self.argparse.add_argument( "--verbosity", type=int, help=("Set starting verbosity level (int). " "Applies before -v and -q"), ) self.argparse.add_argument( "--verbose", "-v", action="count", default=0, help=( "Print test case names and statuses. " "Use multiple '-v's for higher verbosity." ), ) self.argparse.add_argument( "--quiet", "-q", action="count", default=0, dest="quiet", help=("Reduce verbosity. Multiple '-q's result in " "lower verbosity."), ) self.argparse.add_argument( "--log-level", default=logging.WARN, help="Set logging level for message logged to console.", ) def handleCfgArgs(self, cfg_args): """Handle initial arguments. Handle the initial, pre-plugin arguments parsed out of the command line. """ self.session.logLevel = util.parse_log_level(cfg_args.log_level) logging.basicConfig(level=self.session.logLevel) log.debug("logging initialized %s", cfg_args.log_level) if cfg_args.top_level_directory: self.session.topLevelDir = cfg_args.top_level_directory self.session.loadConfigFiles(*self.findConfigFiles(cfg_args)) # set verbosity from config + opts self.session.setVerbosity(cfg_args.verbosity, cfg_args.verbose, cfg_args.quiet) self.session.setStartDir(args_start_dir=cfg_args.start_dir) self.session.prepareSysPath() if cfg_args.load_plugins: self.defaultPlugins.extend(cfg_args.plugins) self.excludePlugins.extend(cfg_args.exclude_plugins) self.loadPlugins() elif cfg_args.plugins or cfg_args.exclude_plugins: log.warn( "Both '--no-plugins' and '--plugin' or '--exclude-plugin' " "specified. No plugins were loaded." ) def findConfigFiles(self, cfg_args): """Find available config files""" filenames = cfg_args.config[:] proj_opts = ("unittest.cfg", "nose2.cfg") for fn in proj_opts: if cfg_args.top_level_directory: fn = os.path.abspath(os.path.join(cfg_args.top_level_directory, fn)) filenames.append(fn) if cfg_args.user_config: user_opts = ("~/.unittest.cfg", "~/.nose2.cfg") for fn in user_opts: filenames.append(os.path.expanduser(fn)) return filenames def handleArgs(self, args): """Handle further arguments. Handle arguments parsed out of command line after plugins have been loaded (and injected their argument configuration). """ self.testNames = args.testNames self.session.hooks.handleArgs(events.CommandLineArgsEvent(args=args)) def loadPlugins(self): """Load available plugins :func:`self.defaultPlugins`` and :func:`self.excludePlugins` are passed to the session to alter the list of plugins that will be loaded. This method also registers any (hook, plugin) pairs set in ``self.hooks``. This is a good way to inject plugins that fall outside of the normal loading procedure, for example, plugins that need some runtime information that can't easily be passed to them through the configuration system. """ self.session.loadPlugins(self.defaultPlugins, self.excludePlugins) for method_name, plugin in self.extraHooks: self.session.hooks.register(method_name, plugin) def createTests(self): """Create top-level test suite""" event = events.CreateTestsEvent(self.testLoader, self.testNames, self.module) result = self.session.hooks.createTests(event) if event.handled: test = result else: log.debug("Create tests from %s/%s", self.testNames, self.module) test = self.testLoader.loadTestsFromNames(self.testNames, self.module) event = events.CreatedTestSuiteEvent(test) result = self.session.hooks.createdTestSuite(event) if event.handled: test = result self.test = test def runTests(self): """Run tests""" # fire plugin hook runner = self._makeRunner() try: self.result = runner.run(self.test) except Exception as e: log.exception("Internal Error") sys.stderr.write("Internal Error: runTests aborted: %s\n" % (e)) if self.exit: sys.exit(1) if self.exit: sys.exit(not self.result.wasSuccessful()) def _makeRunner(self): runner = self.runnerClass(self.session) event = events.RunnerCreatedEvent(runner) self.session.hooks.runnerCreated(event) self.session.testRunner = event.runner return event.runner @classmethod def getCurrentSession(cls): """Returns the current session, or ``None`` if no :class:`nose2.session.Session` is running. """ return cls._currentSession main = PluggableTestProgram def discover(*args, **kwargs): """Main entry point for test discovery. Running discover calls :class:`nose2.main.PluggableTestProgram`, passing through all arguments and keyword arguments **except module**: ``module`` is discarded, to force test discovery. """ kwargs["module"] = None return main(*args, **kwargs) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9954317 nose2-0.12.0/nose2/plugins/0000775002342000234200000000000014264564615015330 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/__init__.py0000664002342000234200000000012514176405443017432 0ustar00sirosensirosenfrom nose2.plugins._constants import DEFAULT_PLUGINS __all__ = ("DEFAULT_PLUGINS",) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/_constants.py0000664002342000234200000000103014176405443020042 0ustar00sirosensirosenDEFAULT_PLUGINS = ( "nose2.plugins.loader.discovery", "nose2.plugins.loader.testcases", "nose2.plugins.loader.functions", "nose2.plugins.loader.testclasses", "nose2.plugins.loader.generators", "nose2.plugins.loader.parameters", "nose2.plugins.loader.loadtests", "nose2.plugins.dundertest", "nose2.plugins.coverage", "nose2.plugins.result", "nose2.plugins.logcapture", "nose2.plugins.buffer", "nose2.plugins.failfast", "nose2.plugins.debugger", "nose2.plugins.prettyassert", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/attrib.py0000664002342000234200000001266314176405443017172 0ustar00sirosensirosenimport logging from unittest import TestSuite from nose2.events import Plugin log = logging.getLogger(__name__) undefined = object() class AttributeSelector(Plugin): """Filter tests by attribute""" def __init__(self): self.attribs = [] self.eval_attribs = [] self.addArgument( self.attribs, "A", "attribute", "Select tests with matching attribute" ) self.addArgument( self.eval_attribs, "E", "eval-attribute", "Select tests for whose attributes the " "given Python expression evaluates to ``True``", ) def handleArgs(self, args): """Register if any attribs defined""" if self.attribs or self.eval_attribs: self.register() def moduleLoadedSuite(self, event): """Filter event.suite by specified attributes""" log.debug("Attribute selector attribs %s/%s", self.attribs, self.eval_attribs) attribs = [] for attr in self.eval_attribs: def eval_in_context(expr, obj): try: return eval(expr, None, ContextHelper(obj)) except Exception as e: log.warning("%s raised exception %s with test %s", expr, e, obj) return False attribs.append([(attr, eval_in_context)]) for attr in self.attribs: # all attributes within an attribute group must match attr_group = [] for attrib in attr.strip().split(","): # don't die on trailing comma if not attrib: continue items = attrib.split("=", 1) if len(items) > 1: # "name=value" # -> 'str(obj.name) == value' must be True key, value = items else: key = items[0] if key[0] == "!": # "!name" # 'bool(obj.name)' must be False key = key[1:] value = False else: # "name" # -> 'bool(obj.name)' must be True value = True attr_group.append((key, value)) attribs.append(attr_group) if not attribs: return event.suite = self.filterSuite(event.suite, attribs) def filterSuite(self, suite, attribs): # FIXME probably need to copy or something to allow suites w/custom attrs to # work or iter and remove instead of recreating new_suite = suite.__class__() for test in suite: if isinstance(test, TestSuite): new_suite.addTest(self.filterSuite(test, attribs)) elif self.validateAttrib(test, attribs): new_suite.addTest(test) return new_suite def validateAttrib(self, test, attribs): any_ = False for group in attribs: match = True for key, value in group: neg = False if key.startswith("!"): neg, key = True, key[1:] obj_value = _get_attr(test, key) if callable(value): if not value(key, test): match = False break elif value is True: # value must exist and be True if not bool(obj_value): match = False break elif value is False: # value must not exist or be False if bool(obj_value): match = False break elif type(obj_value) in (list, tuple): # value must be found in the list attribute found = str(value).lower() in [str(x).lower() for x in obj_value] if found and neg: match = False break elif not found and not neg: match = False break else: # value must match, convert to string and compare if ( value != obj_value and str(value).lower() != str(obj_value).lower() ): match = False break any_ = any_ or match return any_ # helpers def _get_attr(test, key): # FIXME for vals that are lists (or just mutable?), combine all levels val = getattr(test, key, undefined) if val is not undefined: return val if hasattr(test, "_testFunc"): val = getattr(test._testFunc, key, undefined) if val is not undefined: return val elif hasattr(test, "_testMethodName"): # testclasses support if test.__class__.__name__ == "_MethodTestCase": meth = getattr(test.obj, test.method, undefined) else: meth = getattr(test, test._testMethodName, undefined) if meth is not undefined: val = getattr(meth, key, undefined) if val is not undefined: return val class ContextHelper: def __init__(self, obj): self.obj = obj def __getitem__(self, name): return _get_attr(self.obj, name) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/plugins/buffer.py0000664002342000234200000001403114220574143017137 0ustar00sirosensirosen""" Buffer stdout and/or stderr during test execution, appending any output to the error reports of failed tests. This allows you to use print for debugging in tests without making your test runs noisy. This plugin implements :func:`startTest`, :func:`stopTest`, :func:`setTestOutcome`, :func:`outcomeDetail`, :func:`beforeInteraction` and :func:`afterInteraction` to manage capturing sys.stdout and/or sys.stderr into buffers, attaching the buffered output to test error report detail, and getting out of the way when other plugins want to talk to the user. """ import sys import traceback from nose2 import events from nose2._vendor import six from nose2.util import ln __unittest = True class _Buffer(object): def __init__(self, stream): self._stream = stream self._buffer = six.StringIO() def fileno(self): return self._stream.fileno() def __getattr__(self, attr): # this happens on unpickling if attr == "_buffer": raise AttributeError("No _buffer yet") return getattr(self._buffer, attr) def __le__(self, obj): return self._buffer.getvalue() == obj def __eq__(self, obj): return self._buffer.getvalue() == obj def __str__(self): return self._buffer.getvalue() def __repr__(self): return repr(self._buffer.getvalue()) class OutputBufferPlugin(events.Plugin): """Buffer output during test execution""" commandLineSwitch = ("B", "output-buffer", "Enable output buffer") configSection = "output-buffer" def __init__(self): self.captureStdout = self.config.as_bool("stdout", default=True) self.captureStderr = self.config.as_bool("stderr", default=False) self.bufStdout = self.bufStderr = None self.realStdout = sys.__stdout__ self.realStderr = sys.__stderr__ self._disable = False def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) # turn off in this process: the subproc will run the tests self._disable = True def startSubprocess(self, event): self.realStdout = sys.__stdout__ self.realStderr = sys.__stderr__ def startTest(self, event): """Start buffering selected stream(s)""" self._buffer() def stopTest(self, event): """Stop buffering""" self._restore() def _get_stream_unicode_save(self, stream, buffer): buf = "" stream_buffer_exc_info = None try: buf = buffer.getvalue() except UnicodeError: # python2's StringIO.StringIO [1] class has this warning: # # The StringIO object can accept either Unicode or 8-bit strings, # but mixing the two may take some care. If both are used, 8-bit # strings that cannot be interpreted as 7-bit ASCII (that use the # 8th bit) will cause a UnicodeError to be raised when getvalue() # is called. # # This exception handler is a protection against crashes # caused by this exception (such as [2] in the original # nose application). Capturing the exception info allows us # to display it back to the user. # # [1] # [2] stream_buffer_exc_info = sys.exc_info() extraDetail = [] extraDetail.append(ln(">> begin captured %s <<" % stream)) extraDetail.append(buf) extraDetail.append(ln(">> end captured %s <<" % stream)) if stream_buffer_exc_info: extraDetail.append( "OUTPUT ERROR: Could not get captured %s output." % stream ) extraDetail.append( "The test might've printed both 'unicode' strings and " "non-ASCII 8-bit 'str' strings." ) extraDetail.append( ln(">> begin captured %s exception traceback <<" % stream) ) extraDetail.append( "".join(traceback.format_exception(*stream_buffer_exc_info)) ) extraDetail.append(ln(">> end captured %s exception traceback <<" % stream)) return "\n".join(extraDetail) def setTestOutcome(self, event): """Attach buffer(s) to event.metadata""" if self._disable: return if self.captureStdout and "stdout" not in event.metadata: event.metadata["stdout"] = self._get_stream_unicode_save( "stdout", self.bufStdout ) if self.captureStderr and "stderr" not in event.metadata: event.metadata["stderr"] = self._get_stream_unicode_save( "stderr", self.bufStderr ) def outcomeDetail(self, event): """Add buffered output to event.extraDetail""" for stream in ("stdout", "stderr"): if stream in event.outcomeEvent.metadata: b = event.outcomeEvent.metadata[stream] if b: event.extraDetail.append(b) def beforeInteraction(self, event): """Stop buffering so users can see stdout""" self._restore() def afterInteraction(self, event): """Start buffering again (does not clear buffers)""" self._buffer(fresh=False) def stopSubprocess(self, event): self._restore() def _restore(self): if self._disable: return if self.captureStdout: sys.stdout = self.realStdout if self.captureStderr: sys.stderr = self.realStderr def _buffer(self, fresh=True): if self._disable: return if self.captureStdout: if fresh or self.bufStdout is None: self.bufStdout = _Buffer(sys.stdout) sys.stdout = self.bufStdout if self.captureStderr: if fresh or self.bufStderr is None: self.bufStderr = _Buffer(sys.stderr) sys.stderr = self.bufStderr ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1644082942.0 nose2-0.12.0/nose2/plugins/collect.py0000664002342000234200000000250614177533376017335 0ustar00sirosensirosen""" This plugin implements :func:`startTestRun`, setting a test executor (``event.executeTests``) that just collects tests without executing them. To do so it calls result.startTest, result.addSuccess and result.stopTest for each test, without calling the test itself. """ import unittest from nose2.events import Plugin __unittest = True class CollectOnly(Plugin): """Collect but don't run tests""" configSection = "collect-only" commandLineSwitch = ( None, "collect-only", "Collect but do not run tests. With '-v', this will output test names", ) _mpmode = False def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) self._mpmode = True def startTestRun(self, event): """Replace ``event.executeTests``""" if self._mpmode: return event.executeTests = self.collectTests def startSubprocess(self, event): event.executeTests = self.collectTests def collectTests(self, suite, result): """Collect tests, but don't run them""" for test in suite: if isinstance(test, unittest.BaseTestSuite): self.collectTests(test, result) continue result.startTest(test) result.addSuccess(test) result.stopTest(test) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657941616.0 nose2-0.12.0/nose2/plugins/coverage.py0000664002342000234200000001533614264427160017476 0ustar00sirosensirosen""" Use this plugin to activate coverage report. To use this plugin, you need to install ``nose2[coverage_plugin]``. e.g. :: $ pip install nose2[coverage_plugin]>=0.6.5 Then, you can enable coverage reporting with : :: $ nose2 --with-coverage Or with this lines in ``unittest.cfg`` : :: [coverage] always-on = True You can further specify coverage behaviors with a ``.coveragerc`` file, as specified by `Coverage Config `_. However, when doing so you should also be aware of `Differences From coverage`_. """ from __future__ import absolute_import, print_function import logging from nose2._vendor import six from nose2.events import Plugin log = logging.getLogger(__name__) class Coverage(Plugin): configSection = "coverage" commandLineSwitch = ("C", "with-coverage", "Turn on coverage reporting") _mpmode = False _subprocess = False def __init__(self): """Get our config and add our command line arguments.""" # tracking var for any decision which marks the entire run as failed self.decided_failure = False # buffer for error output data self.error_output_buffer = six.StringIO() self.covSource = self.config.as_list("coverage", []) or ["."] self.covReport = self.config.as_list("coverage-report", []) or ["term"] self.covConfig = ( self.config.as_str("coverage-config", "").strip() or ".coveragerc" ) group = self.session.pluginargs group.add_argument( "--coverage", action="append", default=[], metavar="PATH", dest="coverage_source", help="Measure coverage for filesystem path (multi-allowed)", ) group.add_argument( "--coverage-report", action="append", default=[], metavar="TYPE", choices=["term", "term-missing", "annotate", "html", "xml"], dest="coverage_report", help="Generate selected reports, available types:" " term, term-missing, annotate, html, xml (multi-allowed)", ) group.add_argument( "--coverage-config", action="store", default="", metavar="FILE", dest="coverage_config", help="Config file for coverage, default: .coveragerc", ) self.covController = None def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) self._mpmode = True def handleArgs(self, event): """Get our options in order command line, config file, hard coded.""" self.covSource = event.args.coverage_source or self.covSource self.covReport = event.args.coverage_report or self.covReport self.covConfig = event.args.coverage_config or self.covConfig def createTests(self, event): """Start coverage early to catch imported modules. Only called if active so, safe to just start without checking flags""" if event.handled: log.error( "createTests already handled -- " "coverage reporting will be inaccurate" ) else: log.debug("createTests not already handled. coverage should work") self._start_coverage() def beforeSummaryReport(self, event): """Only called if active so stop coverage and produce reports.""" if self.covController: self.covController.stop() # write to .coverage file # do this explicitly (instead of passing auto_data=True to # Coverage constructor) in order to not load an existing .coverage # this better imitates the behavior of invoking `coverage` from the # command-line, which sets `Coverage._auto_save` (triggers atexit # saving to this file), but not `Coverage._auto_load` # requesting a better fix in nedbat/coveragepy#34 self.covController.save() if self._mpmode: self.covController.combine(strict=True) percent_coverage = None if "term" in self.covReport or "term-missing" in self.covReport: # only pass `show_missing` if "term-missing" was given # otherwise, just allow coverage to load show_missing from # config kwargs = {} if "term-missing" in self.covReport: kwargs["show_missing"] = True percent_coverage = self.covController.report( file=self.error_output_buffer, **kwargs ) if "annotate" in self.covReport: percent_coverage = self.covController.annotate() if "html" in self.covReport: percent_coverage = self.covController.html_report() if "xml" in self.covReport: percent_coverage = self.covController.xml_report() fail_under = self.covController.get_option("report:fail_under") if ( fail_under is not None and percent_coverage is not None and fail_under > percent_coverage ): self.decided_failure = True def startSubprocess(self, event): self._mpmode = True self._subprocess = True self._start_coverage() def stopSubprocess(self, event): self.covController.stop() self.covController.save() def wasSuccessful(self, event): """Mark full test run as successful or unsuccessful""" if self.decided_failure: event.success = False def afterSummaryReport(self, event): """Reporting data is collected, failure status determined and set. Now print any buffered error output saved from beforeSummaryReport""" print(self.error_output_buffer.getvalue(), file=event.stream) def _start_coverage(self): try: import coverage except ImportError: print( 'Warning: you need to install "coverage_plugin" ' "extra requirements to use this plugin. " "e.g. `pip install nose2[coverage_plugin]`" ) return self.covController = coverage.Coverage( source=self.covSource, config_file=self.covConfig, data_suffix=self._mpmode ) # Call erase() to remove old files. This is important in multiprocess # mode, where per-process coverage files are unlikely to be # overwritten. self.covController.erase() # start immediately (don't wait until startTestRun) so that coverage # will pick up on things which happen at import time self.covController.start() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/plugins/debugger.py0000664002342000234200000000340014264464446017464 0ustar00sirosensirosen""" Start a :func:`pdb.post_mortem` on errors and failures. This plugin implements :func:`testOutcome` and will drop into pdb whenever it sees a test outcome that includes exc_info. It fires :func:`beforeInteraction` before launching pdb and :func:`afterInteraction` after. Other plugins may implement :func:`beforeInteraction` to return ``False`` and set ``event.handled`` to prevent this plugin from launching pdb. """ import logging import pdb from nose2 import events __unittest = True log = logging.getLogger(__name__) class Debugger(events.Plugin): """Enter pdb on test error or failure .. attribute :: pdb For ease of mocking and using different pdb implementations, pdb is aliased as a class attribute. """ configSection = "debugger" commandLineSwitch = ("D", "debugger", "Enter pdb on test fail or error") # allow easy mocking and replacement of pdb pdb = pdb def __init__(self): self.errorsOnly = self.config.as_bool("errors-only", default=False) def testOutcome(self, event): """Drop into pdb on unexpected errors or failures""" if not event.exc_info or event.expected: # skipped tests, unexpected successes, expected failures return value, tb = event.exc_info[1:] test = event.test if self.errorsOnly and isinstance(value, test.failureException): return evt = events.UserInteractionEvent() result = self.session.hooks.beforeInteraction(evt) try: if not result and evt.handled: log.warning("Skipping pdb for %s, user interaction not allowed", event) return self.pdb.post_mortem(tb) finally: self.session.hooks.afterInteraction(evt) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/doctests.py0000664002342000234200000000334214176405443017527 0ustar00sirosensirosen""" Load tests from doctests. This plugin implements :func:`handleFile` to load doctests from text files and python modules. To disable loading doctests from text files, configure an empty extensions list: .. code-block :: ini [doctest] extensions = """ import doctest import os from nose2 import util from nose2.events import Plugin __unittest = True class DocTestLoader(Plugin): configSection = "doctest" commandLineSwitch = ( None, "with-doctest", "Load doctests from text files and modules", ) def __init__(self): self.extensions = self.config.as_list("extensions", [".txt", ".rst"]) def handleFile(self, event): """Load doctests from text files and modules""" path = event.path _root, ext = os.path.splitext(path) if ext in self.extensions: suite = doctest.DocFileTest(path, module_relative=False) event.extraTests.append(suite) return elif not util.valid_module_name(os.path.basename(path)): return name, package_path = util.name_from_path(path) # ignore top-level setup.py which cannot be imported if name == "setup": return util.ensure_importable(package_path) try: module = util.module_from_name(name) except Exception: # XXX log warning here? return if hasattr(module, "__test__") and not module.__test__: return try: suite = doctest.DocTestSuite(module) except ValueError: # with python <= 3.5, doctest, very annoyingly, raises ValueError # when a module has no tests. return event.extraTests.append(suite) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/dundertest.py0000664002342000234200000000160014176405443020053 0ustar00sirosensirosen""" This plugin implements :func:`startTestRun`, which excludes all test objects that define a ``__test__`` attribute that evaluates to ``False``. """ from unittest import TestSuite from nose2 import events __unittest = True class DunderTestFilter(events.Plugin): """ Exclude all tests defining a ``__test__`` attribute that evaluates to ``False``. """ alwaysOn = True def startTestRun(self, event): """ Recurse :attr:`event.suite` and remove all test suites and test cases that define a ``__test__`` attribute that evaluates to ``False``. """ self.removeNonTests(event.suite) def removeNonTests(self, suite): for test in list(suite): if not getattr(test, "__test__", True): suite._tests.remove(test) elif isinstance(test, TestSuite): self.removeNonTests(test) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/failfast.py0000664002342000234200000000142714176405443017472 0ustar00sirosensirosen""" Stop the test run after the first error or failure. This plugin implements :func:`testOutcome` and sets ``event.result.shouldStop`` if it sees an outcome with exc_info that is not expected. """ from nose2 import events __unittest = True class FailFast(events.Plugin): """Stop the test run after error or failure""" commandLineSwitch = ( "F", "fail-fast", "Stop the test run after the first error or failure", ) def resultCreated(self, event): """Mark new result""" if hasattr(event.result, "failfast"): event.result.failfast = True def testOutcome(self, event): """Stop on unexpected error or failure""" if event.exc_info and not event.expected: event.result.shouldStop = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657941893.0 nose2-0.12.0/nose2/plugins/junitxml.py0000664002342000234200000003056614264427605017563 0ustar00sirosensirosen""" Output test reports in junit-xml format. This plugin implements :func:`startTest`, :func:`testOutcome` and :func:`stopTestRun` to compile and then output a test report in junit-xml format. By default, the report is written to a file called ``nose2-junit.xml`` in the current working directory. You can configure the output filename by setting ``path`` in a ``[junit-xml]`` section in a config file. Unicode characters which are invalid in XML 1.0 are replaced with the ``U+FFFD`` replacement character. In the case that your software throws an error with an invalid byte string. By default, the ranges of discouraged characters are replaced as well. This can be changed by setting the ``keep_restricted`` configuration variable to ``True``. By default, the arguments of parametrized and generated tests are not printed. For instance, the following code: .. code-block:: python # a.py from nose2 import tools def test_gen(): def check(a, b): assert a == b, '{}!={}'.format(a,b) yield check, 99, 99 yield check, -1, -1 @tools.params('foo', 'bar') def test_params(arg): assert arg in ['foo', 'bar', 'baz'] Produces this XML by default: .. code-block:: xml But if ``test_fullname`` is ``True``, then the following XML is produced: .. code-block:: xml """ # Based on unittest2/plugins/junitxml.py, # which is itself based on the junitxml plugin from py.test import datetime import json import os.path import re import sys import time from xml.etree import ElementTree as ET from nose2 import events, result, util from nose2._vendor import six __unittest = True class JUnitXmlReporter(events.Plugin): """Output junit-xml test report to file""" configSection = "junit-xml" commandLineSwitch = ("X", "junit-xml", "Generate junit-xml output report") def __init__(self): # Read argument from configuration file, or filled with default self.path = os.path.realpath( self.config.as_str("path", default="nose2-junit.xml") ) self.keep_restricted = self.config.as_bool("keep_restricted", default=False) self.test_properties = self.config.as_str("test_properties", default=None) self.test_fullname = self.config.as_bool("test_fullname", default=False) if self.test_properties is not None: self.test_properties_path = os.path.realpath(self.test_properties) self.errors = 0 self.failed = 0 self.skipped = 0 self.numtests = 0 self.tree = ET.Element("testsuite") self._start = None # Allow user to override certain option from command line group = self.session.pluginargs group.add_argument( "--junit-xml-path", action="store", default="", metavar="FILE", dest="path", help="Output XML filename", ) def handleArgs(self, event): """Read option from command line and override the value in config file when necessary""" if event.args.path: # register if `--junit-xml-path` is given # this avoids a situation in which a plugin-related option is given # but the plugin isn't activated, which can be confusing (see #521) self.register() self.path = os.path.realpath(event.args.path) def startTest(self, event): """Count test, record start time""" self.numtests += 1 self._start = event.startTime def testOutcome(self, event): """Add test outcome to xml tree""" test = event.test testid_lines = test.id().split("\n") testid = testid_lines[0] parts = testid.split(".") classname = ".".join(parts[:-1]) method = parts[-1] # for generated test cases if len(testid_lines) > 1 and self.test_fullname: test_args = ":".join(testid_lines[1:]) method = "%s (%s)" % (method, test_args) # subtests do not report success if event.outcome == result.SUBTEST and event.exc_info is None: return testcase = ET.SubElement(self.tree, "testcase") testcase.set("timestamp", self._iso_timestamp()) testcase.set("time", "%.6f" % self._time()) if not classname: classname = test.__module__ testcase.set("classname", classname) testcase.set("name", method) msg = "" if event.exc_info: msg = util.exc_info_to_string(event.exc_info, test) elif event.reason: msg = event.reason msg = string_cleanup(msg, self.keep_restricted) if event.outcome == result.ERROR: self.errors += 1 error = ET.SubElement(testcase, "error") error.set("message", "test failure") error.text = msg elif event.outcome == result.FAIL and not event.expected: self.failed += 1 failure = ET.SubElement(testcase, "failure") failure.set("message", "test failure") failure.text = msg elif event.outcome == result.PASS and not event.expected: self.skipped += 1 skipped = ET.SubElement(testcase, "skipped") skipped.set("message", "test passes unexpectedly") elif event.outcome == result.SKIP: self.skipped += 1 skipped = ET.SubElement(testcase, "skipped") if msg: skipmsg = "test skipped" if event.reason: skipmsg = "test skipped: {}".format(event.reason) skipped.set("message", skipmsg) skipped.text = msg elif event.outcome == result.FAIL and event.expected: self.skipped += 1 skipped = ET.SubElement(testcase, "skipped") skipped.set("message", "expected test failure") skipped.text = msg elif event.outcome == result.SUBTEST: if issubclass(event.exc_info[0], event.test.failureException): self.failed += 1 failure = ET.SubElement(testcase, "failure") failure.set("message", "test failure") failure.text = msg else: self.errors += 1 error = ET.SubElement(testcase, "error") error.set("message", "test failure") error.text = msg system_out = ET.SubElement(testcase, "system-out") system_out.text = string_cleanup( "\n".join(event.metadata.get("logs", "")), self.keep_restricted ) def _check(self): if not os.path.exists(os.path.dirname(self.path)): raise IOError( 2, "JUnitXML: Parent folder does not exist for file", self.path ) if self.test_properties is not None: if not os.path.exists(self.test_properties_path): raise IOError( 2, "JUnitXML: Properties file does not exist", self.test_properties_path, ) def stopTestRun(self, event): """Output xml tree to file""" self.tree.set("name", "nose2-junit") self.tree.set("errors", str(self.errors)) self.tree.set("failures", str(self.failed)) self.tree.set("skipped", str(self.skipped)) self.tree.set("tests", str(self.numtests)) self.tree.set("time", "%.3f" % event.timeTaken) self._check() self._include_test_properties() self._indent_tree(self.tree) output = ET.ElementTree(self.tree) output.write(self.path, encoding="utf-8") def _include_test_properties(self): """Include test properties in xml tree""" if self.test_properties is None: return props = {} with open(self.test_properties_path) as data: try: props = json.loads(data.read()) except ValueError: raise ValueError( "JUnitXML: could not decode file: '%s'" % self.test_properties_path ) properties = ET.SubElement(self.tree, "properties") for key, val in props.items(): prop = ET.SubElement(properties, "property") prop.set("name", key) prop.set("value", val) def _indent_tree(self, elem, level=0): """In-place pretty formatting of the ElementTree structure.""" i = "\n" + level * " " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: self._indent_tree(elem, level + 1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def _time(self): try: return time.time() - self._start except Exception: pass finally: self._start = None return 0 def _iso_timestamp(self): # in some cases, `self._start` is still None when this runs, convert to 0 # see: https://github.com/nose-devs/nose2/pull/505 timestamp = self._start or 0 return str(datetime.datetime.utcfromtimestamp(timestamp).isoformat()) # # xml utility functions # # etree outputs XML 1.0 so the 1.1 Restricted characters are invalid. # and there are no characters that can be given as entities aside # form & < > ' " which ever have to be escaped (etree handles these fine) ILLEGAL_RANGES = [ (0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), (0xD800, 0xDFFF), (0xFFFE, 0xFFFF), ] # 0xD800 thru 0xDFFF are technically invalid in UTF-8 but PY2 will encode # bytes into these but PY3 will do a replacement # Other non-characters which are not strictly forbidden but # discouraged. RESTRICTED_RANGES = [(0x7F, 0x84), (0x86, 0x9F), (0xFDD0, 0xFDDF)] # check for a wide build if sys.maxunicode > 0xFFFF: RESTRICTED_RANGES += [ (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF), ] ILLEGAL_REGEX_STR = ( six.u("[") + six.u("").join( ["%s-%s" % (six.unichr(l), six.unichr(h)) for (l, h) in ILLEGAL_RANGES] ) + six.u("]") ) RESTRICTED_REGEX_STR = ( six.u("[") + six.u("").join( ["%s-%s" % (six.unichr(l), six.unichr(h)) for (l, h) in RESTRICTED_RANGES] ) + six.u("]") ) _ILLEGAL_REGEX = re.compile(ILLEGAL_REGEX_STR, re.U) _RESTRICTED_REGEX = re.compile(RESTRICTED_REGEX_STR, re.U) def string_cleanup(string, keep_restricted=False): if not issubclass(type(string), six.text_type): string = six.text_type(string, encoding="utf-8", errors="replace") string = _ILLEGAL_REGEX.sub(six.u("\uFFFD"), string) if not keep_restricted: string = _RESTRICTED_REGEX.sub(six.u("\uFFFD"), string) return string ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/plugins/layers.py0000664002342000234200000002226214220574143017172 0ustar00sirosensirosenimport logging import re from collections import OrderedDict from nose2 import events, exceptions, util from nose2._vendor import six from nose2.suite import LayerSuite BRIGHT = r"\033[1m" RESET = r"\033[0m" __unittest = True log = logging.getLogger(__name__) class MissingParentLayer(Exception): pass class Layers(events.Plugin): alwaysOn = True def startTestRun(self, event): event.suite = self.make_suite(event.suite, self.session.testLoader.suiteClass) def get_layers_from_suite(self, suite, suiteClass): top_layer = suiteClass() layers_dict = OrderedDict() for test in self.flatten_suite(suite): layer = getattr(test, "layer", None) if layer: if layer not in layers_dict: layers_dict[layer] = LayerSuite(self.session, layer=layer) layers_dict[layer].addTest(test) else: top_layer.addTest(test) self.get_parent_layers(layers_dict) return top_layer, layers_dict def get_parent_layers(self, layers_dict): while True: missing_parents = [] for layer in layers_dict.keys(): for parent in layer.__bases__: if parent is object: continue if parent not in layers_dict: missing_parents.append(parent) if not missing_parents: break for parent in missing_parents: layers_dict[parent] = LayerSuite(self.session, layer=parent) def make_suite(self, suite, suiteClass): top_layer, layers_dict = self.get_layers_from_suite(suite, suiteClass) tree = {} unresolved_layers = self.update_layer_tree(tree, layers_dict.keys()) while unresolved_layers: remaining = self.update_layer_tree(tree, unresolved_layers) if len(remaining) == len(unresolved_layers): raise exceptions.LoadTestsFailure( "Could not resolve layer dependencies" ) unresolved_layers = remaining for layer in tree.keys(): if layer and layer not in layers_dict: layers_dict[layer] = LayerSuite(self.session, layer=layer) self.tree_to_suite(tree, None, top_layer, layers_dict) return top_layer @classmethod def update_layer_tree(cls, tree, layers): remaining = [] for layer in layers: try: cls.add_layer_to_tree(tree, layer) except MissingParentLayer: remaining.append(layer) return remaining @classmethod def insert_mixins(cls, tree, layer, outer): mixins = getattr(layer, "mixins", None) if not mixins: return outer last = outer for mixin in mixins: mixin_ancestor = cls.get_oldest_parent(mixin) if last is None: tree.setdefault(None, []).append(mixin_ancestor) else: # The mixin_ancestor can be a layer that has been added to the # tree already. If so, it should a base layer, since it's the # last ancestor. We need to remove it from there, and insert it # in the "last" layer. if mixin_ancestor in tree[None]: tree[None].remove(mixin_ancestor) tree[last].append(mixin_ancestor) if mixin_ancestor not in tree: tree[mixin_ancestor] = [] if mixin not in tree: tree[mixin] = [] last = mixin return last @classmethod def insert_layer(cls, tree, layer, outer): if outer is object: outer = cls.insert_mixins(tree, layer, None) elif outer in tree: outer = cls.insert_mixins(tree, layer, outer) else: err = "{0} not found in {1}".format(outer, tree) raise exceptions.LoadTestsFailure(err) if outer is None: tree.setdefault(None, []).append(layer) else: tree[outer].append(layer) tree[layer] = [] @staticmethod def get_parents_from_tree(layer, tree): parents = [] for key, value in tree.items(): if layer in value: parents.append(key) @classmethod def get_oldest_parent(cls, layer): # FIXME: we assume that there is only one oldest parent # it should be the case most of the time but it will break sometimes. oldest = True for parent in layer.__bases__: if parent in [None, object]: continue else: oldest = False return cls.get_oldest_parent(parent) if oldest: return layer @classmethod def add_layer_to_tree(cls, tree, layer): parents = layer.__bases__ if not parents: err = "Invalid layer {0}: should at least inherit from `object`" raise exceptions.LoadTestsFailure(err.format(layer)) for parent in parents: if parent not in tree and parent is not object: raise MissingParentLayer() # if we reached that point, then all the parents are in the tree # if there are multiple parents, we first try to get the closest # to the current layer. for parent in parents: if not cls.get_parents_from_tree(parent, tree): cls.insert_layer(tree, layer, parent) return raise exceptions.LoadTestsFailure("Failed to add {0}".format(layer)) @classmethod def tree_to_suite(cls, tree, key, suite, layers): _suite = layers.get(key, None) if _suite: suite.addTest(_suite) suite = _suite sublayers = tree.get(key, []) # ensure that layers with a set order are in order sublayers.sort(key=cls.get_layer_position) for layer in sublayers: cls.tree_to_suite(tree, layer, suite, layers) @classmethod def flatten_suite(cls, suite): out = [] for test in suite: try: out.extend(cls.flatten_suite(test)) except TypeError: out.append(test) return out @staticmethod def get_layer_position(layer): pos = getattr(layer, "position", None) # ... lame if pos is not None: key = six.u("%04d") % pos else: key = layer.__name__ return key class LayerReporter(events.Plugin): commandLineSwitch = ( None, "layer-reporter", "Add layer information to test reports", ) configSection = "layer-reporter" def __init__(self): self.indent = self.config.as_str("indent", " ") self.colors = self.config.as_bool("colors", False) self.highlight_words = self.config.as_list( "highlight-words", ["A", "having", "should"] ) self.highlight_re = re.compile(r"\b(%s)\b" % "|".join(self.highlight_words)) self.layersReported = set() def reportStartTest(self, event): if self.session.verbosity < 2: return test = event.testEvent.test layer = getattr(test, "layer", None) if not layer: return for ix, lys in enumerate(util.ancestry(layer)): for layer in lys: if layer not in self.layersReported: desc = self.describeLayer(layer) event.stream.writeln("%s%s" % (self.indent * ix, desc)) self.layersReported.add(layer) event.stream.write(self.indent * (ix + 1)) def describeLayer(self, layer): return self.format(getattr(layer, "description", layer.__name__)) def format(self, st): if self.colors: return self.highlight_re.sub(r"%s\1%s" % (BRIGHT, RESET), st) return st def describeTest(self, event): if hasattr(event.test, "methodDescription"): event.description = self.format(event.test.methodDescription()) if event.errorList and hasattr(event.test, "layer"): # walk back layers to build full description self.describeLayers(event) # we need to remove "\n" from description to keep a well indented report when # tests have docstrings # see https://github.com/nose-devs/nose2/issues/327 for more information event.description = event.description.replace("\n", " ") def describeLayers(self, event): desc = [event.description] base = event.test.layer for layer in base.__mro__ + getattr(base, "mixins", ()): if layer is object: continue desc.append(self.describeLayer(layer)) desc.reverse() event.description = " ".join(desc) # for debugging # def printtree(suite, indent=''): # import unittest # six.print_('%s%s ->' % (indent, getattr(suite, 'layer', 'no layer'))) # for test in suite: # if isinstance(test, unittest.BaseTestSuite): # printtree(test, indent + ' ') # else: # six.print_('%s %s' % (indent, test)) # six.print_('%s<- %s' % (indent, getattr(suite, 'layer', 'no layer'))) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9994316 nose2-0.12.0/nose2/plugins/loader/0000775002342000234200000000000014264564615016576 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/plugins/loader/__init__.py0000664002342000234200000000000013365700060020660 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/discovery.py0000664002342000234200000002240314176405443021153 0ustar00sirosensirosen""" Discovery-based test loader. This plugin implements nose2's automatic test module discovery. It looks for test modules in packages and directories whose names start with ``test``, then fires the :func:`loadTestsFromModule` hook for each one to allow other plugins to load the actual tests. It also fires :func:`handleFile` for every file that it sees, and :func:`matchPath` for every Python module, to allow other plugins to load tests from other kinds of files and to influence which modules are examined for tests. """ # Adapted from unittest2/loader.py from the unittest2 plugins branch. # This module contains some code copied from unittest2/loader.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import logging import os import sys from fnmatch import fnmatch from nose2 import events, util __unittest = True log = logging.getLogger(__name__) class DirectoryHandler(object): def __init__(self, session): self.session = session self.event_handled = False def handle_dir(self, event, full_path, top_level): dirname = os.path.basename(full_path) pattern = self.session.testFilePattern evt = events.HandleFileEvent( event.loader, dirname, full_path, pattern, top_level ) result = self.session.hooks.handleDir(evt) if evt.extraTests: for test in evt.extraTests: yield test if evt.handled: if result: yield result self.event_handled = True return evt = events.MatchPathEvent(dirname, full_path, pattern) result = self.session.hooks.matchDirPath(evt) if evt.handled and not result: self.event_handled = True class Discoverer(object): def loadTestsFromName(self, event): """Load tests from module named by event.name""" # turn name into path or module name # fire appropriate hooks (handle file or load from module) if event.module: return name = event.name module = None _, top_level_dir = self._getStartDirs() try: # try name as a dotted module name first __import__(name) module = sys.modules[name] except (KeyboardInterrupt, SystemExit): raise except BaseException: # if that fails, try it as a file or directory event.extraTests.extend(self._find_tests(event, name, top_level_dir)) else: event.extraTests.extend( self._find_tests_in_module(event, module, top_level_dir) ) def loadTestsFromNames(self, event): """Discover tests if no test names specified""" log.debug("Received event %s", event) if event.names or event.module: return event.handled = True # I will handle discovery return self._discover(event) def _checkIfPathIsOK(self, start_dir): if not os.path.isdir(os.path.abspath(start_dir)): raise OSError("%s is not a directory" % os.path.abspath(start_dir)) def _getStartDirs(self): start_dir = self.session.startDir top_level_dir = self.session.topLevelDir if start_dir is None: start_dir = "." if top_level_dir is None: top_level_dir = start_dir self._checkIfPathIsOK(start_dir) is_not_importable = False start_dir = os.path.abspath(start_dir) top_level_dir = os.path.abspath(top_level_dir) if start_dir != top_level_dir: is_not_importable = not os.path.isfile( os.path.join(start_dir, "__init__.py") ) if is_not_importable: raise ImportError("Start directory is not importable: %r" % start_dir) # this is redundant in some cases, but that's ok self.session.prepareSysPath() return start_dir, top_level_dir def _discover(self, event): loader = event.loader try: start_dir, top_level_dir = self._getStartDirs() except (OSError, ImportError): return loader.suiteClass( loader.failedLoadTests(self.session.startDir, sys.exc_info()) ) log.debug("_discover in %s (%s)", start_dir, top_level_dir) tests = list(self._find_tests(event, start_dir, top_level_dir)) return loader.suiteClass(tests) def _find_tests(self, event, start, top_level): """Used by discovery. Yields test suites it loads.""" log.debug("_find_tests(%r, %r)", start, top_level) if start == top_level: full_path = start else: full_path = os.path.join(top_level, start) if os.path.isdir(start): for test in self._find_tests_in_dir(event, full_path, top_level): yield test elif os.path.isfile(start): for test in self._find_tests_in_file(event, start, full_path, top_level): yield test def _find_tests_in_dir(self, event, full_path, top_level): if not os.path.isdir(full_path): return log.debug("find in dir %s (%s)", full_path, top_level) dir_handler = DirectoryHandler(self.session) for test in dir_handler.handle_dir(event, full_path, top_level): yield test if dir_handler.event_handled: return for path in os.listdir(full_path): entry_path = os.path.join(full_path, path) if os.path.isfile(entry_path): for test in self._find_tests_in_file( event, path, entry_path, top_level ): yield test elif os.path.isdir(entry_path): if ( "test" in path.lower() or util.ispackage(entry_path) or path in self.session.libDirs ): for test in self._find_tests(event, entry_path, top_level): yield test def _find_tests_in_file( self, event, filename, full_path, top_level, module_name=None ): log.debug("find in file %s (%s)", full_path, top_level) pattern = self.session.testFilePattern loader = event.loader evt = events.HandleFileEvent(loader, filename, full_path, pattern, top_level) result = self.session.hooks.handleFile(evt) if evt.extraTests: yield loader.suiteClass(evt.extraTests) if evt.handled: if result: yield result return if not util.valid_module_name(filename): # valid Python identifiers only return evt = events.MatchPathEvent(filename, full_path, pattern) result = self.session.hooks.matchPath(evt) if evt.handled: if not result: return elif not self._match_path(filename, full_path, pattern): return if module_name is None: module_name, package_path = util.name_from_path(full_path) util.ensure_importable(package_path) try: module = util.module_from_name(module_name) except BaseException: yield loader.failedImport(module_name) else: mod_file = os.path.abspath(getattr(module, "__file__", full_path)) realpath = os.path.splitext(mod_file)[0] fullpath_noext = os.path.splitext(full_path)[0] if realpath.lower() != fullpath_noext.lower(): module_dir = os.path.dirname(realpath) mod_name = os.path.splitext(os.path.basename(full_path))[0] expected_dir = os.path.dirname(full_path) msg = ( "%r module incorrectly imported from %r. " "Expected %r. Is this module globally installed?" ) raise ImportError(msg % (mod_name, module_dir, expected_dir)) yield loader.loadTestsFromModule(module) def _find_tests_in_module(self, event, module, top_level_dir): # only called from loadTestsFromName yield event.loader.loadTestsFromModule(module) # may be a package; recurse into __path__ if so pkgpath = getattr(module, "__path__", None) if pkgpath: for entry in pkgpath: full_path = os.path.abspath(os.path.join(top_level_dir, entry)) for test in self._find_tests_in_dir(event, full_path, top_level_dir): yield test def _match_path(self, path, full_path, pattern): # override this method to use alternative matching strategy return fnmatch(path, pattern) class DiscoveryLoader(events.Plugin, Discoverer): """Loader plugin that can discover tests""" alwaysOn = True configSection = "discovery" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def loadTestsFromName(self, event): """Load tests from module named by event.name""" return Discoverer.loadTestsFromName(self, event) def loadTestsFromNames(self, event): """Discover tests if no test names specified""" return Discoverer.loadTestsFromNames(self, event) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/eggdiscovery.py0000664002342000234200000000641514176405443021643 0ustar00sirosensirosen""" Egg-based discovery test loader. This plugin implements nose2's automatic test module discovery inside Egg Files. It looks for test modules in packages whose names start with ``test``, then fires the :func:`loadTestsFromModule` hook for each one to allow other plugins to load the actual tests. It also fires :func:`handleFile` for every file that it sees, and :func:`matchPath` for every Python module, to allow other plugins to load tests from other kinds of files and to influence which modules are examined for tests. """ import logging import os from nose2 import events from nose2.plugins.loader import discovery __unittest = True log = logging.getLogger(__name__) try: import pkg_resources except ImportError: pkg_resources = None class EggDiscoveryLoader(events.Plugin, discovery.Discoverer): """Loader plugin that can discover tests inside Egg Files""" alwaysOn = True configSection = "discovery" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def loadTestsFromName(self, event): """Load tests from module named by event.name""" return discovery.Discoverer.loadTestsFromName(self, event) def loadTestsFromNames(self, event): """Discover tests if no test names specified""" return discovery.Discoverer.loadTestsFromNames(self, event) def _checkIfPathIsOK(self, start_dir): if not os.path.exists(os.path.abspath(start_dir)): raise OSError("%s does not exist" % os.path.abspath(start_dir)) def _find_tests_in_egg_dir(self, event, rel_path, dist): log.debug( "find in egg dir %s %s (%s)", dist.location, rel_path, dist.project_name ) full_path = os.path.join(dist.location, rel_path) dir_handler = discovery.DirectoryHandler(self.session) for test in dir_handler.handle_dir(event, full_path, dist.location): yield test if dir_handler.event_handled: return for path in dist.resource_listdir(rel_path): # on setuptools==38.2.5 , resource_listdir() can yield "" # if that happens, skip processing it to avoid infinite recursion if path == "": continue entry_path = os.path.join(rel_path, path) if dist.resource_isdir(entry_path): for test in self._find_tests_in_egg_dir(event, entry_path, dist): yield test else: modname = os.path.splitext(entry_path)[0].replace(os.sep, ".") for test in self._find_tests_in_file( event, path, os.path.join(dist.location, entry_path), dist.location, modname, ): yield test def _find_tests_in_dir(self, event, full_path, top_level): if os.path.exists(full_path): return elif pkg_resources and full_path.find(".egg") != -1: egg_path = full_path.split(".egg")[0] + ".egg" for dist in pkg_resources.find_distributions(egg_path): for modname in dist._get_metadata("top_level.txt"): for test in self._find_tests_in_egg_dir(event, modname, dist): yield test ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/functions.py0000664002342000234200000001074614176405443021163 0ustar00sirosensirosen""" Load tests from test functions in modules. This plugin responds to :func:`loadTestsFromModule` by adding test cases for all test functions in the module to ``event.extraTests``. It uses ``session.testMethodPrefix`` to find test functions. Functions that are generators, have param lists, or take arguments are not collected. This plugin also implements :func:`loadTestsFromName` to enable loading tests from dotted function names passed on the command line. Fixtures -------- Test functions can specify setup and teardown fixtures as attributes on the function, for example: .. code :: python x = 0 def test(): assert x def setup(): global x x = 1 def teardown(): global x x = 1 test.setup = setup test.teardown = teardown The setup attribute may be named ``setup``, ``setUp`` or ``setUpFunc``. The teardown attribute may be named ``teardown``, ``tearDown`` or ``tearDownFunc``. Other attributes ---------------- The other significant attribute that may be set on a test function is ``paramList``. When ``paramList`` is set, the function will be collected by the :doc:`parameterized test loader `. The easiest way to set ``paramList`` is with the :func:`nose2.tools.params` decorator. """ # This module contains some code copied from unittest2/ and other code # developed in reference to unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import sys import types import unittest from nose2 import util from nose2.events import Plugin __unittest = True class Functions(Plugin): """Loader plugin that loads test functions""" alwaysOn = True configSection = "functions" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def loadTestsFromName(self, event): """Load test if event.name is the name of a test function""" name = event.name module = event.module try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: return parent, obj, name, index = result if ( isinstance(obj, types.FunctionType) and not isinstance(parent, type) and not util.isgenerator(obj) and not hasattr(obj, "paramList") and util.num_expected_args(obj) == 0 ): suite = event.loader.suiteClass() suite.addTests(self._createTests(obj)) event.handled = True return suite def loadTestsFromModule(self, event): """Load test functions from event.module""" module = event.module def is_test(obj): if not obj.__name__.startswith(self.session.testMethodPrefix): return False if util.num_expected_args(obj) > 0: return False return True tests = [] for name in dir(module): obj = getattr(module, name) if isinstance(obj, types.FunctionType) and is_test(obj): tests.extend(self._createTests(obj)) event.extraTests.extend(tests) def _createTests(self, obj): if not hasattr(obj, "setUp"): if hasattr(obj, "setup"): obj.setUp = obj.setup elif hasattr(obj, "setUpFunc"): obj.setUp = obj.setUpFunc if not hasattr(obj, "tearDown"): if hasattr(obj, "teardown"): obj.tearDown = obj.teardown elif hasattr(obj, "tearDownFunc"): obj.tearDown = obj.tearDownFunc tests = [] args = {} setUp = getattr(obj, "setUp", None) tearDown = getattr(obj, "tearDown", None) if setUp is not None: args["setUp"] = setUp if tearDown is not None: args["tearDown"] = tearDown paramList = getattr(obj, "paramList", None) isGenerator = util.isgenerator(obj) if paramList is not None or isGenerator: return tests else: case = util.transplant_class(FunctionTestCase, obj.__module__)(obj, **args) tests.append(case) return tests class FunctionTestCase(unittest.FunctionTestCase): def __repr__(self): return "%s.%s" % (self._testFunc.__module__, self._testFunc.__name__) id = __str__ = __repr__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/generators.py0000664002342000234200000002206414176405443021320 0ustar00sirosensirosen""" Load tests from generators. This plugin implements :func:`loadTestFromTestCase`, :func:`loadTestsFromName` and :func:`loadTestFromModule` to enable loading tests from generators. Generators may be functions or methods in test cases. In either case, they must yield a callable and arguments for that callable once for each test they generate. The callable and arguments may all be in one tuple, or the arguments may be grouped into a separate tuple:: def test_gen(): yield check, 1, 2 yield check, (1, 2) To address a particular generated test via a command-line test name, append a colon (':') followed by the index (*starting from 1*) of the generated case you want to execute. """ # This module contains some code copied from unittest2 and other code # developed in reference to unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import functools import logging import sys import types import unittest from nose2 import exceptions, util from nose2.events import Plugin log = logging.getLogger(__name__) __unittest = True class Generators(Plugin): """Loader plugin that loads generator tests""" alwaysOn = True configSection = "generators" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def unpack(self, generator): for index, func_args in enumerate(generator): try: func, args = func_args if not isinstance(args, tuple): args = (args,) yield index, (func, args) except ValueError: func, args = func_args[0], func_args[1:] yield index, (func, args) def loadTestsFromTestCase(self, event): """Load generator tests from test case""" log.debug("loadTestsFromTestCase %s", event.testCase) testCaseClass = event.testCase for name in dir(testCaseClass): method = getattr(testCaseClass, name) if ( name.startswith(self.session.testMethodPrefix) and hasattr(getattr(testCaseClass, name), "__call__") and util.isgenerator(method) ): instance = testCaseClass(name) event.extraTests.extend( self._testsFromGenerator( event, name, method(instance), testCaseClass ) ) def loadTestsFromTestClass(self, event): testCaseClass = event.testCase for name in dir(testCaseClass): method = getattr(testCaseClass, name) if ( name.startswith(self.session.testMethodPrefix) and hasattr(getattr(testCaseClass, name), "__call__") and util.isgenerator(method) ): instance = testCaseClass() event.extraTests.extend( self._testsFromGeneratorMethod(event, name, method, instance) ) def getTestCaseNames(self, event): """Get generator test case names from test case class""" log.debug("getTestCaseNames %s", event.testCase) names = filter(event.isTestMethod, dir(event.testCase)) klass = event.testCase for name in names: method = getattr(klass, name) if util.isgenerator(method): event.excludedNames.append(name) def getTestMethodNames(self, event): return self.getTestCaseNames(event) def loadTestsFromName(self, event): """Load tests from generator named on command line""" original_name = name = event.name module = event.module try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: # we can't find it - let the default case handle it return parent, obj, name, index = result if not util.isgenerator(obj): return if ( index is None and not isinstance(parent, type) and not isinstance(obj, types.FunctionType) ): log.debug("Don't know how to load generator tests from %s", obj) return if ( parent and isinstance(parent, type) and issubclass(parent, unittest.TestCase) ): # generator method in test case instance = parent(obj.__name__) tests = list( self._testsFromGenerator(event, obj.__name__, obj(instance), parent) ) elif parent and isinstance(parent, type): # generator method in test class method = obj instance = parent() tests = list(self._testsFromGeneratorMethod(event, name, method, instance)) else: # generator func tests = list(self._testsFromGeneratorFunc(event, obj)) if index is not None: try: tests = [tests[index - 1]] except IndexError: raise exceptions.TestNotFoundError(original_name) suite = event.loader.suiteClass() suite.addTests(tests) event.handled = True return suite def loadTestsFromModule(self, event): """Load tests from generator functions in a module""" module = event.module def is_test(obj): return obj.__name__.startswith( self.session.testMethodPrefix ) and util.isgenerator(obj) tests = [] for name in dir(module): obj = getattr(module, name) if isinstance(obj, types.FunctionType) and is_test(obj): tests.extend(self._testsFromGeneratorFunc(event, obj)) event.extraTests.extend(tests) def _testsFromGenerator(self, event, name, generator, testCaseClass): try: for index, (func, args) in self.unpack(generator): method_name = util.name_from_args(name, index, args) setattr(testCaseClass, method_name, None) instance = testCaseClass(method_name) delattr(testCaseClass, method_name) def method(func=func, args=args): return func(*args) method = functools.update_wrapper(method, func) setattr(instance, method_name, method) yield instance except Exception as e: test_name = "%s.%s.%s" % ( testCaseClass.__module__, testCaseClass.__name__, name, ) yield event.loader.failedLoadTests(test_name, e) def _testsFromGeneratorFunc(self, event, obj): extras = list(obj()) name = "%s.%s" % (obj.__module__, obj.__name__) args = {} setUp = getattr(obj, "setUp", None) tearDown = getattr(obj, "tearDown", None) if setUp is not None: args["setUp"] = setUp if tearDown is not None: args["tearDown"] = tearDown def createTest(name): return util.transplant_class(GeneratorFunctionCase, obj.__module__)( name, **args ) for test in self._testsFromGenerator(event, name, extras, createTest): yield test def _testsFromGeneratorMethod(self, event, name, method, instance): extras = list(method(instance)) name = "%s.%s.%s" % ( instance.__class__.__module__, instance.__class__.__name__, method.__name__, ) args = {} setUp = getattr(instance, "setUp", None) tearDown = getattr(instance, "tearDown", None) if setUp is not None: args["setUp"] = setUp if tearDown is not None: args["tearDown"] = tearDown def createTest(name): return util.transplant_class( GeneratorMethodCase(instance.__class__), instance.__class__.__module__ )(name, **args) for test in self._testsFromGenerator(event, name, extras, createTest): yield test class GeneratorFunctionCase(unittest.FunctionTestCase): def __init__(self, name, **args): self._funcName = name unittest.FunctionTestCase.__init__(self, None, **args) _testFunc = property( lambda self: getattr(self, self._funcName), lambda self, func: None ) def __repr__(self): return self._funcName id = __str__ = __repr__ def GeneratorMethodCase(cls): class _GeneratorMethodCase(GeneratorFunctionCase): if util.has_class_fixtures(cls): @classmethod def setUpClass(klass): if hasattr(cls, "setUpClass"): cls.setUpClass() @classmethod def tearDownClass(klass): if hasattr(cls, "tearDownClass"): cls.tearDownClass() # XXX retain original class name _GeneratorMethodCase.__name__ = cls.__name__ return _GeneratorMethodCase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/loadtests.py0000664002342000234200000000544014176405443021150 0ustar00sirosensirosen""" Loader that implements the ``load_tests`` protocol. This plugin implements the ``load_tests`` protocol as detailed in the documentation for :mod:`unittest2`. See the `load_tests protocol`_ documentation for more information. .. warning :: Test suites using the ``load_tests`` protocol do not work correctly with the :mod:`multiprocess` plugin as of nose2 04. This will be fixed in a future release. .. _load_tests protocol: http://docs.python.org/library/unittest.html#load-tests-protocol """ import logging from fnmatch import fnmatch from nose2 import events, util log = logging.getLogger(__name__) class LoadTestsLoader(events.Plugin): """Loader plugin that implements load_tests.""" alwaysOn = True configSection = "load_tests" _loading = False def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def moduleLoadedSuite(self, event): """Run ``load_tests`` in a module. May add to or filter tests loaded in module. """ module = event.module load_tests = getattr(module, "load_tests", None) if not load_tests: return try: event.suite = load_tests( event.loader, event.suite, self.session.testFilePattern ) except Exception as exc: log.exception("Failed to load tests from %s via load_tests", module) suite = event.loader.suiteClass() suite.addTest(event.loader.failedLoadTests(module.__name__, exc)) event.handled = True return suite def handleDir(self, event): """Run ``load_tests`` in packages. If a package itself matches the test file pattern, run ``load_tests`` in its :file:`__init__.py`, and stop default test discovery for that package. """ if self._loading: return if self._match(event.name, event.pattern) and util.ispackage(event.path): name, _package_path = util.name_from_path(event.path) module = util.module_from_name(name) load_tests = getattr(module, "load_tests", None) if not load_tests: return self._loading = True try: suite = event.loader.suiteClass() try: suite = load_tests(event.loader, suite, event.pattern) except Exception as exc: log.exception("Failed to load tests from %s via load_tests", module) suite.addTest(event.loader.failedLoadTests(module.__name__, exc)) event.handled = True return suite finally: self._loading = False def _match(self, filename, pattern): return fnmatch(filename, pattern) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/parameters.py0000664002342000234200000001552114176405443021312 0ustar00sirosensirosen""" Load tests from parameterized functions and methods. This plugin implements :func:`getTestCaseNames`, :func:`loadTestsFromModule`, and :func:`loadTestsFromName` to support loading tests from parameterized test functions and methods. To parameterize a function or test case method, use :func:`nose2.tools.params`. To address a particular parameterized test via a command-line test name, append a colon (':') followed by the index (*starting from 1*) of the case you want to execute. Such And The Parameters Plugin ------------------------------ The parameters plugin can work with the Such DSL, as long as the first argument of the test function is the "case" argument, followed by the other parameters:: from nose2.tools import such from nose2.tools.params import params with such.A('foo') as it: @it.should('do bar') @params(1,2,3) def test(case, bar): case.assertTrue(isinstance(bar, int)) @it.should('do bar and extra') @params((1, 2), (3, 4) ,(5, 6)) def testExtraArg(case, bar, foo): case.assertTrue(isinstance(bar, int)) case.assertTrue(isinstance(foo, int)) it.createTests(globals()) """ # This module contains some code copied from unittest2 and other code # developed in reference to unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import functools import logging import sys import types import unittest from nose2 import exceptions, util from nose2.events import Plugin from nose2.plugins.loader.testclasses import MethodTestCase log = logging.getLogger(__name__) __unittest = True class ParamsFunctionCase(unittest.FunctionTestCase): def __init__(self, name, func, **args): self._funcName = name unittest.FunctionTestCase.__init__(self, func, **args) def __repr__(self): return self._funcName id = __str__ = __repr__ class Parameters(Plugin): """Loader plugin that loads parameterized tests""" alwaysOn = True configSection = "parameters" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def getTestCaseNames(self, event): """Generate test case names for all parameterized methods""" log.debug("getTestCaseNames %s", event) names = filter(event.isTestMethod, dir(event.testCase)) testCaseClass = event.testCase for name in names: method = getattr(testCaseClass, name) paramList = getattr(method, "paramList", None) if paramList is None: continue # exclude this method from normal collection event.excludedNames.append(name) # generate the methods to be loaded by the testcase loader self._generate(event, name, method, testCaseClass) def getTestMethodNames(self, event): return self.getTestCaseNames(event) def loadTestsFromModule(self, event): """Load tests from parameterized test functions in the module""" module = event.module def is_test(obj): return obj.__name__.startswith(self.session.testMethodPrefix) and hasattr( obj, "paramList" ) tests = [] for name in dir(module): obj = getattr(module, name) if isinstance(obj, types.FunctionType) and is_test(obj): tests.extend(self._generateFuncTests(obj)) event.extraTests.extend(tests) def loadTestsFromName(self, event): """Load parameterized test named on command line""" original_name = name = event.name module = event.module try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: # we can't find it - let the default case handle it return parent, obj, fqname, index = result if not hasattr(obj, "paramList"): return if ( index is None and not isinstance(parent, type) and not isinstance(obj, types.FunctionType) ): log.debug("Don't know how to load parameterized tests from %s", obj) return if ( parent and isinstance(parent, type) and issubclass(parent, unittest.TestCase) ): # parameterized method in test case names = self._generate(event, obj.__name__, obj, parent) tests = [parent(n) for n in names] elif parent and isinstance(parent, type): # parameterized method in test class names = self._generate(event, obj.__name__, obj, parent) tests = [MethodTestCase(parent)(name) for name in names] else: # parameterized func tests = list(self._generateFuncTests(obj)) if index is not None: try: tests = [tests[index - 1]] except IndexError: raise exceptions.TestNotFoundError(original_name) suite = event.loader.suiteClass() suite.addTests(tests) event.handled = True return suite def _generate(self, event, name, method, testCaseClass): names = [] for index, argSet in enumerate_params(method.paramList): method_name = util.name_from_args(name, index, argSet) if not hasattr(testCaseClass, method_name): # not already generated def _method(self, method=method, argSet=argSet): return method(self, *argSet) _method = functools.update_wrapper(_method, method) delattr(_method, "paramList") setattr(testCaseClass, method_name, _method) names.append(method_name) return names def _generateFuncTests(self, obj): args = {} setUp = getattr(obj, "setUp", None) tearDown = getattr(obj, "tearDown", None) if setUp is not None: args["setUp"] = setUp if tearDown is not None: args["tearDown"] = tearDown for index, argSet in enumerate_params(obj.paramList): def func(argSet=argSet, obj=obj): return obj(*argSet) func = functools.update_wrapper(func, obj) delattr(func, "paramList") name = "%s.%s" % (obj.__module__, obj.__name__) func_name = util.name_from_args(name, index, argSet) yield util.transplant_class(ParamsFunctionCase, obj.__module__)( func_name, func, **args ) def enumerate_params(paramList): for index, argSet in enumerate(paramList): if not isinstance(argSet, tuple): argSet = (argSet,) yield index, argSet ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/loader/testcases.py0000664002342000234200000001025214176405443021141 0ustar00sirosensirosen""" Load tests from :class:`unittest.TestCase` subclasses. This plugin implements :func:`loadTestsFromName` and :func:`loadTestsFromModule` to load tests from :class:`unittest.TestCase` subclasses found in modules or named on the command line. """ # Adapted from unittest2/loader.py from the unittest2 plugins branch. # This module contains some code copied from unittest2/loader.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import logging import sys import unittest from nose2 import events, util __unittest = True log = logging.getLogger(__name__) class TestCaseLoader(events.Plugin): """Loader plugin that loads from test cases""" alwaysOn = True configSection = "testcases" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def loadTestsFromModule(self, event): """Load tests in :class:`unittest.TestCase` subclasses""" seen = set() module = event.module for name in dir(module): obj = getattr(module, name) if id(obj) in seen: continue seen.add(id(obj)) if isinstance(obj, type) and issubclass(obj, unittest.TestCase): event.extraTests.append(self._loadTestsFromTestCase(event, obj)) def loadTestsFromName(self, event): """Load tests from event.name if it names a test case/method""" name = event.name module = event.module log.debug("load %s from %s", name, module) try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: return parent, obj, name, index = result if isinstance(obj, type) and issubclass(obj, unittest.TestCase): # name is a test case class event.extraTests.append(self._loadTestsFromTestCase(event, obj)) elif ( isinstance(parent, type) and issubclass(parent, unittest.TestCase) and not util.isgenerator(obj) and not hasattr(obj, "paramList") ): # name is a single test method event.extraTests.append(parent(obj.__name__)) def _loadTestsFromTestCase(self, event, testCaseClass): evt = events.LoadFromTestCaseEvent(event.loader, testCaseClass) result = self.session.hooks.loadTestsFromTestCase(evt) if evt.handled: loaded_suite = result or event.loader.suiteClass() else: names = self._getTestCaseNames(event, testCaseClass) if not names and hasattr(testCaseClass, "runTest"): names = ["runTest"] # FIXME return failure test case if name not in testcase class loaded_suite = event.loader.suiteClass(map(testCaseClass, names)) if evt.extraTests: loaded_suite.addTests(evt.extraTests) return loaded_suite def _getTestCaseNames(self, event, testCaseClass): excluded = set() def isTestMethod(attrname, testCaseClass=testCaseClass, excluded=excluded): prefix = evt.testMethodPrefix or self.session.testMethodPrefix return ( attrname.startswith(prefix) and hasattr(getattr(testCaseClass, attrname), "__call__") and attrname not in excluded ) evt = events.GetTestCaseNamesEvent(event.loader, testCaseClass, isTestMethod) result = self.session.hooks.getTestCaseNames(evt) if evt.handled: test_names = result or [] else: excluded.update(evt.excludedNames) test_names = [entry for entry in dir(testCaseClass) if isTestMethod(entry)] if evt.extraNames: test_names.extend(evt.extraNames) sortkey = getattr( testCaseClass, "sortTestMethodsUsing", event.loader.sortTestMethodsUsing ) if sortkey: test_names.sort(key=sortkey) return test_names ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/plugins/loader/testclasses.py0000664002342000234200000002077414264464446021520 0ustar00sirosensirosenr""" Load tests from classes that are *not* :class:`unittest.TestCase` subclasses. This plugin responds to :func:`loadTestsFromModule` by adding test cases for test methods found in classes in the module that are *not* subclasses of :class:`unittest.TestCase`, but whose names (lowercased) match the configured test method prefix. Test class methods that are generators or have param lists are not loaded here, but by the :class:`nose2.plugins.loader.generators.Generators` and :class:`nose2.plugins.loader.parameters.Parameters` plugins. This plugin also implements :func:`loadTestsFromName` to enable loading tests from dotted class and method names passed on the command line. This plugin makes two additional plugin hooks available for other test loaders to use: .. function :: loadTestsFromTestClass(self, event) :param event: A :class:`LoadFromTestClassEvent` instance Plugins can use this hook to load tests from a class that is not a :class:`unittest.TestCase` subclass. To prevent other plugins from loading tests from the test class, set ``event.handled`` to ``True`` and return a test suite. Plugins can also append tests to ``event.extraTests``. Usually, that's what you want, since it allows other plugins to load their tests from the test case as well. .. function :: getTestMethodNames(self, event) :param event: A :class:`GetTestMethodNamesEvent` instance Plugins can use this hook to limit or extend the list of test case names that will be loaded from a class that is not a :class:`unittest.TestCase` subclass by the standard nose2 test loader plugins (and other plugins that respect the results of the hook). To force a specific list of names, set ``event.handled`` to ``True`` and return a list: this exact list will be the only test case names loaded from the test case. Plugins can also extend the list of names by appending test names to ``event.extraNames``, and exclude names by appending test names to ``event.excludedNames``. About Test Classes ------------------ Test classes are classes that look test-like but are not subclasses of :class:`unittest.TestCase`. Test classes support all of the same test types and fixtures as test cases. To "look test-like" a class must have a name that, lowercased, matches the configured test method prefix -- "test" by default. Test classes must also be able to be instantiated without arguments. What are they useful for? Mostly the case where a test class can't for some reason subclass :class:`unittest.TestCase`. Otherwise, test class tests and test cases are functionally equivalent in nose2, and test cases have broader support and all of those helpful *assert\** methods -- so when in doubt, you should use a :class:`unittest.TestCase`. Here's an example of a test class:: class TestSomething(object): def test(self): assert self.something(), "Something failed!" """ import sys import unittest from nose2 import events, util __unittest = True class TestClassLoader(events.Plugin): """Loader plugin that loads test functions""" alwaysOn = True configSection = "test-classes" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def register(self): """Install extra hooks Adds the new plugin hooks: - loadTestsFromTestClass - getTestMethodNames """ super(TestClassLoader, self).register() self.addMethods("loadTestsFromTestClass", "getTestMethodNames") def loadTestsFromModule(self, event): """Load test classes from event.module""" module = event.module for name in dir(module): obj = getattr(module, name) if ( isinstance(obj, type) and not issubclass(obj, unittest.TestCase) and not issubclass(obj, unittest.TestSuite) and name.lower().startswith(self.session.testMethodPrefix) ): event.extraTests.append(self._loadTestsFromTestClass(event, obj)) def loadTestsFromName(self, event): """Load tests from event.name if it names a test class/method""" name = event.name module = event.module try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: return parent, obj, name, index = result if isinstance(obj, type) and not issubclass(obj, unittest.TestCase): # name is a test case class event.extraTests.append(self._loadTestsFromTestClass(event, obj)) elif ( isinstance(parent, type) and not issubclass(parent, unittest.TestCase) and not util.isgenerator(obj) and not hasattr(obj, "paramList") ): # name is a single test method event.extraTests.append( util.transplant_class(MethodTestCase(parent), parent.__module__)( obj.__name__ ) ) def _loadTestsFromTestClass(self, event, cls): # ... fire event for others to load from evt = LoadFromTestClassEvent(event.loader, cls) result = self.session.hooks.loadTestsFromTestClass(evt) if evt.handled: loaded_suite = result or event.loader.suiteClass() else: names = self._getTestMethodNames(event, cls) try: loaded_suite = event.loader.suiteClass( [ util.transplant_class(MethodTestCase(cls), cls.__module__)(name) for name in names ] ) except BaseException: return event.loader.suiteClass( event.loader.failedLoadTests(cls.__name__, sys.exc_info()) ) if evt.extraTests: loaded_suite.addTests(evt.extraTests) # ... add extra tests return loaded_suite def _getTestMethodNames(self, event, cls): # ... give others a chance to modify list excluded = set() def isTestMethod(attrname, cls=cls, excluded=excluded): # FIXME allow plugs to change prefix prefix = self.session.testMethodPrefix return ( attrname.startswith(prefix) and hasattr(getattr(cls, attrname), "__call__") and attrname not in excluded ) evt = GetTestMethodNamesEvent(event.loader, cls, isTestMethod) result = self.session.hooks.getTestMethodNames(evt) if evt.handled: test_names = result or [] else: excluded.update(evt.excludedNames) test_names = [entry for entry in dir(cls) if isTestMethod(entry)] if event.loader.sortTestMethodsUsing: test_names.sort(key=event.loader.sortTestMethodsUsing) return test_names # to prevent unit2 discover from running this as a test, need to # hide it inside of a factory func. ugly! def MethodTestCase(cls): class _MethodTestCase(unittest.TestCase): def __init__(self, method): self.method = method self._name = "%s.%s.%s" % (cls.__module__, cls.__name__, method) self.obj = cls() unittest.TestCase.__init__(self, "runTest") if util.has_class_fixtures(cls): @classmethod def setUpClass(klass): if hasattr(cls, "setUpClass"): cls.setUpClass() @classmethod def tearDownClass(klass): if hasattr(cls, "tearDownClass"): cls.tearDownClass() def setUp(self): if hasattr(self.obj, "setUp"): self.obj.setUp() def tearDown(self): if hasattr(self.obj, "tearDown"): self.obj.tearDown() def __repr__(self): return self._name id = __str__ = __repr__ def runTest(self): getattr(self.obj, self.method)() def shortDescription(self): doc = getattr(self.obj, self.method).__doc__ return doc and doc.split("\n")[0].strip() or None return _MethodTestCase # # Event classes # class LoadFromTestClassEvent(events.LoadFromTestCaseEvent): """Bare subclass of :class:`nose2.events.LoadFromTestCaseEvent`""" class GetTestMethodNamesEvent(events.GetTestCaseNamesEvent): """Bare subclass of :class:`nose2.events.GetTestCaseNamesEvent`""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/logcapture.py0000664002342000234200000001354414176405443020051 0ustar00sirosensirosen""" Capture log messages during test execution, appending them to the error reports of failed tests. This plugin implements :func:`startTestRun`, :func:`startTest`, :func:`stopTest`, :func:`setTestOutcome`, and :func:`outcomeDetail` to set up a logging configuration that captures log messages during test execution, and appends them to error reports for tests that fail or raise exceptions. """ import logging import threading from logging.handlers import BufferingHandler from nose2.events import Plugin from nose2.util import ln, parse_log_level log = logging.getLogger(__name__) __unittest = True class LogCapture(Plugin): """Capture log messages during test execution""" configSection = "log-capture" commandLineSwitch = (None, "log-capture", "Enable log capture") logformat = "%(name)s: %(levelname)s: %(message)s" logdatefmt = None clear = False filters = ["-nose"] def __init__(self): self.logformat = self.config.as_str("format", self.logformat) self.logdatefmt = self.config.as_str("date-format", self.logdatefmt) self.filters = self.config.as_list("filter", self.filters) self.clear = self.config.as_bool("clear-handlers", self.clear) self.loglevel = parse_log_level(self.config.as_str("log-level", "NOTSET")) self.handler = MyMemoryHandler( 1000, self.logformat, self.logdatefmt, self.filters ) def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) def startSubprocess(self, event): self._setupLoghandler() def startTestRun(self, event): """Set up logging handler""" self._setupLoghandler() def startTest(self, event): """Set up handler for new test""" self._setupLoghandler() def setTestOutcome(self, event): """Store captured log messages in ``event.metadata``""" self._addCapturedLogs(event) def stopTest(self, event): """Clear captured messages, ready for next test""" self.handler.truncate() def outcomeDetail(self, event): """Append captured log messages to ``event.extraDetail``""" logs = event.outcomeEvent.metadata.get("logs", None) if logs: event.extraDetail.append(ln(">> begin captured logging <<")) event.extraDetail.extend(logs) event.extraDetail.append(ln(">> end captured logging <<")) def _setupLoghandler(self): # setup our handler with root logger root_logger = logging.getLogger() if self.clear: if hasattr(root_logger, "handlers"): for handler in root_logger.handlers: root_logger.removeHandler(handler) for logger in logging.Logger.manager.loggerDict.values(): if hasattr(logger, "handlers"): for handler in logger.handlers: logger.removeHandler(handler) # make sure there isn't one already # you can't simply use "if self.handler not in root_logger.handlers" # since at least in unit tests this doesn't work -- # LogCapture() is instantiated for each test case while root_logger # is module global # so we always add new MyMemoryHandler instance for handler in root_logger.handlers[:]: if isinstance(handler, MyMemoryHandler): root_logger.handlers.remove(handler) root_logger.addHandler(self.handler) root_logger.setLevel(self.loglevel) def _addCapturedLogs(self, event): format = self.handler.format records = [format(r) for r in self.handler.buffer] if "logs" in event.metadata: event.metadata["logs"].extend(records) else: event.metadata["logs"] = records class FilterSet(object): def __init__(self, filter_components): self.inclusive, self.exclusive = self._partition(filter_components) @staticmethod def _partition(components): inclusive, exclusive = [], [] for component in components: if component.startswith("-"): exclusive.append(component[1:]) else: inclusive.append(component) return inclusive, exclusive def allow(self, record): """returns whether this record should be printed""" if not self: # nothing to filter return True return self._allow(record) and not self._deny(record) @staticmethod def _any_match(matchers, record): """return the bool of whether `record` starts with any item in `matchers`""" def record_matches_key(key): return record == key or record.startswith(key + ".") return any(map(record_matches_key, matchers)) def _allow(self, record): if not self.inclusive: return True return self._any_match(self.inclusive, record) def _deny(self, record): if not self.exclusive: return False return self._any_match(self.exclusive, record) class MyMemoryHandler(BufferingHandler): def __init__(self, capacity, logformat, logdatefmt, filters): BufferingHandler.__init__(self, capacity) fmt = logging.Formatter(logformat, logdatefmt) self.setFormatter(fmt) self.filterset = FilterSet(filters) def flush(self): pass # do nothing def truncate(self): self.buffer = [] def filter(self, record): return self.filterset.allow(record.name) def emit(self, record): # take a snapshot of the potentially mutable arguments record.msg = record.getMessage() record.args = {} BufferingHandler.emit(self, record) def __getstate__(self): state = self.__dict__.copy() del state["lock"] return state def __setstate__(self, state): self.__dict__.update(state) self.lock = threading.RLock() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/plugins/mp.py0000664002342000234200000004466014220574143016315 0ustar00sirosensirosenimport logging import multiprocessing import multiprocessing.connection as connection import os import select import sys import unittest from nose2 import events, loader, result, runner, session, util from nose2._vendor import six try: from collections.abc import Sequence except ImportError: from collections import Sequence log = logging.getLogger(__name__) class MultiProcess(events.Plugin): configSection = "multiprocess" def __init__(self): self.addArgument( self.setProcs, "N", "processes", "Number of processes used to run tests (0 = auto)", ) self.testRunTimeout = self.config.as_float("test-run-timeout", 60.0) self._procs = self.config.as_int("processes", 0) self.setAddress(self.config.as_str("bind_address", None)) self.cases = {} @property def procs(self): """Get the appropriate number of procs for self.procs if self._procs is 0.""" if self._procs == 0: try: self._procs = multiprocessing.cpu_count() except NotImplementedError: self._procs = 1 return self._procs @procs.setter def procs(self, value): """Setter for procs property""" if value < 0: raise ValueError("Number of processes cannot be less than 0") self._procs = value def setProcs(self, num): self.procs = int(num[0]) # FIXME merge n fix self.register() def setAddress(self, address): if address is None or address.strip() == "": address = [] else: address = [x.strip() for x in address.split(":")[:2]] # Background: On Windows, select.select only works on sockets. So the # ability to select a bindable address and optionally port for the mp # plugin was added. Pipes should support a form of select, but this # would require using pywin32. There are alternatives but all have # some kind of downside. An alternative might be creating a connection # like object using a shared queue for incomings events. self.bind_host = None self.bind_port = 0 if sys.platform == "win32" or address: self.bind_host = "127.116.157.163" if address and address[0]: self.bind_host = address[0] self.bind_port = 0 if len(address) >= 2: self.bind_port = int(address[1]) def pluginsLoaded(self, event): self.addMethods("registerInSubprocess", "startSubprocess", "stopSubprocess") def startTestRun(self, event): event.executeTests = self._runmp def beforeInteraction(self, event): # prevent interactive plugins from running event.handled = True return False def _runmp(self, test, result): # flatten technically modifies a hash of test cases, let's # only run it once per run. flat = list(self._flatten(test)) # do not send import failures to the subprocesses, which will mangle them # but 'run' them in the main process. failed_import_id = "nose2.loader.LoadTestsFailure" result_ = self.session.testResult for testid in flat: if testid.startswith(failed_import_id): self.cases[testid].run(result_) # XXX Process-Handling: The length of the filtered list needs to be # known for _startProcs, until this can be cleaned up. This # wasn't the best way to deal with too few tests flat = [x for x in flat if not x.startswith(failed_import_id)] procs = self._startProcs(len(flat)) # send one initial task to each process for _proc, conn in procs: if not flat: break caseid = flat.pop(0) # NOTE: it throws errors on broken pipes and bad serialization conn.send(caseid) rdrs = [conn for proc, conn in procs if proc.is_alive()] while flat or rdrs: ready, _, _ = select.select(rdrs, [], [], self.testRunTimeout) for conn in ready: # XXX Process-Handling: If we get an EOFError on receive the # process finished= or we lost the process and the test it was # working on. Also do we rebuild the process? try: remote_events = conn.recv() except EOFError: # probably dead/12 log.warning("Subprocess connection closed unexpectedly") continue # If remote_events is None, the process exited normally, # which should mean that we didn't any more tests for it. if remote_events is None: log.debug("Conn closed %s", conn) rdrs.remove(conn) continue # replay events testid, events = remote_events log.debug("Received results for %s", testid) for (hook, event) in events: log.debug("Received %s(%s)", hook, event) self._localize(event) getattr(self.session.hooks, hook)(event) # Send the next test_id # NOTE: send throws errors on broken pipes and bad serialization if not flat: # If there are no more, send None - it's the 'done' flag conn.send(None) continue caseid = flat.pop(0) conn.send(caseid) for _, conn in procs: conn.close() # ensure we wait until all processes are done before # exiting, to allow plugins running there to finalize for proc, _ in procs: proc.join() def _prepConns(self): """ If the ``bind_host`` is not ``None``, return: (multiprocessing.connection.Listener, (address, port, authkey)) else: (parent_connection, child_connection) For the former case: ``accept`` must be called on the listener. In order to get a ``Connection`` object for the socket. """ if self.bind_host is not None: # prevent "accidental" wire crossing authkey = os.urandom(20) address = (self.bind_host, self.bind_port) listener = connection.Listener(address, authkey=authkey) return (listener, listener.address + (authkey,)) else: return multiprocessing.Pipe() def _acceptConns(self, parent_conn): """ When listener is is a :class:`connection.Listener` instance: accept the next incoming connection. However, a timeout mechanism is needed. Since this functionality was added to support mp over inet sockets, this method assumes a Socket-based listen, and will accept the private _socket member to get a low_level socket to do a select on. """ if isinstance(parent_conn, connection.Listener): # ick private interface rdrs = [parent_conn._listener._socket] readable, _, _ = select.select(rdrs, [], [], self.testRunTimeout) if readable: return parent_conn.accept() else: raise RuntimeError("MP: Socket Connection Failed") else: return parent_conn def _startProcs(self, test_count): # Create session export session_export = self._exportSession() procs = [] count = min(test_count, self.procs) log.debug("Creating %i worker processes", count) for _ in range(0, count): parent_conn, child_conn = self._prepConns() proc = multiprocessing.Process( target=procserver, args=(session_export, child_conn) ) proc.daemon = True proc.start() parent_conn = self._acceptConns(parent_conn) procs.append((proc, parent_conn)) return procs def _flatten(self, suite): """ Flatten test-suite into list of IDs, AND record all test case into self.cases CAVEAT: Due to current limitation of the MP plugin, examine the suite tests to find out if they have class or module fixtures and group them that way into name of test classes or module. This is aid in their dispatch. """ log.debug("Flattening test into list of IDs") mods = {} classes = {} stack = [suite] while stack: suite = stack.pop() for test in suite: if isinstance(test, unittest.TestSuite): stack.append(test) else: testid = util.test_name(test) self.cases[testid] = test if util.has_module_fixtures(test): mods.setdefault(test.__class__.__module__, []).append(testid) elif util.has_class_fixtures(test): # testclasses support if test.__class__.__name__ == "_MethodTestCase": test = test.obj classes.setdefault( "%s.%s" % (test.__class__.__module__, test.__class__.__name__), [], ).append(testid) else: yield testid for cls in sorted(classes.keys()): yield cls for mod in sorted(mods.keys()): yield mod def _localize(self, event): # XXX set loader, case, result etc to local ones, if present in event # (event case will be just the id) # (traceback in exc_info if any won't be real!) if hasattr(event, "result"): event.result = self.session.testResult if hasattr(event, "loader"): event.loader = self.session.testLoader if hasattr(event, "runner"): event.runner = self.session.testRunner if hasattr(event, "test") and isinstance(event.test, six.string_types): # remote event.case is the test id try: event.test = self.cases[event.test] except KeyError: # this happens when _flatten augments the test suite # due to a class or module fixture being present event.test = self.session.testLoader.loadTestsFromName( event.test )._tests[0] # subtest support if "subtest" in event.metadata: message, params = event.metadata.pop("subtest") # XXX the sentinel value does not survive the pickle # round-trip and must be reset by hand if type(message) == type(object()): # noqa: E721 message = unittest.case._subtest_msg_sentinel event.test = unittest.case._SubTest(event.test, message, params) def _exportSession(self): """ Generate the session information passed to work process. CAVEAT: The entire contents of which *MUST* be pickeable and safe to use in the subprocess. This probably includes: * No argparse namespaces/named-tuples * No plugin instances * No hokes :return: """ export = { "config": self.session.config, "verbosity": self.session.verbosity, "startDir": self.session.startDir, "topLevelDir": self.session.topLevelDir, "logLevel": self.session.logLevel, "pluginClasses": [], } event = RegisterInSubprocessEvent() # fire registerInSubprocess on plugins -- add those plugin classes # CAVEAT: classes must be pickleable! self.session.hooks.registerInSubprocess(event) export["pluginClasses"].extend(event.pluginClasses) return export def procserver(session_export, conn): # init logging system rlog = multiprocessing.log_to_stderr() rlog.setLevel(session_export["logLevel"]) # make a real session from the "session" we got ssn = import_session(rlog, session_export) if isinstance(conn, Sequence): conn = connection.Client(conn[:2], authkey=conn[2]) event = SubprocessEvent( ssn.testLoader, ssn.testResult, ssn.testRunner, ssn.plugins, conn ) res = ssn.hooks.startSubprocess(event) if event.handled and not res: conn.send(None) conn.close() ssn.hooks.stopSubprocess(event) return # receive and run tests executor = event.executeTests for testid in gentests(conn): if testid is None: break # XXX to handle weird cases like layers, need to # deal with the case that testid is something other # than a simple string. test = event.loader.loadTestsFromName(testid) # XXX If there a need to protect the loop? try/except? rlog.debug("Execute test %s (%s)", testid, test) executor(test, event.result) events = [e for e in ssn.hooks.flush()] try: conn.send((testid, events)) rlog.debug("Log for %s returned", testid) except Exception: rlog.exception("Fail sending event %s: %s" % (testid, events)) # Send empty event list to unblock the conn.recv on main process. conn.send((testid, [])) conn.send(None) conn.close() ssn.hooks.stopSubprocess(event) def import_session(rlog, session_export): ssn = session.Session() ssn.config = session_export["config"] ssn.hooks = RecordingPluginInterface() ssn.verbosity = session_export["verbosity"] ssn.startDir = session_export["startDir"] ssn.topLevelDir = session_export["topLevelDir"] ssn.prepareSysPath() loader_ = loader.PluggableTestLoader(ssn) ssn.testLoader = loader_ result_ = result.PluggableTestResult(ssn) ssn.testResult = result_ runner_ = runner.PluggableTestRunner(ssn) # needed?? ssn.testRunner = runner_ # load and register plugins, forcing multiprocess to the end ssn.plugins = [ plugin(session=ssn) for plugin in session_export["pluginClasses"] if plugin is not MultiProcess ] rlog.debug("Plugins loaded: %s", ssn.plugins) for plugin in ssn.plugins: plugin.register() rlog.debug("Registered %s in subprocess", plugin) # instantiating the plugin will register it. ssn.plugins.append(MultiProcess(session=ssn)) rlog.debug("Registered %s in subprocess", MultiProcess) ssn.plugins[-1].pluginsLoaded(events.PluginsLoadedEvent(ssn.plugins)) return ssn # test generator def gentests(conn): while True: try: testid = conn.recv() if testid is None: return yield testid except EOFError: return # custom event classes class SubprocessEvent(events.Event): """Event fired at start and end of subprocess execution. .. attribute :: loader Test loader instance .. attribute :: result Test result .. attribute :: plugins List of plugins loaded in the subprocess. .. attribute :: connection The :class:`multiprocessing.Connection` instance that the subprocess uses for communication with the main process. .. attribute :: executeTests Callable that will be used to execute tests. Plugins may set this attribute to wrap or otherwise change test execution. The callable must match the signature:: def execute(suite, result): ... """ def __init__(self, loader, result, runner, plugins, connection, **metadata): self.loader = loader self.result = result self.runner = runner self.plugins = plugins self.connection = connection self.executeTests = lambda test, result: test(result) super(SubprocessEvent, self).__init__(**metadata) class RegisterInSubprocessEvent(events.Event): """Event fired to notify plugins that multiprocess testing will occur .. attribute :: pluginClasses Add a plugin class to this list to cause the plugin to be instantiated in each test-running subprocess. The most common thing to do, for plugins that need to run in subprocesses, is:: def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__) """ def __init__(self, **metadata): self.pluginClasses = [] super(RegisterInSubprocessEvent, self).__init__(**metadata) # custom hook system that records calls and events class RecordingHook(events.Hook): def __init__(self, method, interface): super(RecordingHook, self).__init__(method) self.interface = interface def __call__(self, event): res = super(RecordingHook, self).__call__(event) self.interface.log(self.method, event) return res class RecordingPluginInterface(events.PluginInterface): hookClass = RecordingHook noLogMethods = set( [ "getTestCaseNames", "startSubprocess", "stopSubprocess", "registerInSubprocess", "moduleLoadedSuite", "getTestMethodNames", ] ) def __init__(self): super(RecordingPluginInterface, self).__init__() self.events = [] def log(self, method, event): self.events.append((method, event)) def flush(self): events = self.events[:] self.events = [] return events def register(self, method, plugin): """Register a plugin for a method. :param method: A method name :param plugin: A plugin instance """ self._hookForMethod(method).append(plugin) def __getattr__(self, attr): if attr.startswith("__"): raise AttributeError("No %s in %s" % (attr, self)) return self._hookForMethod(attr) def _hookForMethod(self, method): # return recording hook for most hooks, normal hook for those # (like test loading and subprocess events) that we don't want # to send back to the main process. try: return self.hooks[method] except KeyError: if method in self.noLogMethods or method.startswith("loadTest"): hook = events.Hook(method) else: hook = self.hookClass(method, self) self.hooks[method] = hook return hook ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/outcomes.py0000664002342000234200000000401014176405443017526 0ustar00sirosensirosen""" Map exceptions to test outcomes. This plugin implements :func:`setTestOutcome` to enable simple mapping of exception classes to existing test outcomes. By setting a list of exception classes in a nose2 config file, you can configure exceptions that would otherwise be treated as test errors, to be treated as failures or skips instead: .. code-block :: ini [outcomes] always-on = True treat-as-fail = NotImplementedError treat-as-skip = TodoError IOError """ from nose2.events import Plugin __unittest = True class Outcomes(Plugin): """Map exceptions to other test outcomes""" configSection = "outcomes" commandLineSwitch = ( None, "set-outcomes", "Treat some configured exceptions as failure or skips", ) def __init__(self): self.treatAsFail = set(self.config.as_list("treat-as-fail", [])) self.treatAsSkip = set(self.config.as_list("treat-as-skip", [])) def setTestOutcome(self, event): """Update outcome, exc_info and reason based on configured mappings""" if event.exc_info: ec, ev, tb = event.exc_info classname = ec.__name__ if classname in self.treatAsFail: short, long_ = self.labels(classname) self._setOutcome(event, "failed", short, long_) elif classname in self.treatAsSkip: short, long_ = self.labels(classname, upper=False) self._setOutcome( event, "skipped", short, "%s: '%s'" % (long_, ev), str(ev) ) def labels(self, label, upper=True): if upper: label = label.upper() else: label = label.lower() short = label[0] return short, label def _setOutcome(self, event, outcome, shortLabel, longLabel, reason=None): event.outcome = outcome event.shortLabel = shortLabel event.longLabel = longLabel if reason: event.exc_info = None event.reason = reason ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/plugins/prettyassert.py0000664002342000234200000003255314220574143020450 0ustar00sirosensirosen""" Make assert statements print pretty output, including source. This makes ``assert x == y`` more usable, as an alternative to ``self.assertEqual(x, y)`` This plugin implements :func:`outcomeDetail` and checks for event.exc_info If it finds that an AssertionError happened, it will inspect the traceback and add additional detail to the error report. """ from __future__ import print_function import collections import inspect import re import textwrap import tokenize from nose2 import events from nose2._vendor import six __unittest = True class PrettyAssert(events.Plugin): """Add pretty output for "assert" statements""" configSection = "pretty-assert" commandLineSwitch = ( None, "pretty-assert", 'Add pretty output for "assert" statements', ) def outcomeDetail(self, event): # skip if no exception or expected error if (not event.outcomeEvent.exc_info) or event.outcomeEvent.expected: return # unpack, but skip if it's not an AssertionError excty, exc, trace = event.outcomeEvent.exc_info if excty is not AssertionError: return self.addAssertDetail(event.extraDetail, exc, trace) @staticmethod def addAssertDetail(extraDetail, exc, trace): """ Add details to output regarding AssertionError and its context extraDetail: a list of lines which will be joined with newlines and added to the output for this test failure -- defined as part of the event format exc: the AssertionError exception which was thrown trace: a traceback object for the exception """ assert_statement, token_descriptions = _collect_assert_data(trace) # no message was given if len(exc.args) == 0: message = None else: message = exc.args[0] # if there is no assertion statement found, do not add detail to output # # in cases like unittest assert*() methods, an assertion error is # raised, but it doesn't originate with an `assert` statement and has # an autogenerated message if not assert_statement: return # # actually add exception info to detail # # add the assert statement to output with '>>>' prefix extraDetail.append(re.sub("^", ">>> ", assert_statement, flags=re.MULTILINE)) if message: extraDetail.append("\nmessage:") extraDetail.append(" {}".format(message)) if token_descriptions: extraDetail.append("\nvalues:") for k, v in token_descriptions.items(): extraDetail.append(" {} = {}".format(k, v)) def _collect_assert_data(trace): """ Given a traceback, extract the assertion statement and get the set of bound variable names (i.e. tokens) """ # inspect the trace, collecting various data and determining whether or not # it can be tokenized at all source_lines, frame_locals, frame_globals, can_tokenize = _get_inspection_info( trace ) # if things will tokenize cleanly, actually do it if can_tokenize: assert_startline, token_descriptions = _tokenize_assert( source_lines, frame_locals, frame_globals ) # otherwise, indicate that we can't render detail by use of Nones else: assert_startline = None token_descriptions = None # if we found an "assert" (we might not, if someone raises # AssertionError themselves), grab the whole assertion statement # # as a fallback, stick with whatever we think the statement was # - this is easily deceived by multiline expressions if assert_startline is not None: statement = textwrap.dedent( "".join(source_lines[assert_startline:]).rstrip("\n") ) else: statement = None return statement, token_descriptions def _get_inspection_info(trace): """ Pick apart a traceback for the info we actually want to inspect from it - lines of source (truncated) - locals and globals from execution frame - statement which failed (which can be garbage -- don't trust it) - can_tokenize: a bool indicating that the lines of source can be parsed """ (frame, fname, lineno, funcname, context, ctx_index) = inspect.getinnerframes( trace )[-1] original_source_lines, firstlineno = inspect.getsourcelines(frame) # truncate to the code in this frame to remove anything after current # assert statement last_index = lineno - firstlineno + 1 source_lines = original_source_lines[:last_index] # in case the current line is actually an incomplete expression, as in # assert x == (y # ).z # # in which case the the current line is "assert x == (y", which is not a # complete expression # try to append lines to complete the expression, retrying parsing each and # every time until it succeeds for line in original_source_lines[last_index:]: if _can_tokenize(source_lines): break else: source_lines.append(line) return (source_lines, frame.f_locals, frame.f_globals, _can_tokenize(source_lines)) def _can_tokenize(source_lines): """ Check if a list of lines of source can successfully be tokenized """ # tokenize.generate_tokens requires a file-like object, so we need to # convert source_lines to a StringIO to give it that interface filelike = six.StringIO(textwrap.dedent("".join(source_lines))) try: for _tokty, _tok, _start, _end, _tok_lineno in tokenize.generate_tokens( filelike.readline ): pass except tokenize.TokenError: return False return True def _tokenize_assert(source_lines, frame_locals, frame_globals): """ Given a set of lines of source ending in a failing assert, plus the frame locals and globals, tokenize source. Only look at tokens in the final assert statement Resolve all names to repr() of values Return The line on which the assert starts (relative to start of source_lines) A collection of token descriptions as a name=val ordered dict """ # tokenize.generate_tokens requires a file-like object, so we need to # convert source_lines to a StringIO to give it that interface filelike_context = six.StringIO(textwrap.dedent("".join(source_lines))) # track the first line of the assert statement # when the assert is on oneline, we'll have it easily, but a multiline # statement like # assert (x == # 1) # will leave us holding the last line of the statement, # e.g. " 1)", which is not useful # so every time a new assert is found, we get a value back indicate # that it's the start line # # assert True # assert False # works fine, because we'll just hold the last value # # assert True # assert False # assert True # also works because we truncated source_lines to remove the final # assert, which we didn't reach during execution assert_startline = None token_processor = TokenProcessor(frame_locals, frame_globals) # tokenize and process each token for tokty, tok, start, end, tok_lineno in tokenize.generate_tokens( filelike_context.readline ): ret = token_processor.handle_token(tokty, tok, start, end, tok_lineno) if ret: assert_startline = ret # adjust assert_startline by 1 to become a valid index into the # source_lines -- "line 1" means "index 0" if assert_startline: assert_startline -= 1 token_descriptions = collections.OrderedDict() for (name, obj) in token_processor.get_token_collection().items(): # okay, get repr() for a good string representation strvalue = repr(obj) # add in the form we want to print token_descriptions[name] = strvalue return assert_startline, token_descriptions class TokenProcessor(object): def __init__(self, frame_locals, frame_globals): # local and global variables from the frame which we're inspecting self.frame_locals, self.frame_globals = frame_locals, frame_globals # None or a tuple of (object, name) where # - "object" is the object whose attributes we are currently resolving # - "name" is its name, as we would like to display it # # start each time we see a sequence of NAME OP NAME OP NAME (etc.) # end each time we see a token which is neither NAME nor OP self.doing_resolution = None # an index of known token names (including the long "x.y.z" names we # get from attribute resolution) to their values, in the order in which # they were encountered # track which tokens we've seen to avoid duplicates if a name appears # twice, as in `assert x != x` self.seen_tokens = collections.OrderedDict() # the previous token seen as a tuple of (tok_type, token_name) # (or None when we start) self.last_tok = None def get_token_collection(self): return self.seen_tokens def handle_token(self, toktype, tok, start, end, line): """ A tokenization processor for tokenize.generate_tokens Skips certain token types, class names, etc When an identifiable/usable token is found, add it to the token collection (self.seen_tokens) When an "assert" statement is found, reset the token collection and return the start line (relative to the text being tokenized) """ prior_tok = self.last_tok self.last_tok = (toktype, tok) # CASE 0: skip non "NAME" or "OP" tokens and clear current resolution # # NAME is most identifiers and keywords # OP is operators, including . # # special note: don't clear resolution for whitespace (e.g. newline) if toktype not in (tokenize.NAME, tokenize.OP): # only newline for now, maybe we'll find others if toktype not in (tokenize.NEWLINE,): self.doing_resolution = None return # CASE 1: Operator token # # skip tokens and either leave resolution in progress or reset, # depending # # continue resolution for # "." # because that's what attribute resolution *is* # ")" # this is handy, as it means that "(x).y" works # # reset resolution for everything else, e.g. "[", "]", ":" # special note: reset resolution for "(" # # failing to filter out "(" can result in badness in cases like this: # >>> def foo(): # >>> return [1] # >>> foo.pop = 2 # >>> ... # >>> def test_foo(): # >>> assert foo().pop() == 2 # # if we stop resolution when we see an LPAREN, we resolve `foo` # successfully, fail on `pop` and everything is OK, but if we try to # traverse the LPAREN, we get `foo.pop = 2` in our values, which is # wrong if toktype == tokenize.OP: if tok not in (".", ")"): self.doing_resolution = None return # CASE 2: "assert" statement # assert statement was reached, reset # return the start line (start = (startrow, startcol)) if tok == "assert": self.seen_tokens.clear() self.doing_resolution = None return start[0] # handle tokens # CASE 3: a name is being resolved, # there is a previous token, # and it's a "." operator if ( self.doing_resolution and prior_tok and (prior_tok[0] == tokenize.OP and prior_tok[1] == ".") ): # unpack and look for the attribute obj, name = self.doing_resolution if hasattr(obj, tok): obj = getattr(obj, tok) name = name + "." + tok self.doing_resolution = (obj, name) self.seen_tokens[name] = obj # if we couldn't find a relevant attribute, reset on resolution so # that we can try afresh else: self.doing_resolution = None # CASE 4: a name is being resolved and there is no preceding "." or # resolution was explicitly stopped else: # skip tokens we've seen, but grab them as the current things under # resolution if tok in self.seen_tokens: self.doing_resolution = (self.seen_tokens[tok], tok) return # we've never seen this token before else: # try to resolve to a value try: value = self.frame_locals[tok] except KeyError: try: value = self.frame_globals[tok] except KeyError: # unresolveable name -- short circuit # shows up in some cases like `f().x` in which `x` # might not be a name bound to a value return # add it (so we don't try it again unless we hit a new assert # and reset) self.seen_tokens[tok] = value self.doing_resolution = (value, tok) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/printhooks.py0000664002342000234200000000343114176405443020076 0ustar00sirosensirosen""" This plugin is primarily useful for plugin authors who want to debug their plugins. It prints each hook that is called to stderr, along with details of the event that was passed to the hook. To do that, this plugin overrides :meth:`nose2.events.Plugin.register` and, after registration, replaces all existing :class:`nose2.events.Hook` instances in ``session.hooks`` with instances of a :class:`~nose2.events.Hook` subclass that prints information about each call. """ import sys from nose2 import events INDENT = [] __unittest = True class PrintHooks(events.Plugin): """Print hooks as they are called""" configSection = "print-hooks" commandLineSwitch = ( "P", "print-hooks", "Print names of hooks in order of execution", ) def register(self): """Override to inject noisy hook instances. Replaces :class:`~nose2.events.Hook` instances in ``self.session.hooks.hooks`` with noisier objects. """ super(PrintHooks, self).register() # now we can be sure that all other plugins have loaded # and this plugin is active, patch in our hook class self.session.hooks.hookClass = NoisyHook for attr, hook in self.session.hooks.hooks.items(): newhook = NoisyHook(attr) newhook.plugins = hook.plugins self.session.hooks.hooks[attr] = newhook class NoisyHook(events.Hook): def __call__(self, event): _report(self.method, event) _indent() try: return super(NoisyHook, self).__call__(event) finally: _dedent() def _report(method, event): sys.stderr.write("\n%s%s: %s" % ("".join(INDENT), method, event)) def _indent(): INDENT.append(" ") def _dedent(): if INDENT: INDENT.pop() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/prof.py0000664002342000234200000000410714176405443016645 0ustar00sirosensirosen""" Profile test execution using cProfile. This plugin implements :func:`startTestRun` and replaces ``event.executeTests`` with :meth:`cProfile.Profile.runcall`. It implements :func:`beforeSummaryReport` to output profiling information before the final test summary time. Config file options ``filename``, ``sort`` and ``restrict`` can be used to change where profiling information is saved and how it is presented. Load this plugin by running nose2 with the `--plugin=nose2.plugins.prof` option and activate it with the `--profile` option,or put the corresponding entries (`plugin` and `always_on`) in the respective sections of the configuration file. """ import cProfile import logging import pstats from nose2 import events, util log = logging.getLogger(__name__) __unittest = True class Profiler(events.Plugin): """Profile the test run""" configSection = "profiler" commandLineSwitch = ("P", "profile", "Run tests under profiler") def __init__(self): self.pfile = self.config.as_str("filename", "") self.sort = self.config.as_str("sort", "cumulative") self.restrict = self.config.as_list("restrict", []) self.fileno = None def startTestRun(self, event): """Set up the profiler""" self.prof = cProfile.Profile() event.executeTests = self.prof.runcall def beforeSummaryReport(self, event): """Output profiling results""" # write prof output to stream class Stream: def write(self, *msg): for m in msg: event.stream.write(m) event.stream.write(" ") event.stream.flush() stream = Stream() prof_stats = pstats.Stats(self.prof, stream=stream) prof_stats.sort_stats(self.sort) event.stream.writeln(util.ln("Profiling results")) if self.restrict: prof_stats.print_stats(*self.restrict) else: prof_stats.print_stats() if self.pfile: prof_stats.dump_stats(self.pfile) self.prof.disable() event.stream.writeln("") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/result.py0000664002342000234200000002521214176405443017215 0ustar00sirosensirosen""" Collect and report test results. This plugin implements the primary user interface for nose2. It collects test outcomes and reports on them to the console, as well as firing several hooks for other plugins to do their own reporting. To see this report, nose2 MUST be run with the :option:`verbose` flag:: nose2 --verbose This plugin extends standard unittest console reporting slightly by allowing custom report categories. To put events into a custom reporting category, change the event.outcome to whatever you want. Note, however, that customer categories are *not* treated as errors or failures for the purposes of determining whether a test run has succeeded. Don't disable this plugin, unless you (a) have another one doing the same job, or (b) really don't want any test results (and want all test runs to ``exit(1)``). """ # This module contains some code copied from unittest2/runner.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import sys import unittest from nose2 import events, result, util __unittest = True class ResultReporter(events.Plugin): """Result plugin that implements standard unittest console reporting""" alwaysOn = True configSection = "test-result" separator1 = "=" * 70 separator2 = "-" * 70 def __init__(self): self.testsRun = 0 self.reportCategories = { "failures": [], "errors": [], "skipped": [], "expectedFailures": [], "unexpectedSuccesses": [], } self.dontReport = set( [ "errors", "failures", "skipped", "passed", "expectedFailures", "unexpectedSuccesses", ] ) self.stream = util._WritelnDecorator(sys.stderr) self.descriptions = self.config.as_bool("descriptions", True) def startTest(self, event): """Handle startTest hook - prints test description if verbosity > 1 """ self.testsRun += 1 self._reportStartTest(event) def testOutcome(self, event): """Handle testOutcome hook - records test outcome in reportCategories - prints test outcome label - fires reporting hooks (:func:`reportSuccess`, :func:`reportFailure`, etc) """ if event.outcome == result.ERROR: self.reportCategories["errors"].append(event) self._reportError(event) elif event.outcome == result.FAIL: if not event.expected: self.reportCategories["failures"].append(event) self._reportFailure(event) else: self.reportCategories["expectedFailures"].append(event) self._reportExpectedFailure(event) elif event.outcome == result.SKIP: self.reportCategories["skipped"].append(event) self._reportSkip(event) elif event.outcome == result.PASS: if event.expected: self._reportSuccess(event) else: self.reportCategories["unexpectedSuccesses"].append(event) self._reportUnexpectedSuccess(event) elif event.outcome == result.SUBTEST: # subtests do not report success if event.exc_info is not None: if issubclass(event.exc_info[0], event.test.failureException): self.reportCategories["failures"].append(event) self._reportFailure(event) else: self.reportCategories["errors"].append(event) self._reportError(event) else: # generic outcome handling self.reportCategories.setdefault(event.outcome, []).append(event) self._reportOtherOutcome(event) def afterTestRun(self, event): """Handle afterTestRun hook - prints error lists - prints summary - fires summary reporting hooks (:func:`beforeErrorList`, :func:`beforeSummaryReport`, etc) """ self._reportSummary(event) def wasSuccessful(self, event): # if another plugin did not set it already, start by setting # success=True if event.success is None: event.success = True for _name, report_events in self.reportCategories.items(): for e in report_events: if ( e.outcome == result.ERROR or (e.outcome == result.FAIL and not e.expected) or e.outcome == result.SUBTEST ): event.success = False break def _reportStartTest(self, event): evt = events.ReportTestEvent(event, self.stream) self.session.hooks.reportStartTest(evt) if evt.handled: return if self.session.verbosity > 1: # allow other plugins to override/spy on stream evt.stream.write(self._getDescription(event.test, errorList=False)) evt.stream.write(" ... ") evt.stream.flush() def _reportError(self, event): self._report(event, "reportError", "E", "ERROR") def _reportFailure(self, event): self._report(event, "reportFailure", "F", "FAIL") def _reportSkip(self, event): self._report(event, "reportSkip", "s", "skipped %s" % event.reason) def _reportExpectedFailure(self, event): self._report(event, "reportExpectedFailure", "x", "expected failure") def _reportUnexpectedSuccess(self, event): self._report(event, "reportUnexpectedSuccess", "u", "unexpected success") def _reportOtherOutcome(self, event): self._report(event, "reportOtherOutcome", "?", "unknown outcome") def _reportSuccess(self, event): self._report(event, "reportSuccess", ".", "ok") def _reportSummary(self, event): # let others print something evt = events.ReportSummaryEvent(event, self.stream, self.reportCategories) self.session.hooks.beforeErrorList(evt) # allows other plugins to mess with report categories cats = evt.reportCategories errors = cats.get("errors", []) failures = cats.get("failures", []) # use evt.stream so plugins can replace/wrap/spy it if self.session.verbosity > 0: evt.stream.writeln("") self._printErrorList("ERROR", errors, evt.stream) self._printErrorList("FAIL", failures, evt.stream) for flavour, events_ in cats.items(): if flavour in self.dontReport: continue self._printErrorList(flavour.upper(), events_, evt.stream) self._printSummary(evt) def _printErrorList(self, flavour, events_, stream): for event in events_: desc = self._getDescription(event.test, errorList=True) err = self._getOutcomeDetail(event) stream.writeln(self.separator1) stream.writeln("%s: %s" % (flavour, desc)) stream.writeln(self.separator2) stream.writeln(err) def _printSummary(self, reportEvent): self.session.hooks.beforeSummaryReport(reportEvent) stream = reportEvent.stream stream.writeln(self.separator2) run = self.testsRun msg = "Ran %d test%s in %.3fs\n" % ( run, run != 1 and "s" or "", reportEvent.stopTestEvent.timeTaken, ) stream.writeln(msg) infos = [] extraInfos = [] if reportEvent.stopTestEvent.result.wasSuccessful(): stream.write("OK") else: stream.write("FAILED") failed = len(reportEvent.reportCategories.get("failures", [])) errored = len(reportEvent.reportCategories.get("errors", [])) skipped = len(reportEvent.reportCategories.get("skipped", [])) expectedFails = len(reportEvent.reportCategories.get("expectedFailures", [])) unexpectedSuccesses = len( reportEvent.reportCategories.get("unexpectedSuccesses", []) ) for flavour, results in reportEvent.reportCategories.items(): if flavour in self.dontReport: continue count = len(results) if count: extraInfos.append("%s=%d" % (flavour, count)) if failed: infos.append("failures=%d" % failed) if errored: infos.append("errors=%d" % errored) if skipped: infos.append("skipped=%d" % skipped) if expectedFails: infos.append("expected failures=%d" % expectedFails) if unexpectedSuccesses: infos.append("unexpected successes=%d" % unexpectedSuccesses) infos.extend(extraInfos) if infos: reportEvent.stream.writeln(" (%s)" % (", ".join(infos),)) else: reportEvent.stream.writeln("") self.session.hooks.afterSummaryReport(reportEvent) def _getDescription(self, test, errorList): if not isinstance(test, unittest.TestCase): return test.__class__.__name__ doc_first_line = test.shortDescription() if self.descriptions and doc_first_line: desc = "\n".join((str(test), doc_first_line)) else: desc = str(test) event = events.DescribeTestEvent(test, description=desc, errorList=errorList) self.session.hooks.describeTest(event) return event.description def _getOutcomeDetail(self, event): evt = events.OutcomeDetailEvent(event) result = self.session.hooks.outcomeDetail(evt) if evt.handled: return result exc_info = getattr(event, "exc_info", None) test = getattr(event, "test", None) if exc_info: detail = [util.exc_info_to_string(exc_info, test)] else: detail = [] if evt.extraDetail: detail.extend(evt.extraDetail) try: return "\n".join(detail) except UnicodeDecodeError: return "\n".join(util.safe_decode(d) for d in detail) def _report(self, event, hook, shortLabel, longLabel): evt = events.ReportTestEvent(event, self.stream) getattr(self.session.hooks, hook)(evt) if evt.handled: return if self.session.verbosity > 1: # event I fired has stream, event I received has labels evt.stream.writeln(getattr(event, "longLabel", None) or longLabel) elif self.session.verbosity: evt.stream.write(getattr(event, "shortLabel", None) or shortLabel) evt.stream.flush() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/plugins/testid.py0000664002342000234200000000645614176405443017204 0ustar00sirosensirosen""" Allow easy test selection with test ids. Assigns (and, in verbose mode, prints) a sequential test id for each test executed. Ids can be fed back in as test names, and this plugin will translate them back to full test names. Saves typing! This plugin implements :func:`reportStartTest`, :func:`loadTestsFromName`, :func:`loadTestsFromNames` and :func:`stopTest`. """ import os import pickle import re from nose2 import util from nose2.events import Plugin __unittest = True class TestId(Plugin): """Allow easy test select with ids""" configSection = "testid" commandLineSwitch = ("I", "with-id", "Add test ids to output") idpat = re.compile(r"(\d+)") def __init__(self): self.idfile = self.config.as_str("id-file", ".noseids") self.ids = {} self.tests = {} if not os.path.isabs(self.idfile): # FIXME expand-user? self.idfile = os.path.join(os.getcwd(), self.idfile) self.id = 0 self._loaded = False def nextId(self): """Increment ID and return it.""" self.id += 1 return self.id def reportStartTest(self, event): """Record and possibly output test id""" testid = util.test_name(event.testEvent.test) if testid not in self.tests: id_ = self.nextId() self.ids[id_] = testid self.tests[testid] = id_ else: id_ = self.tests[testid] event.metadata["testid"] = id_ if self.session.verbosity > 1: event.stream.write("#%s " % id_) def loadTestsFromName(self, event): """Load tests from a name that is an id If the name is a number, it might be an ID assigned by us. If we can find a test to which we have assigned that ID, event.name is changed to the test's real ID. In this way, tests can be referred to via sequential numbers. """ testid = self._testNameFromId(event.name) if testid is not None: event.name = testid def loadTestsFromNames(self, event): """Translate test ids into test names""" for i, name in enumerate(event.names[:]): testid = self._testNameFromId(name) if testid is not None: event.names[i] = testid def stopTestRun(self, event): """Write testids file""" with open(self.idfile, "wb") as fh: pickle.dump({"ids": self.ids, "tests": self.tests}, fh) def loadIds(self): """Load previously pickled 'ids' and 'tests' attributes.""" if self._loaded: return try: with open(self.idfile, "rb") as fh: data = pickle.load(fh) except EnvironmentError: self._loaded = True return if "ids" in data: self.ids = data["ids"] if "tests" in data: self.tests = data["tests"] self.id = max(self.ids.keys()) self._loaded = True def _testNameFromId(self, name): """Try to translate one of our IDs to real test ID.""" m = self.idpat.match(name) if m is None: return None id_ = int(m.groups()[0]) self.loadIds() # Translate to test's real ID try: return self.ids[id_] except KeyError: return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/result.py0000664002342000234200000001041014176405443015526 0ustar00sirosensirosenimport time from nose2 import events ERROR = "error" FAIL = "failed" SKIP = "skipped" PASS = "passed" SUBTEST = "subtest" __unittest = True class PluggableTestResult(object): """Test result that defers to plugins. All test outcome recording and reporting is deferred to plugins, which are expected to implement :func:`startTest`, :func:`stopTest`, :func:`testOutcome`, and :func:`wasSuccessful`. :param session: Test run session. .. attribute :: shouldStop When ``True``, test run should stop before running another test. """ def __init__(self, session): self.session = session self.shouldStop = False # XXX TestCase.subTest expects a result.failfast attribute self.failfast = False def startTest(self, test): """Start a test case. Fires :func:`startTest` hook. """ event = events.StartTestEvent(test, self, time.time()) self.session.hooks.startTest(event) def stopTest(self, test): """Stop a test case. Fires :func:`stopTest` hook. """ event = events.StopTestEvent(test, self, time.time()) self.session.hooks.stopTest(event) def addError(self, test, err): """Test case resulted in error. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, ERROR, err) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addFailure(self, test, err): """Test case resulted in failure. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, FAIL, err) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addSubTest(self, test, subtest, err): """Called at the end of a subtest. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(subtest, self, SUBTEST, err) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addSuccess(self, test): """Test case resulted in success. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, PASS, expected=True) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addSkip(self, test, reason): """Test case was skipped. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, SKIP, reason=reason) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addExpectedFailure(self, test, err): """Test case resulted in expected failure. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, FAIL, err, expected=True) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def addUnexpectedSuccess(self, test): """Test case resulted in unexpected success. Fires :func:`setTestOutcome` and :func:`testOutcome` hooks. """ event = events.TestOutcomeEvent(test, self, PASS) self.session.hooks.setTestOutcome(event) self.session.hooks.testOutcome(event) def wasSuccessful(self): """Was test run successful? Fires :func:`wasSuccessful` hook, and returns ``event.success``. """ # assume failure; plugins must explicitly declare success try: return self._success except AttributeError: event = events.ResultSuccessEvent(self, None) self.session.hooks.wasSuccessful(event) self._success = event.success return self._success def stop(self): """Stop test run. Fires :func:`resultStop` hook, and sets ``self.shouldStop`` to ``event.shouldStop``. """ event = events.ResultStopEvent(self, True) self.session.hooks.resultStop(event) self.shouldStop = event.shouldStop def __repr__(self): return "<%s>" % self.__class__.__name__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/runner.py0000664002342000234200000000406314176405443015530 0ustar00sirosensirosen# This module contains some code copied from unittest2/runner.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import time from nose2 import events, result __unittest = True class PluggableTestRunner(object): """Test runner that defers most work to plugins. :param session: Test run session .. attribute :: resultClass Class to instantiate to create test result. Default: :class:`nose2.result.PluggableTestResult`. """ resultClass = result.PluggableTestResult def __init__(self, session): self.session = session def run(self, test): """Run tests. :param test: A unittest :class:`TestSuite`` or :class:`TestClass`. :returns: Test result Fires :func:`startTestRun` and :func:`stopTestRun` hooks. """ result = self._makeResult() def executor(suite, result): return suite(result) startTime = time.time() event = events.StartTestRunEvent(self, test, result, startTime, executor) self.session.hooks.startTestRun(event) # allows startTestRun to modify test suite test = event.suite # ... and test execution executor = event.executeTests try: if not event.handled: executor(test, result) finally: stopTime = time.time() timeTaken = stopTime - startTime event = events.StopTestRunEvent(self, result, stopTime, timeTaken) self.session.hooks.stopTestRun(event) self.session.hooks.afterTestRun(event) return result def _makeResult(self): result = self.resultClass(self.session) event = events.ResultCreatedEvent(result) self.session.hooks.resultCreated(event) self.session.testResult = event.result return event.result def __repr__(self): return "<%s>" % self.__class__.__name__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/session.py0000664002342000234200000002031014264464446015701 0ustar00sirosensirosenimport argparse import logging import os import sys from nose2 import config, events, util # py2/py3 compatible load of SafeConfigParser/ConfigParser if sys.version_info < (3, 2): from ConfigParser import SafeConfigParser as ConfigParser else: from configparser import ConfigParser log = logging.getLogger(__name__) __unittest = True class Session(object): """Configuration session. Encapsulates all configuration for a given test run. .. attribute :: argparse An instance of :class:`argparse.ArgumentParser`. Plugins can use this directly to add arguments and argument groups, but *must* do so in their ``__init__`` methods. .. attribute :: pluginargs The argparse argument group in which plugins (by default) place their command-line arguments. Plugins can use this directly to add arguments, but *must* do so in their ``__init__`` methods. .. attribute :: hooks The :class:`nose2.events.PluginInterface` instance contains all available plugin methods and hooks. .. attribute :: plugins The list of loaded -- but not necessarily *active* -- plugins. .. attribute :: verbosity Current verbosity level. Default: 1. .. attribute :: startDir Start directory of test run. Test discovery starts here. Default: current working directory. .. attribute :: topLevelDir Top-level directory of test run. This directory is added to sys.path. Default: starting directory. .. attribute :: libDirs Names of code directories, relative to starting directory. Default: ['lib', 'src']. These directories are added to sys.path and discovery if the exist. .. attribute :: testFilePattern Pattern used to discover test module files. Default: test*.py .. attribute :: testMethodPrefix Prefix used to discover test methods and functions: Default: 'test'. .. attribute :: unittest The config section for nose2 itself. """ configClass = config.Config def __init__(self): self.argparse = argparse.ArgumentParser(prog="nose2", add_help=False) self.pluginargs = self.argparse.add_argument_group( "plugin arguments", "Command-line arguments added by plugins:" ) self.config = ConfigParser() self.hooks = events.PluginInterface() self.plugins = [] # this will be reset later, whenever handleCfgArgs happens, but it # starts at 1 so that it always has a non-negative integer value self.verbosity = 1 self.startDir = None self.topLevelDir = None self.testResult = None self.testLoader = None self.logLevel = logging.WARN self.configCache = dict() def get(self, section): """Get a config section. :param section: The section name to retrieve. :returns: instance of self.configClass. """ # If section exists in cache, return cached version if section in self.configCache: return self.configCache[section] # If section doesn't exist in cache, parse config file # (and cache result) items = [] if self.config.has_section(section): items = self.config.items(section) self.configCache[section] = self.configClass(items) return self.configCache[section] def loadConfigFiles(self, *filenames): """Load config files. :param filenames: Names of config files to load. Loads all names files that exist into ``self.config``. """ self.config.read(filenames) def loadPlugins(self, modules=None, exclude=None): """Load plugins. :param modules: List of module names from which to load plugins. """ # plugins set directly if modules is None: modules = [] if exclude is None: exclude = [] # plugins mentioned in config file(s) cfg = self.unittest more_plugins = cfg.as_list("plugins", []) cfg_exclude = cfg.as_list("exclude-plugins", []) exclude.extend(cfg_exclude) exclude = set(exclude) all_ = (set(modules) | set(more_plugins)) - exclude all_ = sorted(all_) log.debug("Loading plugin modules: %s", all_) for module in all_: self.loadPluginsFromModule(util.module_from_name(module)) self.hooks.pluginsLoaded(events.PluginsLoadedEvent(self.plugins)) def loadPluginsFromModule(self, module): """Load plugins from a module. :param module: A python module containing zero or more plugin classes. """ avail = [] for entry in dir(module): try: item = getattr(module, entry) except AttributeError: pass try: if issubclass(item, events.Plugin) and not item == events.Plugin: avail.append(item) except TypeError: pass for cls in avail: log.debug("Plugin is available: %s", cls) plugin = cls(session=self) if plugin not in self.plugins: self.plugins.append(plugin) for method in self.hooks.preRegistrationMethods: if hasattr(plugin, method): self.hooks.register(method, plugin) def registerPlugin(self, plugin): """Register a plugin. :param plugin: A `nose2.events.Plugin` instance. Register the plugin with all methods it implements. """ log.debug("Register active plugin %s", plugin) if plugin not in self.plugins: self.plugins.append(plugin) for method in self.hooks.methods: if hasattr(plugin, method): log.debug("Register method %s for plugin %s", method, plugin) self.hooks.register(method, plugin) def setVerbosity(self, args_verbosity, args_verbose, args_quiet): """ Determine verbosity from various (possibly conflicting) sources of info :param args_verbosity: The --verbosity argument value :param args_verbose: count of -v options :param args_quiet: count of -q options start with config, override with any given --verbosity, then adjust up/down with -vvv -qq, etc """ self.verbosity = self.unittest.as_int("verbosity", 1) if args_verbosity is not None: self.verbosity = args_verbosity # adjust up or down, depending on the difference of these counts self.verbosity += args_verbose - args_quiet # floor the value at 0 -- verbosity is always a non-negative integer self.verbosity = max(self.verbosity, 0) def setStartDir(self, args_start_dir=None): """ start dir comes from config and may be overridden by an argument """ self.startDir = self.unittest.as_str("start-dir", ".") if args_start_dir is not None: self.startDir = args_start_dir def prepareSysPath(self): """Add code directories to sys.path""" tld = self.topLevelDir sd = self.startDir if tld is None: tld = sd tld = os.path.abspath(tld) util.ensure_importable(tld) for libdir in self.libDirs: libdir = os.path.abspath(os.path.join(tld, libdir)) if os.path.exists(libdir): util.ensure_importable(libdir) # convenience properties @property def libDirs(self): return self.unittest.as_list("code-directories", ["lib", "src"]) @property def testFilePattern(self): return self.unittest.as_str("test-file-pattern", "test*.py") @property def testMethodPrefix(self): return self.unittest.as_str("test-method-prefix", "test") @property def unittest(self): return self.get("unittest") def isPluginLoaded(self, pluginName): """Returns ``True`` if a given plugin is loaded. :param pluginName: the name of the plugin module: e.g. "nose2.plugins.layers". """ for plugin in self.plugins: if pluginName == plugin.__class__.__module__: return True return False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657949892.0 nose2-0.12.0/nose2/sphinxext.py0000664002342000234200000002132114264447304016245 0ustar00sirosensirosenimport types from docutils import nodes from docutils.parsers.rst import Directive, directives from docutils.statemachine import ViewList from nose2 import events, plugins, session, util AD = u"" __unittest = True class AutoPlugin(Directive): required_arguments = 1 optional_arguments = 1 final_argument_whitespace = False has_content = False option_spec = {"module": directives.unchanged} def run(self): plugin_name = self.arguments[0] parent, plugin = util.object_from_name(plugin_name) if isinstance(plugin, types.ModuleType): # document all plugins in module module = plugin mod_name = module.__name__ plugins = self.plugins(module) else: if "module" in self.options: mod_name = self.options["module"] else: mod_name = plugin_name[0 : plugin_name.index(plugin.__name__) - 1] plugins = [plugin] rst = ViewList() if mod_name: rst.append(u".. automodule :: %s\n" % mod_name, AD) rst.append(u"", AD) for plug in plugins: self.document(rst, plug) # parse rst and generate new nodelist state = self.state node = nodes.section() node.document = state.document surrounding_title_styles = state.memo.title_styles surrounding_section_level = state.memo.section_level state.memo.title_styles = [] state.memo.section_level = 0 state.nested_parse(rst, 0, node, match_titles=1) state.memo.title_styles = surrounding_title_styles state.memo.section_level = surrounding_section_level return node.children def document(self, rst, plugin): ssn = session.Session() ssn.configClass = ssn.config = config = ConfigBucket() ssn.pluginargs = opts = OptBucket() plugin_name = plugin.__name__ config = ssn.config obj = plugin(session=ssn) try: obj.pluginsLoaded(events.PluginsLoadedEvent([obj])) except AttributeError: pass # config options if config.vars: self.add_config(rst, config, plugin) # command-line options if opts.opts: self.headline(rst, u"Command-line options") for opt in opts: for line in opt.options(): rst.append(line, AD) rst.append("", AD) # class __doc__ self.headline(rst, u"Plugin class reference: %s" % plugin_name) rst.append(u".. autoclass :: %s" % plugin_name, AD) rst.append(u" :members:", AD) rst.append(u"", AD) def add_config(self, rst, config, plugin): # add docs on enabling non-default plugins plugin_modname = plugin.__module__ if plugin_modname not in plugins.DEFAULT_PLUGINS: self.headline(rst, u"Enable this Plugin") rst.append(u"This plugin is built-in, but not loaded by default.", AD) rst.append(u"", AD) rst.append( u"Even if you specify ``always-on = True`` in the " u"configuration, it will not run unless you also enable it. " u"You can do so by putting the following in a " u":file:`unittest.cfg` or :file:`nose2.cfg` file", AD, ) rst.append(u"", AD) rst.append(u".. code-block:: ini", AD) rst.append(u"", AD) rst.append(u" [unittest]", AD) rst.append(u" plugins = %s" % plugin_modname, AD) rst.append(u"", AD) rst.append( u"The ``plugins`` parameter may contain a list of plugin " u"names, including ``%s``" % plugin_modname, AD, ) rst.append(u"", AD) headline = u"Configuration [%s]" % config.section self.headline(rst, headline) for var in sorted(config.vars.keys()): info = config.vars[var] rst.append(u".. rst:configvar :: %s" % var, AD) rst.append(u" ", AD) rst.append(u" :Default: %(default)s" % info, AD) rst.append(u" :Type: %(type)s" % info, AD) rst.append(u"", AD) self.headline(rst, u"Sample configuration", "-") rst.append( u"The default configuration is equivalent to including " u"the following in a :file:`unittest.cfg` file.", AD, ) rst.append(u"", AD) rst.append(u".. code-block:: ini", AD) rst.append(u" ", AD) rst.append(u" [%s]" % config.section, AD) for var in sorted(config.vars.keys()): info = config.vars[var] entry = " %s = " % (var) if info["type"] == "list": if info["default"]: pad = " " * len(entry) entry = u"%s%s" % (entry, info["default"][0]) rst.append(entry, AD) for val in info["default"][1:]: rst.append(u"%s%s" % (pad, val), AD) else: rst.append(entry, AD) elif info["default"] is not None: entry = u"%s%s" % (entry, info["default"]) rst.append(entry, AD) rst.append(u"", AD) def headline(self, rst, headline, level=u"="): rst.append(headline, AD) rst.append(level * len(headline), AD) rst.append(u"", AD) def plugins(self, module): for entry in dir(module): try: item = getattr(module, entry) except AttributeError: pass try: if issubclass(item, events.Plugin): yield item except TypeError: pass def setup(app): app.add_directive("autoplugin", AutoPlugin) app.add_object_type("configvar", "config", u"pair: %s; configvar") DEFAULT = object() class ConfigBucket(object): def __init__(self): self.section = None self.vars = {} def __call__(self, items): self.vars = dict(items) return self def has_section(self, section): self.section = section return False def items(self): return self.vars.items() def as_bool(self, item, default=DEFAULT): self.vars[item] = {"type": "boolean", "default": default} return default as_tri = as_bool def as_int(self, item, default=DEFAULT): self.vars[item] = {"type": "integer", "default": default} return default def as_float(self, item, default=DEFAULT): self.vars[item] = {"type": "float", "default": default} return default def as_str(self, item, default=DEFAULT): self.vars[item] = {"type": "str", "default": default} return default def as_list(self, item, default=DEFAULT): self.vars[item] = {"type": "list", "default": default} return default def __getitem__(self, item): self.vars[item] = {"type": None, "default": DEFAULT} def get(self, item, default=DEFAULT): self.vars[item] = {"type": None, "default": default} return default class OptBucket(object): def __init__(self, doc=None, prog="nosetests"): self.seen = set() self.opts = [] self.doc = doc self.prog = prog def __iter__(self): return iter(self.opts) def format_help(self): return self.doc.replace("%prog", self.prog).replace(":\n", "::\n") def add_argument(self, *arg, **kw): if arg not in self.seen: self.opts.append(Opt(*arg, **kw)) self.seen.add(arg) def __call__(self, callback, opt=None, longOpt=None, help=None): opts = [] if opt is not None: opts.append("-" + opt) if longOpt is not None: opts.append("--" + longOpt) self.add_option(*opts, help=help) class Opt(object): def __init__(self, *arg, **kw): self.opts = arg self.action = kw.pop("action", None) self.default = kw.pop("default", None) self.metavar = kw.pop("metavar", None) self.help = kw.pop("help", None) def options(self): buf = [] for optstring in self.opts: desc = optstring if self.action not in ("store_true", "store_false", None): desc += " %s" % self.meta(optstring) buf.append(desc) res = [".. cmdoption :: " + ", ".join(buf)] if self.help: res.append("") res.append(" %s" % self.help) res.append("") return res def meta(self, optstring): # FIXME optparser default metavar? return self.metavar or "DEFAULT" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/suite.py0000664002342000234200000001203014176405443015341 0ustar00sirosensirosenimport logging import sys import unittest from nose2 import events, util log = logging.getLogger(__name__) __unittest = True # # Layer suite class # class LayerSuite(unittest.BaseTestSuite): def __init__(self, session, tests=(), layer=None): super(LayerSuite, self).__init__(tests) self.layer = layer self.wasSetup = False self.session = session def run(self, result): self.handle_previous_test_teardown(result) if not self._safeMethodCall(self.setUp, result): return try: for test in self: if result.shouldStop: break self._safeMethodCall(self.setUpTest, result, test) try: test(result) finally: self._safeMethodCall(self.tearDownTest, result, test) finally: if self.wasSetup: self._safeMethodCall(self.tearDown, result) def handle_previous_test_teardown(self, result): prev = getattr(result, "_previousTestClass", None) if prev is None: return layer_attr = getattr(prev, "layer", None) if isinstance(layer_attr, LayerSuite): return try: suite_obj = unittest.suite.TestSuite() suite_obj._tearDownPreviousClass(None, result) suite_obj._handleModuleTearDown(result) finally: result._previousTestClass = None def setUp(self): if self.layer is None: return event = events.StartLayerSetupEvent(self.layer) self.session.hooks.startLayerSetup(event) setup = self._getBoundClassmethod(self.layer, "setUp") if setup: setup() self.wasSetup = True event = events.StopLayerSetupEvent(self.layer) self.session.hooks.stopLayerSetup(event) def setUpTest(self, test): if self.layer is None: return # skip suites, to ensure test setup only runs once around each test # even for sub-layer suites inside this suite. try: iter(test) except TypeError: # ok, not a suite pass else: # suite-like enough for skipping return if getattr(test, "_layer_wasSetUp", False): return event = events.StartLayerSetupTestEvent(self.layer, test) self.session.hooks.startLayerSetupTest(event) self._allLayers(test, "testSetUp") test._layer_wasSetUp = True event = events.StopLayerSetupTestEvent(self.layer, test) self.session.hooks.stopLayerSetupTest(event) def tearDownTest(self, test): if self.layer is None: return if not getattr(test, "_layer_wasSetUp", None): return event = events.StartLayerTeardownTestEvent(self.layer, test) self.session.hooks.startLayerTeardownTest(event) self._allLayers(test, "testTearDown", reverse=True) event = events.StopLayerTeardownTestEvent(self.layer, test) self.session.hooks.stopLayerTeardownTest(event) delattr(test, "_layer_wasSetUp") def tearDown(self): if self.layer is None: return event = events.StartLayerTeardownEvent(self.layer) self.session.hooks.startLayerTeardown(event) teardown = self._getBoundClassmethod(self.layer, "tearDown") if teardown: teardown() event = events.StopLayerTeardownEvent(self.layer) self.session.hooks.stopLayerTeardown(event) def _safeMethodCall(self, method, result, *args): try: method(*args) return True except KeyboardInterrupt: raise except BaseException: result.addError(self, sys.exc_info()) return False def _allLayers(self, test, method, reverse=False): done = set() all_lys = util.ancestry(self.layer) if reverse: all_lys = [reversed(lys) for lys in reversed(all_lys)] for lys in all_lys: for layer in lys: if layer in done: continue self._inLayer(layer, test, method) done.add(layer) def _inLayer(self, layer, test, method): meth = self._getBoundClassmethod(layer, method) if meth: if util.num_expected_args(meth) > 1: meth(test) else: meth() def _getBoundClassmethod(self, cls, method): """ Use instead of :func:`getattr` to get only classmethods explicitly defined on ``cls`` (not methods inherited from ancestors) """ descriptor = cls.__dict__.get(method, None) if descriptor: if not isinstance(descriptor, classmethod): raise TypeError( "The %s method on a layer must be a classmethod." % method ) bound_method = descriptor.__get__(None, cls) return bound_method else: return None ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9994316 nose2-0.12.0/nose2/tests/0000775002342000234200000000000014264564615015011 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/__init__.py0000664002342000234200000000004113365700060017100 0ustar00sirosensirosen"""Unit and functional tests.""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1652471884.0 nose2-0.12.0/nose2/tests/_common.py0000664002342000234200000002115014237534114017000 0ustar00sirosensirosen"""Common functionality.""" import os.path import platform import shutil import subprocess import sys import tempfile import unittest from nose2 import discover, util from nose2._vendor import six HERE = os.path.abspath(os.path.dirname(__file__)) SUPPORT = os.path.join(HERE, "functional", "support") class TestCase(unittest.TestCase): """TestCase extension. If the class variable ``_RUN_IN_TEMP`` is ``True`` (default: ``False``), tests will be performed in a temporary directory, which is deleted afterwards. """ _RUN_IN_TEMP = False def setUp(self): super(TestCase, self).setUp() if self._RUN_IN_TEMP: self._orig_dir = os.getcwd() work_dir = self._work_dir = tempfile.mkdtemp() os.chdir(self._work_dir) # Make sure it's possible to import modules from current directory sys.path.insert(0, work_dir) def tearDown(self): super(TestCase, self).tearDown() if self._RUN_IN_TEMP: os.chdir(self._orig_dir) shutil.rmtree(self._work_dir, ignore_errors=True) def __str__(self): """ In python 3.5, the unittest.TestCase.__str__() output changed. This makes it conform to previous version. """ if sys.version_info >= (3, 5): test_module = self.__class__.__module__ test_class = self.__class__.__name__ test_method = self._testMethodName return "%s (%s.%s)" % (test_method, test_module, test_class) else: return super(TestCase, self).__str__() def id(self): """ In python 3.5, the unittest.TestCase.__id__() output changed. This makes it conform to previous version. """ if sys.version_info >= (3, 5): test_module = self.__class__.__module__ test_class = self.__class__.__name__ test_method = self._testMethodName return "%s.%s.%s" % (test_module, test_class, test_method) else: return super(TestCase, self).id() class FunctionalTestCase(unittest.TestCase): tags = ["functional"] def assertTestRunOutputMatches(self, proc, stdout=None, stderr=None): cmd_stdout, cmd_stderr = None, None try: cmd_stdout, cmd_stderr = self._output[proc.pid] except AttributeError: self._output = {} except KeyError: pass if cmd_stdout is None: cmd_stdout, cmd_stderr = proc.communicate() self._output[proc.pid] = cmd_stdout, cmd_stderr # Python 2.7 needs this # assertRegexpMatches() was renamed to assertRegex() in 3.2 testf = ( self.assertRegex if hasattr(self, "assertRegex") else self.assertRegexpMatches ) if stdout: testf(util.safe_decode(cmd_stdout), stdout) if stderr: testf(util.safe_decode(cmd_stderr), stderr) def runIn(self, testdir, *args, **kw): return run_nose2(*args, cwd=testdir, **kw) def runModuleAsMain(self, testmodule, *args): return run_module_as_main(testmodule, *args) class _FakeEventBase(object): """Baseclass for fake :class:`~nose2.events.Event`s.""" def __init__(self): self.handled = False self.version = "0.1" self.metadata = {} class FakeHandleFileEvent(_FakeEventBase): """Fake HandleFileEvent.""" def __init__(self, name): super(FakeHandleFileEvent, self).__init__() self.loader = Stub() # FIXME self.name = name self.path = os.path.split(name)[1] self.extraTests = [] class FakeStartTestEvent(_FakeEventBase): """Fake :class:`~nose2.events.StartTestEvent`.""" def __init__(self, test): super(FakeStartTestEvent, self).__init__() self.test = test self.result = test.defaultTestResult() import time self.startTime = time.time() class FakeLoadFromNameEvent(_FakeEventBase): """Fake :class:`~nose2.events.LoadFromNameEvent`.""" def __init__(self, name): super(FakeLoadFromNameEvent, self).__init__() self.name = name class FakeLoadFromNamesEvent(_FakeEventBase): """Fake :class:`~nose2.events.LoadFromNamesEvent`.""" def __init__(self, names): super(FakeLoadFromNamesEvent, self).__init__() self.names = names class FakeStartTestRunEvent(_FakeEventBase): """Fake :class:`~nose2.events.StartTestRunEvent`""" def __init__( self, runner=None, suite=None, result=None, startTime=None, executeTests=None ): super(FakeStartTestRunEvent, self).__init__() self.suite = suite self.runner = runner self.result = result self.startTime = startTime self.executeTests = executeTests class Stub(object): """Stub object for use in tests""" def __getattr__(self, attr): return Stub() def __call__(self, *arg, **kw): return Stub() def support_file(*path_parts): return os.path.abspath(os.path.join(SUPPORT, *path_parts)) def run_nose2(*nose2_args, **nose2_kwargs): if "cwd" in nose2_kwargs: cwd = nose2_kwargs.pop("cwd") if not os.path.isabs(cwd): nose2_kwargs["cwd"] = support_file(cwd) return NotReallyAProc(nose2_args, **nose2_kwargs) def run_module_as_main(test_module, *args): if not os.path.isabs(test_module): test_module = support_file(test_module) return subprocess.Popen( [sys.executable, test_module] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) class NotReallyAProc(object): def __init__(self, args, cwd=None, **kwargs): self.args = args self.chdir = cwd self.kwargs = kwargs self.result = None self._exit_code = None def __enter__(self): self._stdout = sys.__stdout__ self._stderr = sys.__stderr__ self.cwd = os.getcwd() if self.chdir: os.chdir(self.chdir) self.stdout = sys.stdout = sys.__stdout__ = six.StringIO() self.stderr = sys.stderr = sys.__stderr__ = six.StringIO() return self def __exit__(self, exc_type, exc_val, exc_tb): sys.stdout = sys.__stdout__ = self._stdout sys.stderr = sys.__stderr__ = self._stderr if self.chdir: os.chdir(self.cwd) return False def communicate(self): with self: try: self.result = discover( argv=("nose2",) + self.args, exit=False, **self.kwargs ) except SystemExit as e: self._exit_code = e.code return self.stdout.getvalue(), self.stderr.getvalue() @property def pid(self): return id(self) def poll(self): if self.result is None: return self._exit_code if self._exit_code is not None else 1 # subprocess.poll should return None or the Integer exitcode return int(not self.result.result.wasSuccessful()) class RedirectStdStreams(object): """ Context manager that replaces the stdin/stdout streams with :class:`StringIO` buffers. """ def __init__(self): self.stdout = six.StringIO() self.stderr = six.StringIO() def __enter__(self): self.old_stdout, self.old_stderr = sys.stdout, sys.stderr self.old_stdout.flush() self.old_stderr.flush() sys.stdout, sys.stderr = self.stdout, self.stderr return self def __exit__(self, exc_type, exc_value, traceback): self.stdout.flush() self.stderr.flush() sys.stdout = self.old_stdout sys.stderr = self.old_stderr # mock multiprocessing Connection class Conn(object): def __init__(self, items): self.items = items self.sent = [] self.closed = False def recv(self): if self.closed: raise EOFError("closed") try: return self.items.pop(0) except Exception: raise EOFError("EOF") def send(self, item): self.sent.append(item) def close(self): self.closed = True # true on GitHub Actions, false otherwise def environment_is_ci(): return os.getenv("CI") == "true" # special skip decorator for tests which are broken in Windows in CI def windows_ci_skip(f): return unittest.skipIf( platform.system() == "Windows" and environment_is_ci(), "This test is skipped on Windows in CI", )(f) def _method_name(name="test"): """Get an extra method name for Python 3.11""" # https://github.com/python/cpython/issues/58473 return r"\." + name if sys.version_info >= (3, 11) else "" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/0000775002342000234200000000000014264564615017153 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/__init__.py0000664002342000234200000000000013365700060021235 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9794316 nose2-0.12.0/nose2/tests/functional/support/0000775002342000234200000000000014264564615020667 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/cfg/0000775002342000234200000000000014264564615021426 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/cfg/a.cfg0000664002342000234200000000005113365700060022306 0ustar00sirosensirosen[a] a = 1 [unittest] plugins = plugin_a ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/cfg/b.cfg0000664002342000234200000000002013365700060022303 0ustar00sirosensirosen[b] b = 4 5 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/lib/0000775002342000234200000000000014264564615021435 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/functional/support/lib/layer_hooks_plugin.py0000664002342000234200000000213014220574143025665 0ustar00sirosensirosenfrom nose2 import events from nose2._vendor import six class PrintFixture(events.Plugin): alwaysOn = True def startLayerSetup(self, event): six.print_("StartLayerSetup: {0}".format(event.layer)) def stopLayerSetup(self, event): six.print_("StopLayerSetup: {0}".format(event.layer)) def startLayerSetupTest(self, event): log = "StartLayerSetupTest: {0}:{1}" six.print_(log.format(event.layer, event.test)) def stopLayerSetupTest(self, event): log = "StopLayerSetupTest: {0}:{1}" six.print_(log.format(event.layer, event.test)) def startLayerTeardownTest(self, event): log = "StartLayerTeardownTest: {0}:{1}" six.print_(log.format(event.layer, event.test)) def stopLayerTeardownTest(self, event): log = "StopLayerTeardownTest: {0}:{1}" six.print_(log.format(event.layer, event.test)) def startLayerTeardown(self, event): six.print_("StartLayerTeardown: {0}".format(event.layer)) def stopLayerTeardown(self, event): six.print_("StopLayerTeardown: {0}".format(event.layer)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/lib/plugin_a.py0000664002342000234200000000022614176405443023600 0ustar00sirosensirosenfrom nose2 import events class PluginA(events.Plugin): configSection = "a" def __init__(self): self.a = self.config.as_int("a", 0) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9794316 nose2-0.12.0/nose2/tests/functional/support/scenario/0000775002342000234200000000000014264564615022472 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/class_fixtures/0000775002342000234200000000000014264564615025530 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/class_fixtures/test_cf_testcase.py0000664002342000234200000000075314176405443031424 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): @classmethod def setUpClass(cls): cls.x = 1 def test_1(self): assert self.x def test_2(self): assert self.x class Test2(unittest.TestCase): def setUp(self): self.x = 1 def test_1(self): assert self.x def test_2(self): assert self.x class Test3(Test): # this has class setup by virtue of inheritting from Test def test_3(self): assert self.x ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9714317 nose2-0.12.0/nose2/tests/functional/support/scenario/colliding_test_modules/0000775002342000234200000000000014264564615027225 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/colliding_test_modules/tests/0000775002342000234200000000000014264564615030367 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/colliding_test_modules/tests/more_tests/0000775002342000234200000000000014264564615032553 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/colliding_test_modules/tests/more_tests/test.py0000664002342000234200000000000013365700060034055 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/colliding_test_modules/tests/test.py0000664002342000234200000000000013365700060031671 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/0000775002342000234200000000000014264564615030002 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/.coveragerc0000664002342000234200000000005514176405443032116 0ustar00sirosensirosen[report] show_missing = True fail_under = 80 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/0000775002342000234200000000000014264564615032257 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/__init__.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/__init__0000664002342000234200000000000014176405443033722 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/mod1.py0000664002342000234200000000016614176405443033467 0ustar00sirosensirosendef covered_func(): a = 1 a = a + 8 return a def uncovered_func(): b = 1 b = b + 8 return b ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under/test_mod.py0000664002342000234200000000023014176405443032160 0ustar00sirosensirosenimport unittest from covered_lib import mod1 class TestLib(unittest.TestCase): def test1(self): self.assertEqual(mod1.covered_func(), 9) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/0000775002342000234200000000000014264564615030064 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/.coveragerc0000664002342000234200000000005614176405443032201 0ustar00sirosensirosen[report] show_missing = True fail_under = 100 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/nose2.cfg0000664002342000234200000000012614176405443031565 0ustar00sirosensirosen[coverage] always-on = True coverage = part_covered_lib coverage-config = .coveragerc ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0034316 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/0000775002342000234200000000000014264564615033367 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00119 path=nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/__init__.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/__0000664002342000234200000000000014176405443033650 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021100000000000010207 xustar00115 path=nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/mod1.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/mo0000664002342000234200000000016614176405443033723 0ustar00sirosensirosendef covered_func(): a = 1 a = a + 8 return a def uncovered_func(): b = 1 b = b + 8 return b ././@PaxHeader0000000000000000000000000000021100000000000010207 xustar00115 path=nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/test_part_covered_mod.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_config_fail_under2/test_part_covered_m0000664002342000234200000000023514176405443034032 0ustar00sirosensirosenimport unittest from part_covered_lib import mod1 class TestLib(unittest.TestCase): def test1(self): self.assertEqual(mod1.covered_func(), 9) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_of_imports/0000775002342000234200000000000014264564615026526 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_of_imports/lib20171102/0000775002342000234200000000000014264564615030112 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_of_imports/lib20171102/__init__.py0000664002342000234200000000034313365700060032206 0ustar00sirosensirosen""" The __init__ file is loaded *before* the testsuite starts running in test scenarios. Therefore, even though it would be *great* if we could check that it gets counted correctly by coverage, it's better to leave it out. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_of_imports/lib20171102/mod1.py0000664002342000234200000000035214176405443031317 0ustar00sirosensirosenimport time # statement run at import time should be covered foo = 1 with open("/tmp/showme", "a") as f: f.write("\n\nbeta" + str(time.time())) raise SystemExit # so should an ordinary function body def func(): return 2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/coverage_of_imports/test_import_coverage.py0000664002342000234200000000031513365700060033306 0ustar00sirosensirosenimport unittest from lib20171102.mod1 import foo, func class TestCase(unittest.TestCase): def test1(self): self.assertEqual(foo, 1) def test2(self): self.assertEqual(func(), 2) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/decorators/0000775002342000234200000000000014264564615024637 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/decorators/test_decorators.py0000664002342000234200000000076514176405443030420 0ustar00sirosensirosenfrom nose2.tools.decorators import with_setup, with_teardown setup_performed = False teardown_performed = False def setup(): global setup_performed setup_performed = True def teardown(): global teardown_performed teardown_performed = True @with_setup(setup) def test_with_setup(): assert setup_performed, "Setup not performed." @with_teardown(teardown) def test_with_teardown(): pass def test_teardown_ran(): assert teardown_performed, "Teardown not performed." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/0000775002342000234200000000000014264564615024322 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/docs.py0000664002342000234200000000003013365700060025600 0ustar00sirosensirosen""" >>> 2 == 2 True """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/docs.rst0000664002342000234200000000002013365700060025757 0ustar00sirosensirosen>>> 1 == 1 True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/docs.txt0000664002342000234200000000004113365700060025771 0ustar00sirosensirosen>>> 2 == 2 True >>> 3 == 2 False ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/doctests_pkg1/0000775002342000234200000000000014264564615027074 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/doctests_pkg1/__init__.py0000664002342000234200000000000013365700060031156 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.py0000664002342000234200000000003013365700060030433 0ustar00sirosensirosen""" >>> 2 == 2 True """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.rst0000664002342000234200000000002013365700060030612 0ustar00sirosensirosen>>> 1 == 1 True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.txt0000664002342000234200000000004113365700060030624 0ustar00sirosensirosen>>> 2 == 2 True >>> 3 == 2 False ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/dundertest_attribute/0000775002342000234200000000000014264564615026736 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/dundertest_attribute/test.py0000664002342000234200000000016413365700060030253 0ustar00sirosensirosenimport unittest class TestDunderTest(unittest.TestCase): __test__ = False def test_a(self): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/expected_failures/0000775002342000234200000000000014264564615026165 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/expected_failures/expected_failures.py0000664002342000234200000000051514176405443032226 0ustar00sirosensirosenimport unittest class TestWithExpectedFailures(unittest.TestCase): @unittest.expectedFailure def test_should_fail(self): assert False @unittest.expectedFailure def test_should_pass(self): assert True def test_whatever(self): assert True def test_fails(self): assert False ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9714317 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/0000775002342000234200000000000014264564615024344 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/chdir/0000775002342000234200000000000014264564615025435 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/chdir/test_junitxml_chdir.py0000664002342000234200000000056414176405443032071 0ustar00sirosensirosenimport os.path import shutil import tempfile import unittest class Test(unittest.TestCase): def setUp(self): super(Test, self).setUp() self.temp_dir = tempfile.mkdtemp() def tearDown(self): super(Test, self).tearDown() shutil.rmtree(self.temp_dir, ignore_errors=True) def test_chdir(self): os.chdir(self.temp_dir) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/empty_properties/0000775002342000234200000000000014264564615027756 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/empty_properties/properties.json0000664002342000234200000000000013365700060033016 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/empty_properties/test_junitxml_empty_properties.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/empty_properties/test_junitxml_empty_p0000664002342000234200000000012214176405443034335 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/empty_properties/unittest.cfg0000664002342000234200000000013013365700060032273 0ustar00sirosensirosen[junit-xml] always-on = False keep_restricted = False test_properties = properties.json ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/fail_to_write/0000775002342000234200000000000014264564615027173 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/fail_to_write/test_junitxml_fail_to_write.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/fail_to_write/test_junitxml_fail_to_wr0000664002342000234200000000012214176405443034222 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/fail_to_write/unittest.cfg0000664002342000234200000000012113365700060031510 0ustar00sirosensirosen[junit-xml] always-on = False keep_restricted = False path = /does/not/exist.xml ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0074315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/happyday/0000775002342000234200000000000014264564615026163 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/happyday/test_junitxml_happyday.py0000664002342000234200000000012214176405443033333 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/missing_properties/0000775002342000234200000000000014264564615030271 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00126 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/missing_properties/test_junitxml_missing_properties.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/missing_properties/test_junitxml_missi0000664002342000234200000000012214176405443034317 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/missing_properties/unittest.cfg0000664002342000234200000000013013365700060032606 0ustar00sirosensirosen[junit-xml] always-on = False keep_restricted = False test_properties = properties.json ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/non_default_path/0000775002342000234200000000000014264564615027656 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/non_default_path/test_junitxml_non_default_path.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/non_default_path/test_junitxml_non_def0000664002342000234200000000015314176405443034174 0ustar00sirosensirosen# -*- coding: utf-8 -*- import unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/non_default_path/unittest.cfg0000664002342000234200000000003114176405443032203 0ustar00sirosensirosen[junit-xml] path = a.xml ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/skip_reason/0000775002342000234200000000000014264564615026661 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/skip_reason/test_junitxml_skip_reason.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/skip_reason/test_junitxml_skip_reason.0000664002342000234200000000015514176405443034164 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): @unittest.skip("ohai") def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/skip_reason/unittest.cfg0000664002342000234200000000011214176405443031206 0ustar00sirosensirosen[unittest] plugins = nose2.plugins.junitxml [junit-xml] always-on = True ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/with_properties/0000775002342000234200000000000014264564615027573 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/with_properties/test_junitxml_with_properties.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/with_properties/test_junitxml_with_pro0000664002342000234200000000012214176405443034330 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/junitxml/with_properties/unittest.cfg0000664002342000234200000000013013365700060032110 0ustar00sirosensirosen[junit-xml] always-on = False keep_restricted = False test_properties = properties.json ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/layers/0000775002342000234200000000000014264564615023771 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers/test_layers.py0000664002342000234200000000723214176405443026700 0ustar00sirosensirosenimport unittest STATE = {} class Base(object): @classmethod def setUp(cls): STATE["base"] = "setup" @classmethod def tearDown(cls): del STATE["base"] class LayerA(Base): position = 1 @classmethod def setUp(cls): STATE["layerA"] = "setup" @classmethod def tearDown(cls): del STATE["layerA"] @classmethod def testSetUp(cls, test): STATE["layerA.test"] = "setup" # print "->", STATE, test @classmethod def testTearDown(cls, test): # print "<-", STATE, test del STATE["layerA.test"] class LayerA_1(LayerA): position = 0 @classmethod def setUp(cls): STATE["layerA_1"] = "setup" @classmethod def tearDown(cls): del STATE["layerA_1"] class LayerB(LayerA): position = 2 @classmethod def setUp(cls): STATE["layerB"] = "setup" @classmethod def tearDown(cls): del STATE["layerB"] class LayerB_1(LayerB): position = 0 @classmethod def setUp(cls): STATE["layerB_1"] = "setup" @classmethod def tearDown(cls): del STATE["layerB_1"] class LayerC(LayerB, LayerA): position = 1 @classmethod def setUp(cls): STATE["layerC"] = "setup" @classmethod def tearDown(cls): del STATE["layerC"] class LayerD(Base): position = 0 @classmethod def setUp(cls): STATE["layerD"] = "setup" @classmethod def tearDown(cls): del STATE["layerD"] class Outer(unittest.TestCase): layer = Base def test(self): self.assertEqual(STATE.get("base"), "setup") class InnerA(unittest.TestCase): layer = LayerA def setUp(self): STATE["innerA.test"] = "setup" def tearDown(self): del STATE["innerA.test"] def test(self): expect = { "base": "setup", "layerA": "setup", "innerA.test": "setup", "layerA.test": "setup", } for k, v in expect.items(): self.assertEqual(STATE.get(k), v) class InnerA_1(unittest.TestCase): layer = LayerA_1 def test(self): expect = { "base": "setup", "layerA": "setup", "layerA_1": "setup", "layerA.test": "setup", } for k, v in expect.items(): self.assertEqual(STATE.get(k), v) class InnerB(unittest.TestCase): layer = LayerB def setUp(self): STATE["innerB.test"] = "setup" def tearDown(self): STATE["innerB.test"] = "tearDown" class InnerB_1(unittest.TestCase): layer = LayerB_1 def test(self): expect = {"base": "setup", "layerB": "setup", "layerB_1": "setup"} for k, v in expect.items(): self.assertEqual(STATE.get(k), v) class InnerC(unittest.TestCase): layer = LayerC def test(self): expect = { "base": "setup", "layerB": "setup", "layerC": "setup", "layerA": "setup", "layerA.test": "setup", } for k, v in expect.items(): self.assertEqual(STATE.get(k), v) def test2(self): expect = { "base": "setup", "layerB": "setup", "layerC": "setup", "layerA": "setup", "layerA.test": "setup", } for k, v in expect.items(): self.assertEqual(STATE.get(k), v) class InnerD(unittest.TestCase): layer = LayerD def test(self): """test with docstring""" self.assertEqual({"base": "setup", "layerD": "setup"}, STATE) class NoLayer(unittest.TestCase): def test(self): self.assertEqual(STATE, {}) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_attributes/0000775002342000234200000000000014264564615027061 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_attributes/test_layers_and_attributes.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_attributes/test_layers_and_attribute0000664002342000234200000000115614176405443034245 0ustar00sirosensirosenimport unittest STATE = {} class L1(object): @classmethod def setUp(cls): STATE["L1"] = "setup" @classmethod def tearDown(cls): del STATE["L1"] class L2(object): @classmethod def setUp(cls): STATE["L2"] = "setup" @classmethod def tearDown(cls): del STATE["L2"] class LayerAndAttributesA(unittest.TestCase): layer = L1 a = 1 def test(self): self.assertEqual(STATE.get("L1"), "setup") class LayerAndAttributesB(unittest.TestCase): layer = L2 b = 1 def test(self): self.assertEqual(STATE.get("L2"), "setup") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/0000775002342000234200000000000014264564615027044 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/__init__.py0000664002342000234200000000000013365700060031126 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/common.py0000664002342000234200000000267414264464446030720 0ustar00sirosensirosenimport logging import unittest log = logging.getLogger(__name__) class UniqueResource(object): _instance = None used = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(UniqueResource, cls).__new__(cls, *args, **kwargs) return cls._instance def lock(self): if not self.used: self.used = True else: raise Exception("Resource already used") def unlock(self): if self.used: self.used = False else: raise Exception("Resource already unlocked") class NormalTest(unittest.TestCase): @classmethod def setUpClass(cls): log.info("Called setUpClass in NormalTest") cls.unique_resource = UniqueResource() cls.unique_resource.lock() @classmethod def tearDownClass(cls): log.info("Called tearDownClass in NormalTest") cls.unique_resource.unlock() def test(self): self.assertTrue(self.unique_resource.used) class NormalTestTwo(unittest.TestCase): @classmethod def setUpClass(cls): log.info("Called setUpClass in NormalTestTwo") cls.unique_resource = UniqueResource() cls.unique_resource.lock() @classmethod def tearDownClass(cls): log.info("Called tearDownClass in NormalTestTwo") cls.unique_resource.unlock() def test(self): self.assertTrue(self.unique_resource.used) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/test_layers.py0000664002342000234200000000253314176405443031752 0ustar00sirosensirosenimport logging import unittest from .common import NormalTest, NormalTestTwo, UniqueResource # noqa: F401 log = logging.getLogger(__name__) class Layer1(object): @classmethod def setUp(cls): log.info("Called setup in layer 1") cls.unique_resource = UniqueResource() cls.unique_resource.lock() @classmethod def tearDown(cls): log.info("Called teardown in layer 2") cls.unique_resource.unlock() class Layer2(object): @classmethod def setUp(cls): log.info("Called setup in layer 2") cls.unique_resource = UniqueResource() cls.unique_resource.lock() @classmethod def tearDown(cls): log.info("Called teardown in layer 2") cls.unique_resource.unlock() class Layer3(Layer2): @classmethod def setUp(cls): log.info("Called setup in layer 3") @classmethod def tearDown(cls): log.info("Called teardown in layer 3") class LayerTest1(unittest.TestCase): layer = Layer1 def test(self): self.assertTrue(self.layer.unique_resource.used) class LayerTest2(unittest.TestCase): layer = Layer2 def test(self): self.assertTrue(self.layer.unique_resource.used) class LayerTest3(unittest.TestCase): layer = Layer2 def test(self): self.assertTrue(self.layer.unique_resource.used) ././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_has_setup.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_has_setup.0000664002342000234200000000114714176405443034152 0ustar00sirosensirosenimport logging from nose2.tools import such from .common import NormalTest, NormalTestTwo, UniqueResource # noqa: F401 log = logging.getLogger(__name__) with such.A("system with setup") as it: @it.has_setup def setup(): log.info("Called setup in such test") it.unique_resource = UniqueResource() it.unique_resource.lock() @it.has_teardown def teardown(): log.info("Called teardown in such test") it.unique_resource.unlock() @it.should("do something") def test(case): it.assertTrue(it.unique_resource.used) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_uses_decorator.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_uses_decor0000664002342000234200000000213214176405443034227 0ustar00sirosensirosenimport logging from nose2.tools import such from .common import NormalTest, NormalTestTwo, UniqueResource # noqa: F401 log = logging.getLogger(__name__) class Layer1(object): description = "Layer1" @classmethod def setUp(cls): log.info("Called setup in layer 1") it.unique_resource = UniqueResource() it.unique_resource.lock() @classmethod def tearDown(cls): log.info("Called teardown in layer 2") it.unique_resource.unlock() class Layer2(object): description = "Layer2" @classmethod def setUp(cls): log.info("Called setup in layer 2") @classmethod def tearDown(cls): log.info("Called teardown in layer 2") with such.A("system with setup") as it: it.uses(Layer1) @it.should("do something") def test(case): it.assertTrue(it.unique_resource.used) with it.having("another setup"): it.uses(Layer2) @it.should("do something else") # noqa: F811 def test(case): # noqa: F811 it.assertTrue(it.unique_resource.used) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0114315 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_hooks/0000775002342000234200000000000014264564615025174 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_hooks/test_layers_simple.py0000664002342000234200000000262014176405443031450 0ustar00sirosensirosenimport unittest class Layer1(object): layer_setup = 0 test_setup = 0 test_teardown = 0 layer_teardown = 0 tests_count = 0 @classmethod def setUp(cls): if cls.layer_setup >= 1: raise Exception("layer_setup already ran") cls.layer_setup += 1 @classmethod def testSetUp(cls): if cls.test_setup >= 2: raise Exception("test_setup already ran twice") cls.test_setup += 1 @classmethod def testTearDown(cls): if cls.test_teardown >= 2: raise Exception("test_teardown already ran twice") cls.test_teardown += 1 @classmethod def tearDown(cls): if cls.layer_teardown >= 1: raise Exception("layer_teardown already ran") cls.layer_teardown += 1 class TestSimple(unittest.TestCase): layer = Layer1 def test_1(self): assert self.layer.layer_setup == 1 assert self.layer.test_setup == self.layer.tests_count + 1 assert self.layer.test_teardown == self.layer.tests_count assert self.layer.layer_teardown == 0 self.layer.tests_count += 1 def test_2(self): assert self.layer.layer_setup == 1 assert self.layer.test_setup == self.layer.tests_count + 1 assert self.layer.test_teardown == self.layer.tests_count assert self.layer.layer_teardown == 0 self.layer.tests_count += 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_hooks/test_simple_such.py0000664002342000234200000000022414176405443031111 0ustar00sirosensirosenfrom nose2.tools import such with such.A("system") as it: @it.should("do something") def test(): pass it.createTests(globals()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/0000775002342000234200000000000014264564615025374 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/higher_layer_setup.py0000664002342000234200000000145414176405443031627 0ustar00sirosensirosenimport logging from nose2.tools import such log = logging.getLogger(__name__) with such.A("foo") as it: it.upper_run = 0 it.lower_run = 0 @it.has_setup def upper_test_setup(case): log.error("foo::setUp") it.upper_run += 1 with it.having("some bar"): @it.has_setup def lower_test_setup(case): log.error("foo some bar::setUp") it.lower_run += 1 @it.should("run all setups") def test_run_all_setups(case): case.assertEqual(it.upper_run, 1) case.assertEqual(it.lower_run, 1) @it.should("run all setups just once") def test_run_all_setups_just_once(case): case.assertEqual(it.upper_run, 1) case.assertEqual(it.lower_run, 1) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_3layers.py0000664002342000234200000000221114176405443034161 0ustar00sirosensirosenimport logging from nose2.tools import such log = logging.getLogger(__name__) with such.A("foo") as it: it.upper_run = 0 it.mid_run = 0 it.lower_run = 0 @it.has_test_setup def upper_test_setup(case): log.error("foo::setUp") it.upper_run += 1 with it.having("some bar"): @it.has_test_setup def middle_test_setup(case): log.error("foo some bar::setUp") it.mid_run += 1 with it.having("and more"): @it.has_test_setup def lower_test_setup(case): log.error("foo some bar and more::setUp") it.lower_run += 1 @it.should("run all setups") def test_run_all_setups(case): case.assertEqual(it.upper_run, 1) case.assertEqual(it.mid_run, 1) case.assertEqual(it.lower_run, 1) @it.should("run all setups again") def test_run_all_setups_again(case): case.assertEqual(it.upper_run, 2) case.assertEqual(it.mid_run, 2) case.assertEqual(it.lower_run, 2) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_no_test.py0000664002342000234200000000145614176405443034264 0ustar00sirosensirosenimport logging from nose2.tools import such log = logging.getLogger(__name__) with such.A("foo") as it: it.upper_run = 0 it.lower_run = 0 @it.has_test_setup def upper_test_setup(case): log.error("foo::setUp") it.upper_run += 1 with it.having("some bar"): @it.has_test_setup def lower_test_setup(case): log.error("foo some bar::setUp") it.lower_run += 1 @it.should("run all setups") def test_run_all_setups(case): case.assertEqual(it.upper_run, 1) case.assertEqual(it.lower_run, 1) @it.should("run all setups again") def test_run_all_setups_again(case): case.assertEqual(it.upper_run, 2) case.assertEqual(it.lower_run, 2) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_with_test.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_with_test.0000664002342000234200000000171314176405443034246 0ustar00sirosensirosenimport logging from nose2.tools import such log = logging.getLogger(__name__) with such.A("foo") as it: it.upper_run = 0 it.lower_run = 0 @it.has_test_setup def upper_test_setup(case): log.error("foo::setUp") it.upper_run += 1 @it.should("run upper setups") def test_run_upper_setups(case): case.assertEqual(it.upper_run, 1) case.assertEqual(it.lower_run, 0) with it.having("some bar"): @it.has_test_setup def lower_test_setup(case): log.error("foo some bar::setUp") it.lower_run += 1 @it.should("run all setups") def test_run_all_setups(case): case.assertEqual(it.upper_run, 2) case.assertEqual(it.lower_run, 1) @it.should("run all setups again") def test_run_all_setups_again(case): case.assertEqual(it.upper_run, 3) case.assertEqual(it.lower_run, 2) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/0000775002342000234200000000000014264564615026420 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_layer_setup_fail.py0000664002342000234200000000033514176405443033354 0ustar00sirosensirosenimport unittest class Layer(object): @classmethod def setUp(cls): raise RuntimeError("Bad Error in Layer setUp!") class Test(unittest.TestCase): layer = Layer def testPass(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_layer_teardown_fail.py0000664002342000234200000000043614176405443034041 0ustar00sirosensirosenimport unittest class Layer(object): @classmethod def setUp(cls): pass @classmethod def testTearDown(cls): raise RuntimeError("Bad Error in Layer testTearDown!") class Test(unittest.TestCase): layer = Layer def testPass(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_layers_with_errors.py0000664002342000234200000000063114176405443033752 0ustar00sirosensirosenimport unittest class Layer(object): description = "fixture with a value" @classmethod def setUp(cls): cls.value = 1 class Test(unittest.TestCase): layer = Layer def test_ok(self): self.assertEqual(self.layer.value, 1) def test_fail(self): self.assertEqual(self.layer.value, 2) def test_err(self): self.assertEqual(self.layer.mulch, "pine") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_such_setup_fail.py0000664002342000234200000000043314176405443033201 0ustar00sirosensirosenfrom nose2.tools import such with such.A("test scenario with errors") as it: @it.has_setup def setup_fail(): raise RuntimeError("Bad Error in such setUp!") @it.should("check that value == 1") def test_passes(case): pass it.createTests(globals()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_such_teardown_fail.py0000664002342000234200000000044414176405443033666 0ustar00sirosensirosenfrom nose2.tools import such with such.A("test scenario with errors") as it: @it.has_teardown def teardown_fail(): raise RuntimeError("Bad Error in such tearDown!") @it.should("check that value == 1") def test_passes(case): pass it.createTests(globals()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_errors/test_such_with_errors.py0000664002342000234200000000102714176405443033415 0ustar00sirosensirosenfrom nose2.tools import such with such.A("test scenario with errors") as it: @it.has_setup def set_value(): it.value = 1 @it.should("check that value == 1") def test_passes(case): case.assertEqual(it.value, 1) @it.should("check that value == 2 and fail") def test_fails(case): case.assertEqual(it.value, 2) @it.should("check for an attribute that does not exist and raise an error") def test_err(case): case.assertEqual(it.mulch, "pine") it.createTests(globals()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_inheritance/0000775002342000234200000000000014264564615027375 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_inheritance/test_layers_with_inheritance.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/layers_with_inheritance/test_layers_with_inheri0000664002342000234200000000132714176405443034245 0ustar00sirosensirosenimport unittest class L1(object): @classmethod def setUp(cls): print("L1 setUp") @classmethod def testSetUp(cls): print("L1 testSetUp") @classmethod def tearDown(cls): print("L1 tearDown") @classmethod def testTearDown(cls): print("L1 testTearDown") class L2(L1): @classmethod def setUp(cls): print("L2 setUp") @classmethod def testSetUp(cls): print("L2 testSetUp") @classmethod def testTearDown(cls): print("L2 testTearDown") # L1 tearDown should only run once class T1(unittest.TestCase): layer = L2 def test1(self): print("Run test1") def test2(self): print("Run test2") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests/0000775002342000234200000000000014264564615024633 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests/test_filter.py0000664002342000234200000000037514176405443027531 0ustar00sirosensirosenimport unittest class TestCase(unittest.TestCase): def test_a(self): pass def test_b(self): pass def test_c(self): pass def load_tests(loader, tests, pattern): del tests._tests[0]._tests[1] return tests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests/test_simple.py0000664002342000234200000000052614176405443027533 0ustar00sirosensirosenimport unittest class TestCase(unittest.TestCase): def test_a(self): pass def test_b(self): pass def test_c(self): pass def load_tests(loader, tests, pattern): class InnerTest(unittest.TestCase): def test_d(self): pass tests.addTest(InnerTest("test_d")) return tests ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/0000775002342000234200000000000014264564615025474 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/0000775002342000234200000000000014264564615026615 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/__init__.py0000664002342000234200000000003713365700060030711 0ustar00sirosensirosendef gt(a, b): return a > b ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/tests/0000775002342000234200000000000014264564615027757 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/tests/__init__.py0000664002342000234200000000045013365700060032052 0ustar00sirosensirosenimport os def load_tests(loader, standard_tests, pattern): # top level directory cached on loader instance this_dir = os.path.dirname(__file__) package_tests = loader.discover(start_dir=this_dir, pattern=pattern) standard_tests.addTests(package_tests) return standard_tests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/tests/test_find_these.py0000664002342000234200000000012214176405443033466 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/0000775002342000234200000000000014264564615026677 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/__init__.py0000664002342000234200000000003713365700060030773 0ustar00sirosensirosendef lt(a, b): return a < b ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/tests/0000775002342000234200000000000014264564615030041 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/tests/__init__.py0000664002342000234200000000041714176405443032147 0ustar00sirosensirosenimport unittest def load_tests(loader, standard_tests, pattern): suite = loader.suiteClass() class Test(unittest.TestCase): def test(self): import ltpkg2 assert ltpkg2.lt(1, 2) suite.addTest(Test("test")) return suite ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/tests/test_skip_these.py0000664002342000234200000000017014176405443033601 0ustar00sirosensirosenimport unittest class Test(unittest.TestCase): def test(self): raise Exception("this should not execute") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/load_tests_pkg/unittest.cfg0000664002342000234200000000004513365700060030016 0ustar00sirosensirosen[unittest] test-file-pattern = test* ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0154316 nose2-0.12.0/nose2/tests/functional/support/scenario/logging/0000775002342000234200000000000014264564615024120 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=nose2-0.12.0/nose2/tests/functional/support/scenario/logging/logging_keeps_copies_of_mutable_objects.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/logging/logging_keeps_copies_of_mutable_objects0000664002342000234200000000050214176405443034120 0ustar00sirosensirosenimport logging import unittest import nose2 log = logging.getLogger(__name__) class Test(unittest.TestCase): def test_logging_keeps_copies_of_mutable_objects(self): d = {} log.debug("foo: %s", d) d["bar"] = "baz" self.assertTrue(False) if __name__ == "__main__": nose2.main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/logging_config/0000775002342000234200000000000014264564615025445 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/logging_config/logging_config.py0000664002342000234200000000041014176405443030760 0ustar00sirosensirosenimport logging import unittest import nose2 log = logging.getLogger(__name__) class Test(unittest.TestCase): def test_logging_config(self): log.debug("foo") log.info("bar") assert False if __name__ == "__main__": nose2.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/logging_config/nose2.cfg0000664002342000234200000000016614176405443027152 0ustar00sirosensirosen[log-capture] always-on = True format = "[%%(name)s] [%%(levelname)s] %%(message)s" [pretty-assert] always-on = True ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/many_tests/0000775002342000234200000000000014264564615024660 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/many_tests/test_gen_many_func.py0000664002342000234200000000013014176405443031066 0ustar00sirosensirosendef check(_): pass def test(): for i in range(0, 600): yield check, i ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/many_tests_socket/0000775002342000234200000000000014264564615026230 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/many_tests_socket/nose2.cfg0000664002342000234200000000005014176405443027725 0ustar00sirosensirosen[multiprocess] bind_address = 127.0.0.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/many_tests_socket/test_gen_many_socket_func.py0000664002342000234200000000013014176405443034006 0ustar00sirosensirosendef check(_): pass def test(): for i in range(0, 600): yield check, i ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/module_fixtures/0000775002342000234200000000000014264564615025710 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_fixtures/test_mf_func.py0000664002342000234200000000026113365700060030720 0ustar00sirosensirosenTHINGS = [] def setUpModule(): THINGS.append(1) def tearDownModule(): while THINGS: THINGS.pop() def test(): assert THINGS, "setup didn't run I think" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_fixtures/test_mf_gen_func.py0000664002342000234200000000032413365700060031551 0ustar00sirosensirosenTHINGS = [] def setUpModule(): THINGS.append(1) def tearDownModule(): while THINGS: THINGS.pop() def check(_): assert THINGS, "setup didn't run I think" def test(): yield check, 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_fixtures/test_mf_param_func.py0000664002342000234200000000031214176405443032105 0ustar00sirosensirosenTHINGS = [] def setUpModule(): THINGS.append(1) def tearDownModule(): while THINGS: THINGS.pop() def test(p): assert THINGS, "setup didn't run I think" test.paramList = (1,) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_fixtures/test_mf_testcase.py0000664002342000234200000000045014176405443031610 0ustar00sirosensirosenimport unittest THINGS = [] def setUpModule(): THINGS.append(1) def tearDownModule(): while THINGS: THINGS.pop() class Test(unittest.TestCase): def test_1(self): assert THINGS, "setup didn't run" def test_2(self): assert THINGS, "setup didn't run" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/0000775002342000234200000000000014264564615026221 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/pkg/0000775002342000234200000000000014264564615027002 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/pkg/__init__.py0000664002342000234200000000000013365700060031064 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/pkg/test_attribute_err.py0000664002342000234200000000016414176405443033262 0ustar00sirosensirosenimport unittest def test_foo(): pass class TestFoo(unittest.TestCase): def test_foo(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/pkg/test_import_err.py0000664002342000234200000000022214176405443032564 0ustar00sirosensirosenraise ValueError("booms") import unittest # noqa: E402 def test(): pass class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/module_import_err/test_import_err.py0000664002342000234200000000020514176405443032004 0ustar00sirosensirosenimport unittest raise ImportError("booms") def test(): pass class Test(unittest.TestCase): def test(self): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/no_tests/0000775002342000234200000000000014264564615024330 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/no_tests/a.py0000664002342000234200000000002713365700060025104 0ustar00sirosensirosen"""An empty module.""" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/one_test/0000775002342000234200000000000014264564615024312 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/one_test/tests.py0000664002342000234200000000021614176405443026020 0ustar00sirosensirosenimport unittest import nose2 class Test(unittest.TestCase): def test(self): pass if __name__ == "__main__": nose2.main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/package_in_lib/0000775002342000234200000000000014264564615025401 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9754317 nose2-0.12.0/nose2/tests/functional/support/scenario/package_in_lib/lib/0000775002342000234200000000000014264564615026147 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/package_in_lib/lib/pkg2/0000775002342000234200000000000014264564615027012 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/package_in_lib/lib/pkg2/__init__.py0000664002342000234200000000016113365700060031104 0ustar00sirosensirosenimport logging log = logging.getLogger(__name__) def get_one(): log.debug("Returning %s", 1) return 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/package_in_lib/tests.py0000664002342000234200000000061614176405443027113 0ustar00sirosensirosenimport logging import unittest from pkg2 import get_one log = logging.getLogger(__name__) log.debug("module imported") def test(): log.debug("test run") assert get_one() == 1 def test_fail(): log.debug("test_fail run") assert get_one() == 2 class Tests(unittest.TestCase): def test_fail2(self): log.debug("test_fail2 run") self.assertEqual(get_one(), 4) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9754317 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/0000775002342000234200000000000014264564615025565 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/assign_after_assert/0000775002342000234200000000000014264564615031613 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/assign_after_assert/test_assign_after_assert.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/assign_after_assert/test_assign_0000664002342000234200000000033414176405443034213 0ustar00sirosensirosendef test_demo(): """ Assign a value to `x` after an assert Testsuite will want to ensure that we print `x = 1`, which was the value at the time of the assert """ x = 1 assert x == 2 x = 2 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0194316 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution/0000775002342000234200000000000014264564615032053 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution/test_prettyassert_attribute_resolution.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution/test_pretty0000664002342000234200000000030714176405443034357 0ustar00sirosensirosenimport unittest class TestFoo(unittest.TestCase): x = 1 def test_ohnoez(self): x = self # fmt: off assert x.x != (self ).x # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution2/0000775002342000234200000000000014264564615032135 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution2/test_prettyassert_attribute_resolution2.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution2/test_prett0000664002342000234200000000026014176405443034246 0ustar00sirosensirosenimport unittest class TestFoo(unittest.TestCase): def test_ohnoez(self): self.x = 1 def foo(): return self assert foo().x != self.x ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/conf_on/0000775002342000234200000000000014264564615027206 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/conf_on/nose2.cfg0000664002342000234200000000004114176405443030703 0ustar00sirosensirosen[pretty-assert] always-on = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/conf_on/test_conf_on.py0000664002342000234200000000011314176405443032226 0ustar00sirosensirosenmyglob = 1 def test_w_global(): global myglob assert myglob == 2 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/0000775002342000234200000000000014264564615030574 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/__init__.py0000664002342000234200000000000014176405443032666 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022600000000000010215 xustar00128 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/test_prettyassert_ignore_passing.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/test_prettyassert0000664002342000234200000000047314176405443034326 0ustar00sirosensirosenimport unittest class TestFailAssert(unittest.TestCase): def test_failing_assert(self): x = True y = False # fmt: off # flake8: noqa assert x; assert y # fmt: on def test_failing_assert2(self): p = 1 q = 0 assert p assert q ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_funcdef/0000775002342000234200000000000014264564615031261 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_funcdef/test_multiline_funcdef.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_funcdef/test_multiline0000664002342000234200000000040314176405443034235 0ustar00sirosensirosenfrom nose2.tools.params import params # fmt: off # multiline function definition def test_demo( ): x = 1 y = 2 assert x > y, "oh noez, x <= y" @params(('foo',), ('bar',)) def test_multiline_deco(value): assert not value # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_statement/0000775002342000234200000000000014264564615031653 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_statement/test_multiline_statement.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/multiline_statement/test_multili0000664002342000234200000000020014176405443034277 0ustar00sirosensirosendef test_demo(): x = 1 y = 2 # fmt: off assert (x > y), "oh noez, x <= y" # fmt: on ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/simple_global/0000775002342000234200000000000014264564615030376 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/simple_global/test_simple_global.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/simple_global/test_simple_global0000664002342000234200000000011314176405443034157 0ustar00sirosensirosenmyglob = 1 def test_w_global(): global myglob assert myglob == 2 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/0000775002342000234200000000000014264564615031533 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/__init__.py0000664002342000234200000000000014176405443033625 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/test_prettyassert_unittestassertion.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/test_prettyas0000664002342000234200000000020314176405443034356 0ustar00sirosensirosenimport unittest class TestFoo(unittest.TestCase): def test_old_assertion(self): x = False self.assertTrue(x) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/slow/0000775002342000234200000000000014264564615023456 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/slow/test_slow.py0000664002342000234200000000066714176405443026057 0ustar00sirosensirosenimport logging import time import unittest log = logging.getLogger(__name__) class TestSlow(unittest.TestCase): def test_ok(self): print("hide this") time.sleep(2) def test_fail(self): print("show this") log.debug("hola") time.sleep(2) self.assertEqual(1, 2) def test_err(self): print("show this too") log.debug("ciao") time.sleep(2) {}["x"] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/subtests/0000775002342000234200000000000014264564615024346 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/subtests/test_subtests.py0000664002342000234200000000143614176405443027632 0ustar00sirosensirosenimport unittest class Case(unittest.TestCase): def test_subtest_success(self): for i in range(3): with self.subTest(i=i): self.assertTrue(i < 3) def test_subtest_failure(self): for i in range(6): with self.subTest(i=i): self.assertEqual(i % 2, 0) def test_subtest_error(self): for i in range(3): with self.subTest(i=i): raise RuntimeError(i) @unittest.expectedFailure def test_subtest_expected_failure(self): for i in range(6): with self.subTest(i=i): self.assertEqual(i % 2, 0) def test_subtest_message(self): for i in range(6): with self.subTest("msg", i=i): self.assertEqual(i % 2, 0) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/such_with_params/0000775002342000234200000000000014264564615026032 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/such_with_params/such_with_params.py0000664002342000234200000000067214176405443031744 0ustar00sirosensirosenfrom nose2.tools import such from nose2.tools.params import params with such.A("foo") as it: @it.should("do bar") @params(1, 2, 3) def test(case, bar): case.assertTrue(isinstance(bar, int)) @it.should("do bar and extra") @params((1, 2), (3, 4), (5, 6)) def testExtraArg(case, bar, foo): case.assertTrue(isinstance(bar, int)) case.assertTrue(isinstance(foo, int)) it.createTests(globals()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_class_fail/0000775002342000234200000000000014264564615025631 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_class_fail/test_class_fail.py0000664002342000234200000000045114176405443031335 0ustar00sirosensirosenclass Test(object): def __init__(self): raise RuntimeError( "Something bad happened but other tests should still be run!" ) def test(self): raise RuntimeError( "Something bad happened but other tests should still be run! RUNNING" ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes/0000775002342000234200000000000014264564615025166 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes/test_classes.py0000664002342000234200000000037714176405443030236 0ustar00sirosensirosenclass Test(object): def test(self): pass def test_gen(self): def check(a): pass for i in range(0, 5): yield check, i def test_params(self, a): pass test_params.paramList = (1, 2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes/test_fixtures.py0000664002342000234200000000116314176405443030444 0ustar00sirosensirosenclass Test(object): @classmethod def setUpClass(cls): cls.setup = 1 @classmethod def tearDownClass(cls): del cls.setup def setUp(self): self.test_setup = 1 def tearDown(self): del self.test_setup def test(self): assert self.test_setup assert self.setup def test_gen(self): def check(a): assert self.test_setup assert self.setup for i in range(0, 2): yield check, i def test_params(self, a): assert self.test_setup assert self.setup test_params.paramList = (1, 2) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0234315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes_mp/0000775002342000234200000000000014264564615025662 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes_mp/test_classes_mp.py0000664002342000234200000000037714176405443031426 0ustar00sirosensirosenclass Test(object): def test(self): pass def test_gen(self): def check(a): pass for i in range(0, 5): yield check, i def test_params(self, a): pass test_params.paramList = (1, 2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_classes_mp/test_fixtures_mp.py0000664002342000234200000000116314176405443031634 0ustar00sirosensirosenclass Test(object): @classmethod def setUpClass(cls): cls.setup = 1 @classmethod def tearDownClass(cls): del cls.setup def setUp(self): self.test_setup = 1 def tearDown(self): del self.test_setup def test(self): assert self.test_setup assert self.setup def test_gen(self): def check(a): assert self.test_setup assert self.setup for i in range(0, 2): yield check, i def test_params(self, a): assert self.test_setup assert self.setup test_params.paramList = (1, 2) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9794316 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/0000775002342000234200000000000014264564615026651 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/0000775002342000234200000000000014264564615030771 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/.coveragerc0000664002342000234200000000003513365700060033073 0ustar00sirosensirosen[report] show_missing = True ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00118 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_coveragerc/ 28 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_cov0000775002342000234200000000000014264564615034036 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_coveragerc/__init__.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_cov0000664002342000234200000000000013365700060034011 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_coveragerc/mod1.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_cov0000664002342000234200000000016613365700060034026 0ustar00sirosensirosendef covered_func(): a = 1 a = a + 8 return a def uncovered_func(): b = 1 b = b + 8 return b ././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/test_coveragerc.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/test_coveragerc0000664002342000234200000000024313365700060034055 0ustar00sirosensirosenimport unittest from covered_lib_coveragerc import mod1 class TestLib(unittest.TestCase): def test1(self): self.assertEqual(mod1.covered_func(), 9) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/0000775002342000234200000000000014264564615030357 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose2cfg/ 28 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose20000775002342000234200000000000014264564615033663 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose2cfg/__init__.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose20000664002342000234200000000000013365700060033636 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose2cfg/mod1.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose20000664002342000234200000000016613365700060033653 0ustar00sirosensirosendef covered_func(): a = 1 a = a + 8 return a def uncovered_func(): b = 1 b = b + 8 return b ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/nose2.cfg0000664002342000234200000000013414176405443032057 0ustar00sirosensirosen[coverage] always-on = True coverage-report = term-missing coverage = covered_lib_nose2cfg/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/test_nose2cfg.py0000664002342000234200000000024113365700060033456 0ustar00sirosensirosenimport unittest from covered_lib_nose2cfg import mod1 class TestLib(unittest.TestCase): def test1(self): self.assertEqual(mod1.covered_func(), 9) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_with_module/0000775002342000234200000000000014264564615026051 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/test_with_module/lib/0000775002342000234200000000000014264564615026617 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_with_module/lib/__init__.py0000664002342000234200000000000013365700060030701 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_with_module/lib/mod1.py0000664002342000234200000000016613365700060030017 0ustar00sirosensirosendef covered_func(): a = 1 a = a + 8 return a def uncovered_func(): b = 1 b = b + 8 return b ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/test_with_module/test_coverage.py0000664002342000234200000000022013365700060031232 0ustar00sirosensirosenimport unittest from lib import mod1 class TestLib(unittest.TestCase): def test1(self): self.assertEqual(mod1.covered_func(), 9) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/0000775002342000234200000000000014264564615025775 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/docs.rst0000664002342000234200000000002013365700060027432 0ustar00sirosensirosen>>> 1 == 1 True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/docs.txt0000664002342000234200000000004113365700060027444 0ustar00sirosensirosen>>> 2 == 2 True >>> 3 == 2 False ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/0000775002342000234200000000000014264564615026637 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/__init__.py0000664002342000234200000000000213365700060030723 0ustar00sirosensirosen# ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/mod1.py0000664002342000234200000000022014176405443030036 0ustar00sirosensirosendef some_other_func(): """This is a function with an inline doctest. >>> a = 1 >>> b = 2 >>> a == b False """ pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0274315 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/0000775002342000234200000000000014264564615027616 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/__init__.py0000664002342000234200000000000213365700060031702 0ustar00sirosensirosen# ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py0000664002342000234200000000322714176405443032522 0ustar00sirosensirosenimport unittest class SomeTests(unittest.TestCase): tags = ["case"] def test_ok(self): pass test_ok.tags = ["method", "pass"] test_ok.a = 0 test_ok.b = 1 def test_typeerr(self): raise TypeError("oops") test_typeerr.tags = ["method"] def test_failed(self): print("Hello stdout") assert False, "I failed" test_failed.tags = ["method"] def test_skippy(self): raise unittest.SkipTest("I wanted to skip") test_skippy.a = 1 test_skippy.b = 1 def test_gen_method(self): def check(x): assert x == 1 check.b = 2 yield check, 1 yield check, 2 test_gen_method.a = 1 test_gen_method.b = 1 def test_params_method(self, a): self.assertEqual(a, 1) test_params_method.paramList = (1, 2) test_params_method.a = 1 def test_func(): assert 1 == 1 test_func.a = 1 test_func.b = 0 test_func.tags = ["func", "pass"] def test_gen(): def check(a, b): assert a == b check.tags = ["func"] for i in range(0, 5): yield check, (i, i) test_gen.testGenerator = True test_gen.tags = ["func"] def test_gen_nose_style(): def check(a, b): assert a == b for i in range(0, 5): yield check, i, i did_setup = False def setup(): global did_setup did_setup = True def test_fixt(): assert did_setup test_fixt.setup = setup def test_params_func(a): assert a == 1 test_params_func.paramList = (1, 2) test_params_func.tags = ["func"] def test_params_func_multi_arg(a, b): assert a == b test_params_func_multi_arg.paramList = ((1, 1), (1, 2), (2, 2)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/setup.py0000664002342000234200000000020214176405443027474 0ustar00sirosensirosenfrom setuptools import find_packages, setup setup(name="pkg1", packages=find_packages(), test_suite="nose2.collector.collector") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_package/unittest.cfg0000664002342000234200000000014313365700060030316 0ustar00sirosensirosen[outcomes] treat-as-skip = IOError TodoError TypeError treat-as-fail = GlormpError ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0314314 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/0000775002342000234200000000000014264564615027245 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/docs.rst0000664002342000234200000000002013365700060030702 0ustar00sirosensirosen>>> 1 == 1 True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/docs.txt0000664002342000234200000000004113365700060030714 0ustar00sirosensirosen>>> 2 == 2 True >>> 3 == 2 False ././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00111 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/ 28 mtime=1657989516.9794316 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000775002342000234200000000000014264564615033044 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00120 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/ 28 mtime=1657989517.0314314 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000775002342000234200000000000014264564615033044 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00131 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/SOURCES.txt 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000040113365700060033024 0ustar00sirosensirosensetup.py pkgunegg/__init__.py pkgunegg/mod1.py pkgunegg.egg-info/PKG-INFO pkgunegg.egg-info/SOURCES.txt pkgunegg.egg-info/dependency_links.txt pkgunegg.egg-info/top_level.txt pkgunegg.egg-info/zip-safe pkgunegg/test/__init__.py pkgunegg/test/test_things.py ././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/dependency_links.txt 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000000014176405443033027 0ustar00sirosensirosen././@PaxHeader0000000000000000000000000000023300000000000010213 xustar00133 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/top_level.txt 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000001113365700060033021 0ustar00sirosensirosenpkgunegg ././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00120 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/ 28 mtime=1657989517.0314314 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000775002342000234200000000000014264564615033044 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00131 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/__init__.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000000213365700060033021 0ustar00sirosensirosen# ././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/mod1.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000022014176405443033033 0ustar00sirosensirosendef some_other_func(): """This is a function with an inline doctest. >>> a = 1 >>> b = 2 >>> a == b False """ pass ././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00125 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/test/ 28 mtime=1657989517.0314314 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000775002342000234200000000000014264564615033044 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/test/__init__.py 22 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000000213365700060033021 0ustar00sirosensirosen# ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/test/test_things.py 22 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg0000664002342000234200000000322714176405443033045 0ustar00sirosensirosenimport unittest class SomeTests(unittest.TestCase): tags = ["case"] def test_ok(self): pass test_ok.tags = ["method", "pass"] test_ok.a = 0 test_ok.b = 1 def test_typeerr(self): raise TypeError("oops") test_typeerr.tags = ["method"] def test_failed(self): print("Hello stdout") assert False, "I failed" test_failed.tags = ["method"] def test_skippy(self): raise unittest.SkipTest("I wanted to skip") test_skippy.a = 1 test_skippy.b = 1 def test_gen_method(self): def check(x): assert x == 1 check.b = 2 yield check, 1 yield check, 2 test_gen_method.a = 1 test_gen_method.b = 1 def test_params_method(self, a): self.assertEqual(a, 1) test_params_method.paramList = (1, 2) test_params_method.a = 1 def test_func(): assert 1 == 1 test_func.a = 1 test_func.b = 0 test_func.tags = ["func", "pass"] def test_gen(): def check(a, b): assert a == b check.tags = ["func"] for i in range(0, 5): yield check, (i, i) test_gen.testGenerator = True test_gen.tags = ["func"] def test_gen_nose_style(): def check(a, b): assert a == b for i in range(0, 5): yield check, i, i did_setup = False def setup(): global did_setup did_setup = True def test_fixt(): assert did_setup test_fixt.setup = setup def test_params_func(a): assert a == 1 test_params_func.paramList = (1, 2) test_params_func.tags = ["func"] def test_params_func_multi_arg(a, b): assert a == b test_params_func_multi_arg.paramList = ((1, 1), (1, 2), (2, 2)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/setup.py0000664002342000234200000000024414176405443030752 0ustar00sirosensirosenfrom setuptools import find_packages, setup setup( name="pkg1", packages=find_packages(), zip_safe=True, test_suite="nose2.collector.collector", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/unittest.cfg0000664002342000234200000000014313365700060031566 0ustar00sirosensirosen[outcomes] treat-as-skip = IOError TodoError TypeError treat-as-fail = GlormpError ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0314314 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_zipped_eggs/0000775002342000234200000000000014264564615026702 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_zipped_eggs/docs.rst0000664002342000234200000000002013365700060030337 0ustar00sirosensirosen>>> 1 == 1 True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_zipped_eggs/docs.txt0000664002342000234200000000004113365700060030351 0ustar00sirosensirosen>>> 2 == 2 True >>> 3 == 2 False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tests/functional/support/scenario/tests_in_zipped_eggs/pkgegg-0.0.0-py2.7.egg0000664002342000234200000001225213365700060032125 0ustar00sirosensirosenPK VVD EGG-INFO/UT I}SI}Sux "PK VVDpkgegg/UT I}SI}Sux "PK VVD pkgegg/test/UT I}SI}Sux "PK D2EGG-INFO/dependency_links.txtUT ZxpSI}Sux " PKtVD-{EGG-INFO/SOURCES.txtUT J}SuJ}Sux "+N-)-+*NOMO׏,GO1DpX73/-_?]C"?45XC.% 5/%5/2>'3/ԲUʼni0`s7XDėddPKwVDPKuEGG-INFO/PKG-INFOUT "J}S)J}Sux "M-ILI,I K-*ϳR03KMR(NOMO!WpinnbQBG~nnAbz*Bȱ$#LN+FZ\YP &X_PK D2EGG-INFO/zip-safeUT ZxpSI}Sux " PK zVD{,EGG-INFO/top_level.txtUT (J}SuJ}Sux "pkgegg PKD7dpkgegg/__init__.pycUT ZxpSuJ}Sux "c\@,@"!X$C#uDRifN~RJfq^Nf^inY~jz~Av~||f^fI|^Ae PMn~JiNb9PK R[Dpkgegg/__init__.pyUT L#pSI}Sux "# PKDMљ5ypkgegg/mod1.pycUT ZxpSuJ}Sux "O 0?pR-)ZIKikRLƾ"R]=r"Z{H_hb ů 1v,tNb#0 DG(g'$'۬>o:b[R.2dlG]S6iLE^%&q ,1c⹧Ȧ H ])Iqq6lБ/ؠ`:L  n ?= kIRx> #6J*-}*PI}>"< a ;d!9|̅x%M+77PKD8ϲ pkgegg/test/test_things.pycUT ZxpSuJ}Sux "WoD˗僔%pBx@#-M_ԏHrn.N|ջ')P&1^x}KEœY{v~4=~|Y$x݁&!EA%؆ioo^@hrPYUƒ*Hi o:腁1y wCM5lN_lghL,*ƬBKD,SA9T(:= (3, 8), "FIXME: this test fails on modern pythons on macos", ) @windows_ci_skip def test_run_with_mp(self): # this test needs to be done with nose2 config because (as of 2019-12) # multiprocessing does not allow each test process to pick up on # command line arguments # run with 4 processes -- this will fail if `coverage` isn't running in # a "parallel" mode (with a "data suffix" set and combining results for # reporting) proc = self.runIn( "scenario/test_coverage_config/nose2cfg", "-v", "--plugin=nose2.plugins.mp", "-N", "4", ) self.assertProcOutputPattern( proc, "covered_lib_nose2cfg", r"\s+8\s+5\s+38%\s+1, 7-10", total_stats=r"\s+8\s+5\s+38%", ) # FIXME: figure out why this fails and remove @skip @unittest.skip("fails in testsuite but passes in real-world conditions") def test_measures_imports(self): proc = self.runIn( "scenario/coverage_of_imports", "-v", "--with-coverage", "--coverage=lib20171102/", ) self.assertProcOutputPattern(proc, "lib20171102", stats=r"\s+3\s+0\s+100%") def test_run_coverage_fail_under(self): STATS = r"\s+8\s+5\s+38%\s+1, 7-10" TOTAL_STATS = r"\s+8\s+5\s+38%\s" proc = self.runIn( "scenario/coverage_config_fail_under", "-v", "--with-coverage", "--coverage=covered_lib/", ) self.assertProcOutputPattern( proc, "covered_lib", STATS, total_stats=TOTAL_STATS, assert_exit_status=1 ) def test_run_coverage_fail_under2(self): """Check with coverage settings in config, not CLI""" STATS = r"\s+8\s+5\s+38%\s+1, 7-10" TOTAL_STATS = r"\s+8\s+5\s+38%\s" proc = self.runIn("scenario/coverage_config_fail_under2", "-v") self.assertProcOutputPattern( proc, "part_covered_lib", STATS, total_stats=TOTAL_STATS, assert_exit_status=1, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_decorators.py0000664002342000234200000000130314176405443022721 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase class DecoratorsTests(FunctionalTestCase): def test_with_setup(self): process = self.runIn("scenario/decorators", "test_decorators.test_with_setup") self.assertTestRunOutputMatches(process, stderr="Ran 1 test") self.assertEqual(process.poll(), 0, process.stderr.getvalue()) def test_with_teardown(self): process = self.runIn( "scenario/decorators", "test_decorators.test_with_teardown", "test_decorators.test_teardown_ran", ) self.assertTestRunOutputMatches(process, stderr="Ran 2 test") self.assertEqual(process.poll(), 0, process.stderr.getvalue()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_discovery_loader.py0000664002342000234200000000601014176405443024111 0ustar00sirosensirosenfrom nose2 import events, loader, session from nose2.plugins.loader.discovery import DiscoveryLoader from nose2.tests._common import FunctionalTestCase, TestCase, support_file class Watcher(events.Plugin): def __init__(self): self.called = [] def loadTestsFromModule(self, event): self.called.append(event) class DiscoveryFunctionalTest(FunctionalTestCase): def setUp(self): self.session = session.Session() self.plug = DiscoveryLoader(session=self.session) self.loader = loader.PluggableTestLoader(self.session) self.watcher = Watcher(session=self.session) self.watcher.register() def test_can_discover_test_modules_in_packages(self): self.session.startDir = support_file("scenario/tests_in_package") event = events.LoadFromNamesEvent(self.loader, [], None) result = self.session.hooks.loadTestsFromNames(event) assert isinstance(result, self.loader.suiteClass) self.assertEqual(len(result._tests), 1) self.assertEqual(len(self.watcher.called), 1) self.assertEqual( self.watcher.called[0].module.__name__, "pkg1.test.test_things" ) def test_discovery_supports_code_in_lib_dir(self): self.session.startDir = support_file("scenario/package_in_lib") event = events.LoadFromNamesEvent(self.loader, [], None) result = self.session.hooks.loadTestsFromNames(event) assert isinstance(result, self.loader.suiteClass) self.assertEqual(len(result._tests), 1) self.assertEqual(len(self.watcher.called), 1) self.assertEqual(self.watcher.called[0].module.__name__, "tests") def test_match_path_event_can_prevent_discovery(self): class NoTestsForYou(events.Plugin): def matchPath(self, event): event.handled = True return False mp = NoTestsForYou(session=self.session) mp.register() self.session.startDir = support_file("scenario/tests_in_package") event = events.LoadFromNamesEvent(self.loader, [], None) result = self.session.hooks.loadTestsFromNames(event) assert isinstance(result, self.loader.suiteClass) self.assertEqual(len(result._tests), 0) self.assertEqual(len(self.watcher.called), 0) def test_handle_file_event_can_add_tests(self): class TextTest(TestCase): def test(self): pass class TestsInText(events.Plugin): def handleFile(self, event): if event.path.endswith(".txt"): event.extraTests.append(TextTest("test")) mp = TestsInText(session=self.session) mp.register() self.session.startDir = support_file("scenario/tests_in_package") event = events.LoadFromNamesEvent(self.loader, [], None) result = self.session.hooks.loadTestsFromNames(event) assert isinstance(result, self.loader.suiteClass) self.assertEqual(len(result._tests), 2) self.assertEqual(len(self.watcher.called), 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_doctests_plugin.py0000664002342000234200000000427214176405443023772 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase, support_file class TestDoctestsPlugin(FunctionalTestCase): def test_simple(self): proc = self.runIn( "scenario/doctests", "-v", "--plugin=nose2.plugins.doctests", "--with-doctest", ) self.assertTestRunOutputMatches(proc, stderr="Ran 6 tests") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs ... ok") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs.rst ... ok") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs.txt ... ok") self.assertTestRunOutputMatches( proc, stderr="Doctest: doctests_pkg1.docs1 ... ok" ) self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.rst ... ok") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.txt ... ok") self.assertEqual(proc.poll(), 0) def test_start_directory_inside_package(self): proc = self.runIn( "scenario/doctests/doctests_pkg1", "-v", "--plugin=nose2.plugins.doctests", "--with-doctest", "-t", support_file("scenario/doctests"), ) self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertTestRunOutputMatches( proc, stderr="Doctest: doctests_pkg1.docs1 ... ok" ) self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.rst ... ok") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.txt ... ok") self.assertEqual(proc.poll(), 0) def test_project_directory_inside_package(self): proc = self.runIn( "scenario/doctests/doctests_pkg1", "-v", "--plugin=nose2.plugins.doctests", "--with-doctest", ) self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertTestRunOutputMatches( proc, stderr="Doctest: doctests_pkg1.docs1 ... ok" ) self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.rst ... ok") self.assertTestRunOutputMatches(proc, stderr="Doctest: docs1.txt ... ok") self.assertEqual(proc.poll(), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_dundertest_plugin.py0000664002342000234200000000040514176405443024315 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase class TestDunderTestPlugin(FunctionalTestCase): def test_dunder(self): proc = self.runIn("scenario/dundertest_attribute", "-v") self.assertTestRunOutputMatches(proc, stderr="Ran 0 tests") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956667.0 nose2-0.12.0/nose2/tests/functional/test_eggdiscovery_loader.py0000664002342000234200000000575214264464473024616 0ustar00sirosensirosenimport sys # This unused import is not very elegant, but it allows eggdiscovery to be found in # Travis (or when run with PYTHONPATH=.) import nose2.plugins.loader.eggdiscovery # noqa: F401 from nose2.tests._common import FunctionalTestCase, support_file try: import pkg_resources except ImportError: pkg_resources = None else: class EggDiscoveryFunctionalTest(FunctionalTestCase): def setUp(self): for m in [m for m in sys.modules if m.startswith("pkgegg")]: del sys.modules[m] self.egg_path = support_file( "scenario/tests_in_zipped_eggs/pkgegg-0.0.0-py2.7.egg" ) sys.path.append(self.egg_path) def tearDown(self): if self.egg_path in sys.path: sys.path.remove(self.egg_path) for m in [m for m in sys.modules if m.startswith("pkgegg")]: del sys.modules[m] def test_non_egg_discoverer_does_not_fail_when_looking_in_egg(self): proc = self.runIn("scenario/tests_in_zipped_eggs", "-v", "pkgegg") self.assertTestRunOutputMatches(proc, stderr="Ran 0 tests in") def test_can_discover_test_modules_in_zipped_eggs(self): proc = self.runIn( "scenario/tests_in_zipped_eggs", "-v", "--plugin=nose2.plugins.loader.eggdiscovery", "pkgegg", ) self.assertTestRunOutputMatches( proc, stderr=r"FAILED \(failures=5, errors=1, skipped=1\)" ) def test_eggdiscovery_failure_does_not_exist(self): proc = self.runIn( "scenario", "-v", "--plugin=nose2.plugins.loader.eggdiscovery", "--exclude-plugin=nose2.plugins.loader.discovery", "-s", "tests_in_zipped_eggs_BAD", ) self.assertTestRunOutputMatches( proc, stderr="tests_in_zipped_eggs_BAD does not exist" ) class UnzippedEggDiscoveryFunctionalTest(FunctionalTestCase): def setUp(self): for m in [m for m in sys.modules if m.startswith("pkgegg")]: del sys.modules[m] self.egg_path = support_file( "scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg" ) sys.path.append(self.egg_path) def tearDown(self): if self.egg_path in sys.path: sys.path.remove(self.egg_path) for m in [m for m in sys.modules if m.startswith("pkgunegg")]: del sys.modules[m] def test_eggdiscovery_ignores_unzipped_eggs(self): proc = self.runIn( "scenario/tests_in_unzipped_eggs", "-v", "--plugin=nose2.plugins.loader.eggdiscovery", "pkgunegg", ) self.assertTestRunOutputMatches( proc, stderr=r"FAILED \(failures=5, errors=1, skipped=1\)" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657942290.0 nose2-0.12.0/nose2/tests/functional/test_junitxml_plugin.py0000664002342000234200000002344114264430422024004 0ustar00sirosensirosenimport os from xml.etree import ElementTree as ET from nose2.tests._common import FunctionalTestCase, TestCase, _method_name, support_file class JunitXmlPluginFunctionalTest(FunctionalTestCase, TestCase): _RUN_IN_TEMP = True def run_with_junitxml_loaded(self, scenario, *args, **kwargs): work_dir = os.getcwd() test_dir = support_file(*scenario) junit_report = os.path.join( work_dir, kwargs.get("junit_report", "nose2-junit.xml") ) config = os.path.join(test_dir, "unittest.cfg") config_args = () if os.path.exists(junit_report): os.remove(junit_report) if os.path.exists(config): config_args = ("-c", config) proc = self.runIn( work_dir, "-s%s" % test_dir, "--plugin=nose2.plugins.junitxml", "-v", *(config_args + args) ) return junit_report, proc def test_invocation_by_double_dash_option(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "happyday"), "--junit-xml" ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_happyday.Test" + _method_name() + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) self.assertTrue( os.path.isfile(junit_report), "junitxml report wasn't found in working directory. " "Searched for " + junit_report, ) def test_invocation_by_single_dash_option(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "happyday"), "-X" ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_happyday.Test" + _method_name() + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) self.assertTrue( os.path.isfile(junit_report), "junitxml report wasn't found in working directory. " "Searched for " + junit_report, ) def test_implicit_registration_by_path_option(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "happyday"), "--junit-xml-path=b.xml", junit_report="b.xml", ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_happyday.Test" + _method_name() + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) self.assertTrue( os.path.isfile(junit_report), "junitxml report wasn't found in working directory. " "Searched for " + junit_report, ) def test_no_report_written_if_loaded_but_not_invoked(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "happyday") ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_happyday.Test" + _method_name() + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) self.assertFalse( os.path.isfile(junit_report), "junitxml report was found in working directory. " "Report file: " + junit_report, ) def test_report_location_should_be_resilent_to_chdir_in_tests(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "chdir"), "--junit-xml" ) self.assertTestRunOutputMatches( proc, stderr=r"test_chdir \(test_junitxml_chdir.Test" + _method_name("test_chdir") + r"\) \.* ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) self.assertTrue( os.path.isfile(junit_report), "junitxml report wasn't found in working directory. " "Searched for " + junit_report, ) def test_report_includes_properties(self): work_dir = os.getcwd() with open(os.path.join(work_dir, "properties.json"), "w") as fh: fh.write('{"PROPERTY_NAME":"PROPERTY_VALUE"}') junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "with_properties"), "--junit-xml" ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_with_properties.Test" + _method_name() + r"\) \.* ok", ) self.assertEqual(proc.poll(), 0) with open(junit_report, "r") as fh: tree = ET.parse(fh).getroot() self.assertEqual(len(tree.findall("properties")), 1) prop = tree.find("properties").find("property") assert "name" in prop.attrib assert "value" in prop.attrib self.assertEqual(prop.get("name"), "PROPERTY_NAME") self.assertEqual(prop.get("value"), "PROPERTY_VALUE") def test_skip_reason_in_message(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "skip_reason"), "--junit-xml" ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_skip_reason.Test" + _method_name() + r"\) \.* skip", ) exit_status = proc.poll() assert exit_status == 0 with open(junit_report, "r") as fh: tree = ET.parse(fh).getroot() num_test_cases = len(tree.findall("testcase")) assert num_test_cases == 1 num_skipped = len(tree.find("testcase").findall("skipped")) assert num_skipped == 1 skip_node = tree.find("testcase").find("skipped") assert "message" in skip_node.attrib skip_message = skip_node.get("message") assert skip_message == "test skipped: ohai" def test_xml_path_override_by_config(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "non_default_path"), "--junit-xml", junit_report="a.xml", ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_non_default_path.Test" + _method_name() + r"\) \.* ok", ) exit_status = proc.poll() assert exit_status == 0 self.assertTrue(os.path.isfile(junit_report)) def test_xml_path_override_by_command(self): junit_report, proc = self.run_with_junitxml_loaded( ("scenario", "junitxml", "non_default_path"), "--junit-xml", "--junit-xml-path=b.xml", junit_report="b.xml", ) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_non_default_path.Test" + _method_name() + r"\) \.* ok", ) exit_status = proc.poll() assert exit_status == 0 self.assertTrue(os.path.isfile(junit_report)) class JunitXmlPluginFunctionalFailureTest(FunctionalTestCase, TestCase): def test_failure_to_write_report(self): proc = self.runIn( "scenario/junitxml/fail_to_write", "--plugin=nose2.plugins.junitxml", "-v", "--junit-xml", ) self.assertEqual(proc.poll(), 1) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_fail_to_write.Test" + _method_name() + r"\) \.* ok", ) filename_for_regex = os.path.abspath("/does/not/exist.xml") filename_for_regex = filename_for_regex.replace("\\", r"\\\\") self.assertTestRunOutputMatches( proc, stderr=r"Internal Error: runTests aborted: \[Errno 2\] " "JUnitXML: Parent folder does not exist for file: " "'%s'" % filename_for_regex, ) def test_failure_to_read_missing_properties(self): proc = self.runIn( "scenario/junitxml/missing_properties", "--plugin=nose2.plugins.junitxml", "-v", "--junit-xml", ) self.assertEqual(proc.poll(), 1) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_missing_properties.Test" + _method_name() + r"\) \.* ok", ) filename_for_regex = os.path.join("missing_properties", "properties.json") filename_for_regex = filename_for_regex.replace("\\", r"\\\\") self.assertTestRunOutputMatches( proc, stderr=r"Internal Error: runTests aborted: \[Errno 2\] " "JUnitXML: Properties file does not exist: " "'.*%s'" % filename_for_regex, ) def test_failure_to_read_empty_properties(self): proc = self.runIn( "scenario/junitxml/empty_properties", "--plugin=nose2.plugins.junitxml", "-v", "--junit-xml", ) self.assertEqual(proc.poll(), 1) self.assertTestRunOutputMatches( proc, stderr=r"test \(test_junitxml_empty_properties.Test" + _method_name() + r"\) \.* ok", ) filename_for_regex = os.path.join("empty_properties", "properties.json") filename_for_regex = filename_for_regex.replace("\\", r"\\") self.assertTestRunOutputMatches( proc, stderr="Internal Error: runTests aborted: " "JUnitXML: could not decode file: " "'.*%s'" % filename_for_regex, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/tests/functional/test_layers_hooks.py0000664002342000234200000005067314264464446023302 0ustar00sirosensirosenimport os import sys from nose2.tests._common import FunctionalTestCase class TestLayerHooks(FunctionalTestCase): @classmethod def setUp(cls): filepath = os.path.dirname(os.path.realpath(__file__)) cls.libpath = os.path.join(filepath, "support", "lib") sys.path.append(cls.libpath) @classmethod def tearDown(cls): if cls.libpath in sys.path: sys.path.remove(cls.libpath) def test_simple_such(self): proc = self.runIn( "scenario/layers_hooks", "--plugin=nose2.plugins.layers", "--plugin=layer_hooks_plugin", "test_simple_such", ) if sys.version_info >= (3, 11): expected = r"""^StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something \(test_simple_such.A system.test 0000: should do something\) StopLayerSetupTest: :test 0000: should do something \(test_simple_such.A system.test 0000: should do something\) StartLayerTeardownTest: :test 0000: should do something \(test_simple_such.A system.test 0000: should do something\) StopLayerTeardownTest: :test 0000: should do something \(test_simple_such.A system.test 0000: should do something\) StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 else: expected = r"""^StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something \(test_simple_such.A system\) StopLayerSetupTest: :test 0000: should do something \(test_simple_such.A system\) StartLayerTeardownTest: :test 0000: should do something \(test_simple_such.A system\) StopLayerTeardownTest: :test 0000: should do something \(test_simple_such.A system\) StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stdout=expected) self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_complex_such(self): proc = self.runIn( "such/", "--plugin=nose2.plugins.layers", "--plugin=layer_hooks_plugin", "test_such", ) if sys.version_info >= (3, 11): expected = r"""StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something \(test_such.A system with complex setup.test 0000: should do something\) StopLayerSetupTest: :test 0000: should do something \(test_such.A system with complex setup.test 0000: should do something\) StartLayerTeardownTest: :test 0000: should do something \(test_such.A system with complex setup.test 0000: should do something\) StopLayerTeardownTest: :test 0000: should do something \(test_such.A system with complex setup.test 0000: should do something\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do more things \(test_such.having an expensive fixture.test 0000: should do more things\) StopLayerSetupTest: :test 0000: should do more things \(test_such.having an expensive fixture.test 0000: should do more things\) StartLayerTeardownTest: :test 0000: should do more things \(test_such.having an expensive fixture.test 0000: should do more things\) StopLayerTeardownTest: :test 0000: should do more things \(test_such.having an expensive fixture.test 0000: should do more things\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do that not this \(test_such.having another precondition.test 0000: should do that not this\) StopLayerSetupTest: :test 0000: should do that not this \(test_such.having another precondition.test 0000: should do that not this\) StartLayerTeardownTest: :test 0000: should do that not this \(test_such.having another precondition.test 0000: should do that not this\) StopLayerTeardownTest: :test 0000: should do that not this \(test_such.having another precondition.test 0000: should do that not this\) StartLayerSetupTest: :test 0001: should do this not that \(test_such.having another precondition.test 0001: should do this not that\) StopLayerSetupTest: :test 0001: should do this not that \(test_such.having another precondition.test 0001: should do this not that\) StartLayerTeardownTest: :test 0001: should do this not that \(test_such.having another precondition.test 0001: should do this not that\) StopLayerTeardownTest: :test 0001: should do this not that \(test_such.having another precondition.test 0001: should do this not that\) StartLayerTeardown: StopLayerTeardown: StartLayerSetup: StopLayerSetup: StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something else \(test_such.having a different precondition.test 0000: should do something else\) StopLayerSetupTest: :test 0000: should do something else \(test_such.having a different precondition.test 0000: should do something else\) StartLayerTeardownTest: :test 0000: should do something else \(test_such.having a different precondition.test 0000: should do something else\) StopLayerTeardownTest: :test 0000: should do something else \(test_such.having a different precondition.test 0000: should do something else\) StartLayerSetupTest: :test 0001: should have another test \(test_such.having a different precondition.test 0001: should have another test\) StopLayerSetupTest: :test 0001: should have another test \(test_such.having a different precondition.test 0001: should have another test\) StartLayerTeardownTest: :test 0001: should have another test \(test_such.having a different precondition.test 0001: should have another test\) StopLayerTeardownTest: :test 0001: should have another test \(test_such.having a different precondition.test 0001: should have another test\) StartLayerSetupTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition.test 0002: should have access to an external fixture\) StopLayerSetupTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition.test 0002: should have access to an external fixture\) StartLayerTeardownTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition.test 0002: should have access to an external fixture\) StopLayerTeardownTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition.test 0002: should have access to an external fixture\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture.test 0000: should still have access to that fixture\) StopLayerSetupTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture.test 0000: should still have access to that fixture\) StartLayerTeardownTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture.test 0000: should still have access to that fixture\) StopLayerTeardownTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture.test 0000: should still have access to that fixture\) StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 else: expected = r"""StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something \(test_such.A system with complex setup\) StopLayerSetupTest: :test 0000: should do something \(test_such.A system with complex setup\) StartLayerTeardownTest: :test 0000: should do something \(test_such.A system with complex setup\) StopLayerTeardownTest: :test 0000: should do something \(test_such.A system with complex setup\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do more things \(test_such.having an expensive fixture\) StopLayerSetupTest: :test 0000: should do more things \(test_such.having an expensive fixture\) StartLayerTeardownTest: :test 0000: should do more things \(test_such.having an expensive fixture\) StopLayerTeardownTest: :test 0000: should do more things \(test_such.having an expensive fixture\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do that not this \(test_such.having another precondition\) StopLayerSetupTest: :test 0000: should do that not this \(test_such.having another precondition\) StartLayerTeardownTest: :test 0000: should do that not this \(test_such.having another precondition\) StopLayerTeardownTest: :test 0000: should do that not this \(test_such.having another precondition\) StartLayerSetupTest: :test 0001: should do this not that \(test_such.having another precondition\) StopLayerSetupTest: :test 0001: should do this not that \(test_such.having another precondition\) StartLayerTeardownTest: :test 0001: should do this not that \(test_such.having another precondition\) StopLayerTeardownTest: :test 0001: should do this not that \(test_such.having another precondition\) StartLayerTeardown: StopLayerTeardown: StartLayerSetup: StopLayerSetup: StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should do something else \(test_such.having a different precondition\) StopLayerSetupTest: :test 0000: should do something else \(test_such.having a different precondition\) StartLayerTeardownTest: :test 0000: should do something else \(test_such.having a different precondition\) StopLayerTeardownTest: :test 0000: should do something else \(test_such.having a different precondition\) StartLayerSetupTest: :test 0001: should have another test \(test_such.having a different precondition\) StopLayerSetupTest: :test 0001: should have another test \(test_such.having a different precondition\) StartLayerTeardownTest: :test 0001: should have another test \(test_such.having a different precondition\) StopLayerTeardownTest: :test 0001: should have another test \(test_such.having a different precondition\) StartLayerSetupTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition\) StopLayerSetupTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition\) StartLayerTeardownTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition\) StopLayerTeardownTest: :test 0002: should have access to an external fixture \(test_such.having a different precondition\) StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture\) StopLayerSetupTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture\) StartLayerTeardownTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture\) StopLayerTeardownTest: :test 0000: should still have access to that fixture \(test_such.having a case inside the external fixture\) StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 self.assertTestRunOutputMatches(proc, stderr="Ran 9 tests") self.assertTestRunOutputMatches(proc, stdout=expected) self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_simple_layers(self): proc = self.runIn( "scenario/layers_hooks", "--plugin=nose2.plugins.layers", "--plugin=layer_hooks_plugin", "test_layers_simple", ) if sys.version_info >= (3, 11): expected = r"""^StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test_1 \(test_layers_simple.TestSimple.test_1\) StopLayerSetupTest: :test_1 \(test_layers_simple.TestSimple.test_1\) StartLayerTeardownTest: :test_1 \(test_layers_simple.TestSimple.test_1\) StopLayerTeardownTest: :test_1 \(test_layers_simple.TestSimple.test_1\) StartLayerSetupTest: :test_2 \(test_layers_simple.TestSimple.test_2\) StopLayerSetupTest: :test_2 \(test_layers_simple.TestSimple.test_2\) StartLayerTeardownTest: :test_2 \(test_layers_simple.TestSimple.test_2\) StopLayerTeardownTest: :test_2 \(test_layers_simple.TestSimple.test_2\) StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 else: expected = r"""^StartLayerSetup: StopLayerSetup: StartLayerSetupTest: :test_1 \(test_layers_simple.TestSimple\) StopLayerSetupTest: :test_1 \(test_layers_simple.TestSimple\) StartLayerTeardownTest: :test_1 \(test_layers_simple.TestSimple\) StopLayerTeardownTest: :test_1 \(test_layers_simple.TestSimple\) StartLayerSetupTest: :test_2 \(test_layers_simple.TestSimple\) StopLayerSetupTest: :test_2 \(test_layers_simple.TestSimple\) StartLayerTeardownTest: :test_2 \(test_layers_simple.TestSimple\) StopLayerTeardownTest: :test_2 \(test_layers_simple.TestSimple\) StartLayerTeardown: StopLayerTeardown: \n*$""" # noqa: E501 self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertTestRunOutputMatches(proc, stdout=expected) self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1652471884.0 nose2-0.12.0/nose2/tests/functional/test_layers_plugin.py0000664002342000234200000001213514237534114023432 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase, _method_name class TestLayers(FunctionalTestCase): def test_runs_layer_fixtures(self): proc = self.runIn("scenario/layers", "-v", "--plugin=nose2.plugins.layers") self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertEqual(proc.poll(), 0) def test_scenario_fails_without_plugin(self): proc = self.runIn("scenario/layers", "-v") self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=7\)") self.assertEqual(proc.poll(), 1) def test_methods_run_once_per_class(self): proc = self.runIn( "scenario/layers_with_inheritance", "-v", "--plugin=nose2.plugins.layers" ) expected = ( "^" "L1 setUp\n" "L2 setUp\n" "L1 testSetUp\n" "L2 testSetUp\n" "Run test1\n" "L2 testTearDown\n" "L1 testTearDown\n" "L1 testSetUp\n" "L2 testSetUp\n" "Run test2\n" "L2 testTearDown\n" "L1 testTearDown\n" "L1 tearDown\n" "$" ) self.assertTestRunOutputMatches(proc, stdout=expected) self.assertEqual(proc.poll(), 0) def test_layer_reporter_output(self): proc = self.runIn( "scenario/layers", "-v", "--plugin=nose2.plugins.layers", "--layer-reporter" ) expect = ( r"""test \(test_layers.NoLayer""" + _method_name() + r"""\) ... ok Base test \(test_layers.Outer""" + _method_name() + r"""\) ... ok LayerD test \(test_layers.InnerD""" + _method_name() + r"""\) test with docstring ... ok LayerA test \(test_layers.InnerA""" + _method_name() + r"""\) ... ok LayerB LayerB_1 test \(test_layers.InnerB_1""" + _method_name() + r"""\) ... ok LayerC test \(test_layers.InnerC""" + _method_name() + r"""\) ... ok test2 \(test_layers.InnerC""" + _method_name("test2") + r"""\) ... ok LayerA_1 test \(test_layers.InnerA_1""" + _method_name() + r"""\) ... ok""" ).split("\n") self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") for line in expect: self.assertTestRunOutputMatches(proc, stderr=line) self.assertEqual(proc.poll(), 0) def test_layer_reporter_error_output(self): proc = self.runIn( "scenario/layers_with_errors", "--plugin=nose2.plugins.layers", "--layer-reporter", ) expect = [ r"ERROR: fixture with a value test_err \(test_layers_with_errors.Test" + _method_name("test_err") + r"\)", "ERROR: A test scenario with errors should check for an attribute " "that does not exist and raise an error", r"FAIL: fixture with a value test_fail \(test_layers_with_errors.Test" + _method_name("test_fail") + r"\)", "FAIL: A test scenario with errors should check that value == 2 " "and fail", ] for line in expect: self.assertTestRunOutputMatches(proc, stderr=line) self.assertEqual(proc.poll(), 1) def test_layers_and_attributes(self): proc = self.runIn( "scenario/layers_and_attributes", "-v", "--plugin=nose2.plugins.attrib", "--plugin=nose2.plugins.layers", "-A", "a=1", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) def test_teardown_fail(self): proc = self.runIn( "scenario/layers_with_errors", "--plugin=nose2.plugins.layers", "-v", "test_layer_teardown_fail", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test in") self.assertTestRunOutputMatches(proc, stderr="ERROR: LayerSuite") self.assertTestRunOutputMatches(proc, stderr="FAIL") self.assertTestRunOutputMatches(proc, stderr="Bad Error in Layer testTearDown") def test_setup_fail(self): proc = self.runIn( "scenario/layers_with_errors", "--plugin=nose2.plugins.layers", "-v", "test_layer_setup_fail", ) self.assertTestRunOutputMatches(proc, stderr="Ran 0 tests in") self.assertTestRunOutputMatches(proc, stderr="ERROR: LayerSuite") self.assertTestRunOutputMatches(proc, stderr="FAIL") self.assertTestRunOutputMatches(proc, stderr="Bad Error in Layer setUp!") def test_layers_and_non_layers(self): proc = self.runIn( "scenario/", "layers_and_non_layers", "-v", "--plugin=nose2.plugins.layers" ) self.assertTestRunOutputMatches(proc, stderr="Ran 12 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_loading.py0000664002342000234200000003325014176405443022177 0ustar00sirosensirosen""" pkg1 pkg1.test pkg1.test.test_things pkg1.test.test_things.test_func pkg1.test.test_things.test_gen pkg1.test.test_things.test_gen:3 pkg1.test.test_things.SomeTests pkg1.test.test_things.SomeTests.test_ok # generator method # generator method index # param func # param func index # param method # param method index """ import sys from nose2.tests._common import FunctionalTestCase, support_file class TestLoadTestsFromPackage(FunctionalTestCase): def test_start_directory_inside_package(self): proc = self.runIn( "scenario/tests_in_package/pkg1/test", "-v", "-t", support_file("scenario/tests_in_package"), ) self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_project_directory_inside_package(self): proc = self.runIn("scenario/tests_in_package/pkg1/test", "-v") self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_module_name(self): proc = self.runIn("scenario/tests_in_package", "-v", "pkg1.test.test_things") self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_package_name(self): proc = self.runIn("scenario/tests_in_package", "-v", "pkg1") self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_module_name_with_start_dir(self): proc = self.runIn( ".", "-v", "-s", support_file("scenario/tests_in_package"), "pkg1.test.test_things", ) self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_package_name_with_start_dir(self): proc = self.runIn( ".", "-v", "-s", support_file("scenario/tests_in_package"), "pkg1" ) self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_function_name(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_func" ) self.assertTestRunOutputMatches(proc, stderr="test_func") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_function_string_repr(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_func" ) self.assertTestRunOutputMatches( proc, stderr=r"pkg1.test.test_things.test_func \.\.\. ok" ) self.assertEqual(proc.poll(), 0) def test_generator_function_name(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_gen" ) self.assertTestRunOutputMatches(proc, stderr="test_gen") self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_generator_function_index(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_gen:3" ) self.assertTestRunOutputMatches(proc, stderr="test_gen") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) def test_generator_function_index_1_based(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_gen:1" ) self.assertTestRunOutputMatches(proc, stderr="test_gen") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_testcase_name(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests" ) self.assertTestRunOutputMatches(proc, stderr="SomeTests") self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertEqual(proc.poll(), 1) def test_testcase_method(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests.test_ok" ) self.assertTestRunOutputMatches(proc, stderr="SomeTests") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_generator_method(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests.test_gen_method", ) self.assertTestRunOutputMatches(proc, stderr="test_gen_method") self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 1) def test_generator_method_index(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests.test_gen_method:1", ) self.assertTestRunOutputMatches(proc, stderr="test_gen_method") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_parameterized_method(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests.test_params_method", ) self.assertTestRunOutputMatches(proc, stderr="test_params_method") self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 1) def test_parameterized_method_index(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.SomeTests.test_params_method:1", ) self.assertTestRunOutputMatches(proc, stderr="test_params_method") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_parameterized_func(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_params_func" ) self.assertTestRunOutputMatches(proc, stderr="test_params_func") self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 1) def test_parameterized_func_index(self): proc = self.runIn( "scenario/tests_in_package", "-v", "pkg1.test.test_things.test_params_func:1", ) self.assertTestRunOutputMatches(proc, stderr="test_params_func") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) class TestLoadTestsOutsideOfPackage(FunctionalTestCase): def test_module_name(self): proc = self.runIn("scenario/package_in_lib", "-v", "tests") self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertEqual(proc.poll(), 1) def test_function_name(self): proc = self.runIn("scenario/package_in_lib", "-v", "tests.test") self.assertTestRunOutputMatches(proc, stderr="test") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_module_name_with_start_dir(self): proc = self.runIn( ".", "-v", "-s", support_file("scenario/package_in_lib"), "tests" ) self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertEqual(proc.poll(), 1) class TestLoadingErrors(FunctionalTestCase): def test_import_error_module(self): proc = self.runIn("scenario/module_import_err", "-v", "test_import_err") self.assertTestRunOutputMatches(proc, stderr="ImportError: booms") self.assertTestRunOutputMatches( proc, stderr=r"Traceback \(most recent call last\):" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) def test_import_error_func(self): proc = self.runIn("scenario/module_import_err", "-v", "test_import_err.test") self.assertTestRunOutputMatches(proc, stderr="ImportError: booms") self.assertTestRunOutputMatches( proc, stderr=r"Traceback \(most recent call last\):" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) def test_import_error_testcase(self): proc = self.runIn("scenario/module_import_err", "-v", "test_import_err.Test") self.assertTestRunOutputMatches(proc, stderr="ImportError: booms") self.assertTestRunOutputMatches( proc, stderr=r"Traceback \(most recent call last\):" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) def test_import_error_testcase_method(self): proc = self.runIn( "scenario/module_import_err", "-v", "test_import_err.Test.test" ) self.assertTestRunOutputMatches(proc, stderr="ImportError: booms") self.assertTestRunOutputMatches( proc, stderr=r"Traceback \(most recent call last\):" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) def test_import_error_package(self): proc = self.runIn("scenario/module_import_err", "-v", "pkg") # In this case, there should not be an AttributeError since we only # import pkg, which should work. self.assertTestRunOutputMatches( proc, stderr="ImportError: Failed to import test module: pkg.test_import_err", ) self.assertTestRunOutputMatches( proc, stderr=r"Traceback \(most recent call last\):" ) self.assertTestRunOutputMatches(proc, stderr="ValueError: booms") # 3 tests should run, and only one should fail. We're testing that a # loading error does not prevent from running other tests. self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(errors=1\)") self.assertEqual(proc.poll(), 1) def test_import_error_module_in_package(self): proc = self.runIn("scenario/module_import_err", "-v", "pkg.test_import_err") # In this case, there should not be an ImportError. The import of # pkg.test_import_err fails due with a `ValueError`, and this is the # one we are expecting. self.assertTestRunOutputMatches(proc, stderr="AttributeError: ") self.assertTestRunOutputMatches(proc, stderr="ValueError: booms") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) def test_import_error_unknown_module_in_package(self): proc = self.runIn("scenario/module_import_err", "-v", "pkg.test_does_not_exit") # In this case, there should not be an ImportError. The import of # pkg.test_import_err fails due with a `ValueError`, and this is the # one we are expecting. self.assertTestRunOutputMatches(proc, stderr="AttributeError: ") # py3.6 introduced ModuleNotFoundError, a subclass of ImportError if sys.version_info < (3, 6): importerr = "ImportError: No module named" else: importerr = "ModuleNotFoundError: No module named" self.assertTestRunOutputMatches(proc, stderr=importerr) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 1) class TestTestClassLoading(FunctionalTestCase): def test_load_testclass_by_name(self): proc = self.runIn("scenario/test_classes", "-v", "test_classes.Test") self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertEqual(proc.poll(), 0) def test_load_testclass_method_by_name(self): proc = self.runIn("scenario/test_classes", "-v", "test_classes.Test.test") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) def test_load_testclass_generator_method_by_name(self): proc = self.runIn("scenario/test_classes", "-v", "test_classes.Test.test_gen") self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_load_testclass_params_method_by_name(self): proc = self.runIn( "scenario/test_classes", "-v", "test_classes.Test.test_params" ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_class_level_fixtures_supported(self): proc = self.runIn("scenario/test_classes", "-v", "test_fixtures") self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_error_in_test_class(self): proc = self.runIn("scenario/test_class_fail", "-v", "test_class_fail") self.assertTestRunOutputMatches(proc, stderr="nose2.loader.LoadTestsFailure") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertEqual(proc.poll(), 1) def test_expected_failures(self): proc = self.runIn("scenario/expected_failures", "-v", "expected_failures") self.assertTestRunOutputMatches( proc, stderr=( r"FAILED \(failures=1, expected failures=1, unexpected successes=1\)" ), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_loadtests_plugin.py0000664002342000234200000000374114176405443024144 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase class TestLoadTestsPlugin(FunctionalTestCase): def test_simple(self): proc = self.runIn( "scenario/load_tests", "-v", "--plugin=nose2.plugins.loader.loadtests" ) self.assertTestRunOutputMatches(proc, stderr="Ran 6 tests") self.assertTestRunOutputMatches(proc, stderr="test_a..test_simple") self.assertTestRunOutputMatches(proc, stderr="test_b..test_simple") self.assertTestRunOutputMatches(proc, stderr="test_c..test_simple") self.assertTestRunOutputMatches(proc, stderr="test_d..test_simple") self.assertTestRunOutputMatches(proc, stderr="test_a..test_filter") self.assertTestRunOutputMatches(proc, stderr="test_c..test_filter") self.assertEqual(proc.poll(), 0) def test_package(self): proc = self.runIn( "scenario/load_tests_pkg", "-v", "-c=" "nose2/tests/functional/support/scenario/load_tests_pkg/unittest.cfg", "--plugin=nose2.plugins.loader.loadtests", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertTestRunOutputMatches( proc, stderr="test..ltpkg.tests.test_find_these.Test" ) # with python >= 3.5, the test name contains the fully qualified class # name, so the regexp has an optional matching part. self.assertTestRunOutputMatches( proc, stderr="test..ltpkg2.tests(.load_tests.)?.Test" ) def test_project_directory_inside_package(self): proc = self.runIn( "scenario/load_tests_pkg/ltpkg/tests", "-v", "-c=" "nose2/tests/functional/support/scenario/load_tests_pkg/unittest.cfg", "--plugin=nose2.plugins.loader.loadtests", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches( proc, stderr="test..ltpkg.tests.test_find_these.Test" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_logcapture_plugin.py0000664002342000234200000000232014176405443024277 0ustar00sirosensirosenimport re from nose2.tests._common import FunctionalTestCase class LogCaptureFunctionalTest(FunctionalTestCase): def test_package_in_lib(self): match = re.compile(">> begin captured logging <<") self.assertTestRunOutputMatches( self.runIn("scenario/package_in_lib", "--log-capture"), stderr=match ) def test_logging_keeps_copies_of_mutable_objects(self): proc = self.runIn( "scenario/logging", "-v", "--log-capture", "logging_keeps_copies_of_mutable_objects", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test in") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertTestRunOutputMatches(proc, stderr="foo: {}") def test_logging_config_interpolation(self): proc = self.runIn("scenario/logging_config", "-v", "logging_config") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test in") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertTestRunOutputMatches( proc, stderr=r"\[logging_config\] \[DEBUG\] foo" ) self.assertTestRunOutputMatches(proc, stderr=r"\[logging_config\] \[INFO\] bar") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_main.py0000664002342000234200000000164614176405443021512 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase class TestPluggableTestProgram(FunctionalTestCase): def test_run_in_empty_dir_succeeds(self): proc = self.runIn("scenario/no_tests") stdout, stderr = proc.communicate() self.assertEqual(proc.poll(), 0, stderr) def test_extra_hooks(self): class Check(object): ran = False def startTestRun(self, event): self.ran = True check = Check() proc = self.runIn("scenario/no_tests", extraHooks=[("startTestRun", check)]) stdout, stderr = proc.communicate() self.assertEqual(proc.poll(), 0, stderr) assert check.ran, "Extra hook did not execute" def test_run_in_module_from_its_main(self): proc = self.runModuleAsMain("scenario/one_test/tests.py") self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/tests/functional/test_mp_plugin.py0000664002342000234200000004172214264464446022565 0ustar00sirosensirosenimport multiprocessing import sys import threading import time import unittest from multiprocessing import connection from nose2 import session from nose2._vendor import six from nose2.plugins import buffer from nose2.plugins.loader import discovery, testcases from nose2.plugins.mp import MultiProcess, procserver from nose2.tests._common import Conn, FunctionalTestCase, _method_name, support_file class TestMpPlugin(FunctionalTestCase): def setUp(self): super(TestMpPlugin, self).setUp() self.session = session.Session() self.plugin = MultiProcess(session=self.session) self.plugin.testRunTimeout = 2 def test_flatten_without_fixtures(self): sys.path.append(support_file("scenario/slow")) import test_slow as mod suite = unittest.TestSuite() suite.addTest(mod.TestSlow("test_ok")) suite.addTest(mod.TestSlow("test_fail")) suite.addTest(mod.TestSlow("test_err")) flat = list(self.plugin._flatten(suite)) self.assertEqual(len(flat), 3) def test_flatten_nested_suites(self): sys.path.append(support_file("scenario/slow")) import test_slow as mod suite = unittest.TestSuite() suite.addTest(mod.TestSlow("test_ok")) suite.addTest(mod.TestSlow("test_fail")) suite.addTest(mod.TestSlow("test_err")) suite2 = unittest.TestSuite() suite2.addTest(suite) flat = list(self.plugin._flatten(suite2)) self.assertEqual(len(flat), 3) def test_flatten_respects_module_fixtures(self): sys.path.append(support_file("scenario/module_fixtures")) import test_mf_testcase as mod suite = unittest.TestSuite() suite.addTest(mod.Test("test_1")) suite.addTest(mod.Test("test_2")) flat = list(self.plugin._flatten(suite)) self.assertEqual(flat, ["test_mf_testcase"]) def test_flatten_respects_class_fixtures(self): sys.path.append(support_file("scenario/class_fixtures")) import test_cf_testcase as mod suite = unittest.TestSuite() suite.addTest(mod.Test("test_1")) suite.addTest(mod.Test("test_2")) suite.addTest(mod.Test2("test_1")) suite.addTest(mod.Test2("test_2")) suite.addTest(mod.Test3("test_3")) flat = list(self.plugin._flatten(suite)) self.assertEqual( flat, [ "test_cf_testcase.Test2.test_1", "test_cf_testcase.Test2.test_2", "test_cf_testcase.Test", "test_cf_testcase.Test3", ], ) def test_conn_prep(self): self.plugin.bind_host = None (parent_conn, child_conn) = self.plugin._prepConns() (parent_pipe, child_pipe) = multiprocessing.Pipe() self.assertIsInstance(parent_conn, type(parent_pipe)) self.assertIsInstance(child_conn, type(child_pipe)) self.plugin.bind_host = "127.0.0.1" self.plugin.bind_port = 0 (parent_conn, child_conn) = self.plugin._prepConns() self.assertIsInstance(parent_conn, connection.Listener) self.assertIsInstance(child_conn, tuple) self.assertEqual(parent_conn.address, child_conn[:2]) def test_conn_accept(self): (parent_conn, child_conn) = multiprocessing.Pipe() self.assertEqual(self.plugin._acceptConns(parent_conn), parent_conn) listener = connection.Listener(("127.0.0.1", 0)) with self.assertRaises(RuntimeError): self.plugin._acceptConns(listener) def fake_client(address): client = connection.Client(address) time.sleep(self.plugin.testRunTimeout) client.close() t = threading.Thread(target=fake_client, args=(listener.address,)) t.start() conn = self.plugin._acceptConns(listener) self.assertTrue(hasattr(conn, "send")) self.assertTrue(hasattr(conn, "recv")) t.join() class TestProcserver(FunctionalTestCase): def setUp(self): super(TestProcserver, self).setUp() self.session = session.Session() def test_dispatch_tests_receive_events(self): ssn = { "config": self.session.config, "verbosity": 1, "startDir": support_file("scenario/tests_in_package"), "topLevelDir": support_file("scenario/tests_in_package"), "logLevel": 100, "pluginClasses": [ discovery.DiscoveryLoader, testcases.TestCaseLoader, buffer.OutputBufferPlugin, ], } conn = Conn( [ "pkg1.test.test_things.SomeTests.test_ok", "pkg1.test.test_things.SomeTests.test_failed", ] ) procserver(ssn, conn) # check conn calls expect = [ ( "pkg1.test.test_things.SomeTests.test_ok", [ ("startTest", {}), ("setTestOutcome", {"outcome": "passed"}), ("testOutcome", {"outcome": "passed"}), ("stopTest", {}), ], ), ( "pkg1.test.test_things.SomeTests.test_failed", [ ("startTest", {}), ( "setTestOutcome", { "outcome": "failed", "expected": False, "metadata": { "stdout": """\ -------------------- >> begin captured stdout << --------------------- Hello stdout --------------------- >> end captured stdout << ----------------------""" }, }, ), ( "testOutcome", { "outcome": "failed", "expected": False, "metadata": { "stdout": """\ -------------------- >> begin captured stdout << --------------------- Hello stdout --------------------- >> end captured stdout << ----------------------""" }, }, ), ("stopTest", {}), ], ), ] for val in conn.sent: if val is None: break test, events = val exp_test, exp_events = expect.pop(0) self.assertEqual(test, exp_test) for method, event in events: exp_meth, exp_attr = exp_events.pop(0) self.assertEqual(method, exp_meth) for attr, val in exp_attr.items(): self.assertEqual(getattr(event, attr), val) class MPPluginTestRuns(FunctionalTestCase): def test_tests_in_package(self): proc = self.runIn( "scenario/tests_in_package", "-v", "--plugin=nose2.plugins.mp", "-N=2" ) self.assertTestRunOutputMatches(proc, stderr="Ran 25 tests") self.assertEqual(proc.poll(), 1) def test_package_in_lib(self): proc = self.runIn( "scenario/package_in_lib", "-v", "--plugin=nose2.plugins.mp", "-N=2" ) self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests") self.assertEqual(proc.poll(), 1) def test_module_fixtures(self): proc = self.runIn( "scenario/module_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2" ) self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_class_fixtures(self): proc = self.runIn( "scenario/class_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2" ) self.assertTestRunOutputMatches(proc, stderr="Ran 7 tests") self.assertEqual(proc.poll(), 0) def test_large_number_of_tests_stresstest(self): proc = self.runIn( "scenario/many_tests", "-v", "--plugin=nose2.plugins.mp", "--plugin=nose2.plugins.loader.generators", "-N=1", ) self.assertTestRunOutputMatches(proc, stderr="Ran 600 tests") self.assertEqual(proc.poll(), 0) def test_socket_stresstest(self): proc = self.runIn( "scenario/many_tests_socket", "-v", "-c scenario/many_test_socket/nose2.cfg", "--plugin=nose2.plugins.mp", "--plugin=nose2.plugins.loader.generators", "-N=1", ) self.assertTestRunOutputMatches(proc, stderr="Ran 600 tests") self.assertEqual(proc.poll(), 0) def test_too_many_procs(self): # Just need to run the mp plugin with less tests than # processes. proc = self.runModuleAsMain( "scenario/one_test/tests.py", "--log-level=debug", "--plugin=nose2.plugins.mp", "-N=2", ) ret_vals = six.moves.queue.Queue() def save_return(): """ Popen.communciate() blocks. Use a thread-safe queue to return any exceptions. Ideally, this completes and returns None. """ try: self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) ret_vals.put(None) except Exception as exc: ret_vals.put(exc) thread = threading.Thread(target=save_return) thread.start() # 1 minute should be more than sufficient for this # little test case. try: exc = ret_vals.get(True, 60) except six.moves.queue.Empty: exc = "MP Test timed out" proc.kill() self.assertIsNone(exc, str(exc)) def test_with_output_buffer(self): proc = self.runIn( "scenario/module_fixtures", "-v", "--plugin=nose2.plugins.mp", "--plugin=nose2.plugins.buffer", "-N=2", "-B", ) self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_unknown_module(self): proc = self.runIn( "scenario/module_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2", "-B", "does.not.exists.module", "does.not.exists.module2", ) expected_results = ( r"does\.not\.exists\.module2 (\S+) \.\.\. ERROR\n" r"does\.not\.exists\.module (\S+) \.\.\. ERROR" ) self.assertTestRunOutputMatches(proc, stderr=expected_results) self.assertEqual(proc.poll(), 1) class MPTestClassSupport(FunctionalTestCase): def test_testclass_discover(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2" ) self.assertTestRunOutputMatches(proc, stderr="Ran 13 tests") self.assertEqual(proc.poll(), 0) def test_testclass_by_module(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_classes_mp", ) self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertEqual(proc.poll(), 0) def test_testclass_by_class(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_classes_mp.Test", ) self.assertTestRunOutputMatches(proc, stderr="Ran 8 tests") self.assertEqual(proc.poll(), 0) def test_testclass_parameters(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_classes_mp.Test.test_params", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testclass_generators(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_classes_mp.Test.test_gen", ) self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) class MPClassFixturesSupport(FunctionalTestCase): def test_testcase_class_fixtures(self): proc = self.runIn( "scenario/class_fixtures", "-v", "test_cf_testcase.Test.test_1" ) # main process runs selected tests self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) def test_testcase_class_fixtures_mp(self): proc = self.runIn( "scenario/class_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_cf_testcase.Test.test_1", ) # XXX mp plugin runs the entire class if a class fixture is detected self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testcase_class_fixtures_report_mp(self): proc = self.runIn( "scenario/class_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_cf_testcase.Test.test_1", ) # report should show correct names for all tests self.assertTestRunOutputMatches( proc, stderr=r"test_1 \(test_cf_testcase.Test" + _method_name("test_1") + r"\) ... ok", ) self.assertTestRunOutputMatches( proc, stderr=r"test_2 \(test_cf_testcase.Test" + _method_name("test_2") + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testclass_class_fixtures_and_parameters(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "test_fixtures_mp.Test.test_params" ) # main process runs selected tests self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testclass_class_fixtures_and_parameters_mp(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_fixtures_mp.Test.test_params", ) # XXX mp plugin runs the entire class if a class fixture is detected self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) def test_testclass_class_fixtures_and_generators(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "test_fixtures_mp.Test.test_gen" ) # main process runs selected tests self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testclass_class_fixtures_and_generators_mp(self): proc = self.runIn( "scenario/test_classes_mp", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_fixtures_mp.Test.test_gen", ) # XXX mp plugin runs the entire class if a class fixture is detected self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertEqual(proc.poll(), 0) class MPModuleFixturesSupport(FunctionalTestCase): def test_testcase_module_fixtures(self): proc = self.runIn( "scenario/module_fixtures", "-v", "test_mf_testcase.Test.test_1" ) # main process runs selected tests self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0) def test_testcase_module_fixtures_mp(self): proc = self.runIn( "scenario/module_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_mf_testcase.Test.test_1", ) # XXX mp plugin runs the entire module if a module fixture is detected self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) def test_testcase_module_fixtures_report_mp(self): proc = self.runIn( "scenario/module_fixtures", "-v", "--plugin=nose2.plugins.mp", "-N=2", "test_mf_testcase.Test.test_1", ) # report should show correct names for all tests self.assertTestRunOutputMatches( proc, stderr=r"test_1 \(test_mf_testcase.Test" + _method_name("test_1") + r"\) ... ok", ) self.assertTestRunOutputMatches( proc, stderr=r"test_2 \(test_mf_testcase.Test" + _method_name("test_2") + r"\) ... ok", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests") self.assertEqual(proc.poll(), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657930056.0 nose2-0.12.0/nose2/tests/functional/test_prettyassert.py0000664002342000234200000001412514264400510023317 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase, windows_ci_skip class TestPrettyAsserts(FunctionalTestCase): def assertProcOutputPattern(self, proc, expected, assert_exit_status=1): """ - proc: a popen proc to check output on - expected: expected output pattern """ stdout, stderr = proc.communicate() if assert_exit_status is not None: self.assertEqual(assert_exit_status, proc.poll()) self.assertTestRunOutputMatches(proc, stderr=expected) return stderr def test_simple_global(self): proc = self.runIn( "scenario/pretty_asserts/simple_global", "-v", "--pretty-assert" ) expected = "\n".join( [">>> assert myglob == 2", "", "values:", " myglob = 1", ""] ) self.assertProcOutputPattern(proc, expected) def test_conf_on(self): proc = self.runIn("scenario/pretty_asserts/conf_on", "-v") expected = "\n".join( [">>> assert myglob == 2", "", "values:", " myglob = 1", ""] ) self.assertProcOutputPattern(proc, expected) def test_conf_on_suppresses_clihelp(self): proc = self.runIn("scenario/pretty_asserts/conf_on", "--help") stdout, stderr = proc.communicate() exit_status = proc.poll() assert "--pretty-assert" not in stdout assert "--pretty-assert" not in stderr assert exit_status == 0 def test_conf_on_plus_arg(self): """ensures that #432 stays fixed""" proc = self.runIn("scenario/pretty_asserts/conf_on", "-v", "--pretty-assert") expected = "\n".join( [">>> assert myglob == 2", "", "values:", " myglob = 1", ""] ) self.assertProcOutputPattern(proc, expected) def test_assign_after_assert(self): proc = self.runIn( "scenario/pretty_asserts/assign_after_assert", "-v", "--pretty-assert" ) expected = "\n".join([">>> assert x == 2", "", "values:", " x = 1", ""]) self.assertProcOutputPattern(proc, expected) def test_multiline_assert_statement(self): proc = self.runIn( "scenario/pretty_asserts/multiline_statement", "-v", "--pretty-assert" ) expected = "\n".join( [ ">>> assert \\(x", ">>> >", '>>> y\\), \\"oh noez, x <= y\\"', "", "message:", " oh noez, x <= y", "", "values:", " x = 1", " y = 2", "", ] ) self.assertProcOutputPattern(proc, expected) def test_multiline_funcdef(self): proc = self.runIn( "scenario/pretty_asserts/multiline_funcdef", "--pretty-assert" ) expected1 = "\n".join( [ '>>> assert x > y, \\"oh noez, x <= y\\"', "", "message:", " oh noez, x <= y", "", "values:", " x = 1", " y = 2", "", ] ) expected2 = "\n".join( [">>> assert not value", "", "values:", " value = 'foo'", ""] ) expected3 = "\n".join( [">>> assert not value", "", "values:", " value = 'bar'", ""] ) self.assertProcOutputPattern(proc, expected1) self.assertProcOutputPattern(proc, expected2) self.assertProcOutputPattern(proc, expected3) def test_assert_attribute_resolution(self): proc = self.runIn( "scenario/pretty_asserts/attribute_resolution", "-v", "--pretty-assert" ) expected = "\n".join( [ ">>> assert x.x \\!= \\(self", ">>> \\).x", "", "values:", ( " x = " ), " x.x = 1", ( " self = " ), "", ] ) self.assertProcOutputPattern(proc, expected) @windows_ci_skip def test_assert_attribute_resolution2(self): proc = self.runIn( "scenario/pretty_asserts/attribute_resolution2", "-v", "--pretty-assert" ) expected = "\n".join( [ ">>> assert foo\\(\\).x \\!= self.x", "", "values:", ( " foo = .|)foo at " "0x[a-z0-9]+>" ), ( " self = " ), " self.x = 1", "", ] ) self.assertProcOutputPattern(proc, expected) def test_assert_ignore_passing(self): proc = self.runIn( "scenario/pretty_asserts/ignore_passing", "-v", "--pretty-assert" ) expected1 = "\n".join( [">>> assert x; assert y", "", "values:", " y = False", ""] ) expected2 = "\n".join([">>> assert q", "", "values:", " q = 0", ""]) self.assertProcOutputPattern(proc, expected1) self.assertProcOutputPattern(proc, expected2) def test_unittest_assertion(self): proc = self.runIn( "scenario/pretty_asserts/unittest_assertion", "-v", "--pretty-assert" ) # look for typical unittest output expected = "self.assertTrue\\(x\\)\nAssertionError: False is not true" stderr = self.assertProcOutputPattern(proc, expected) # the assertion line wasn't reprinted by prettyassert self.assertNotIn(">>> self.assertTrue", stderr) # the assertion values weren't printed by prettyassert self.assertNotIn("values:", stderr) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_printhooks_plugin.py0000664002342000234200000000226414176405443024341 0ustar00sirosensirosenimport re from nose2.tests._common import FunctionalTestCase class TestPrintHooksPlugin(FunctionalTestCase): def test_invocation_by_double_dash_option(self): proc = self.runIn( "scenario/no_tests", "--plugin=nose2.plugins.printhooks", "--print-hooks" ) match = re.compile( "\n" + r"handleArgs: CommandLineArgsEvent\(handled=False, args=" ) self.assertTestRunOutputMatches(proc, stderr=match) self.assertEqual(proc.poll(), 0) def test_invocation_by_single_dash_option(self): proc = self.runIn( "scenario/no_tests", "--plugin=nose2.plugins.printhooks", "-P" ) match = re.compile( "\n" + r"handleArgs: CommandLineArgsEvent\(handled=False, args=" ) self.assertTestRunOutputMatches(proc, stderr=match) self.assertEqual(proc.poll(), 0) def test_nested_hooks_are_indented(self): proc = self.runIn( "scenario/no_tests", "--plugin=nose2.plugins.printhooks", "--print-hooks" ) match = re.compile("\n handleFile: ") self.assertTestRunOutputMatches(proc, stderr=match) self.assertEqual(proc.poll(), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/tests/functional/test_session.py0000664002342000234200000000355714264464446022262 0ustar00sirosensirosenimport sys from nose2 import session from nose2.tests._common import FunctionalTestCase, support_file class SessionFunctionalTests(FunctionalTestCase): def setUp(self): self.s = session.Session() self.s.loadConfigFiles( support_file("cfg", "a.cfg"), support_file("cfg", "b.cfg") ) sys.path.insert(0, support_file("lib")) def test_session_can_load_config_files(self): assert self.s.config.has_section("a") assert self.s.config.has_section("b") def test_session_holds_plugin_config(self): plug_config = self.s.get("a") assert plug_config def test_session_can_load_plugins_from_modules(self): self.s.loadPlugins() assert self.s.plugins plug = self.s.plugins[0] self.assertEqual(plug.a, 1) def test_session_config_cacheing(self): """Test caching of config sections works""" # Create new session (generic one likely already cached # depending on test order) cache_sess = session.Session() cache_sess.loadConfigFiles(support_file("cfg", "a.cfg")) # First access to given section, should read from config file firstaccess = cache_sess.get("a") assert firstaccess.as_int("a") == 1 # Hack cached Config object internals to make the stored value # something different cache_sess.configCache["a"]._mvd["a"] = "0" newitems = [] for item in cache_sess.configCache["a"]._items: if item != ("a", "1"): newitems.append(item) else: newitems.append(("a", "0")) cache_sess.configCache["a"]._items = newitems # Second access to given section, confirm returns cached value # rather than parsing config file again secondaccess = cache_sess.get("a") assert secondaccess.as_int("a") == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1647576546.0 nose2-0.12.0/nose2/tests/functional/test_subtests.py0000664002342000234200000004072514215002742022430 0ustar00sirosensirosenimport os import sys import tempfile from xml.etree import ElementTree as ET from nose2.tests._common import FunctionalTestCase def read_report(path): with open(path, "r", encoding="utf-8") as f: return ET.parse(f).getroot() class TestSubtests(FunctionalTestCase): def setUp(self): super(TestSubtests, self).setUp() if sys.version_info < (3, 4): self.skipTest("Python >= 3.4 required") def test_success(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_success" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="test_subtest_success") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_failure(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_failure" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=3\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=5\)") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=3\)") self.assertEqual(proc.poll(), 1) def test_error(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_error" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=0\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 0") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 1") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=2\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 2") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(errors=3\)") self.assertEqual(proc.poll(), 1) def test_expected_failure(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_expected_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches( proc, stderr="test_subtest_expected_failure.*expected failure" ) self.assertTestRunOutputMatches(proc, stderr=r"OK \(expected failures=1\)") self.assertEqual(proc.poll(), 0) def test_message(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_message" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=1\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=3\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=5\)" ) self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=3\)") self.assertEqual(proc.poll(), 1) def test_all(self): proc = self.runIn("scenario/subtests", "-v", "test_subtests") self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=3\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=5\)") self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=1\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=3\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=5\)" ) self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=0\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=2\)") self.assertTestRunOutputMatches( proc, stderr=r"FAILED \(failures=6, errors=3, expected failures=1\)" ) self.assertEqual(proc.poll(), 1) class TestSubtestsMultiprocess(FunctionalTestCase): def setUp(self): super(TestSubtestsMultiprocess, self).setUp() if sys.version_info < (3, 4): self.skipTest("Python >= 3.4 required") def test_success(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests.Case.test_subtest_success", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="test_subtest_success") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) def test_failure(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests.Case.test_subtest_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=3\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=5\)") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=3\)") self.assertEqual(proc.poll(), 1) def test_error(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests.Case.test_subtest_error", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=0\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 0") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 1") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=2\)") self.assertTestRunOutputMatches(proc, stderr="RuntimeError: 2") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(errors=3\)") self.assertEqual(proc.poll(), 1) def test_expected_failure(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests.Case.test_subtest_expected_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches( proc, stderr="test_subtest_expected_failure.*expected failure" ) self.assertTestRunOutputMatches(proc, stderr=r"OK \(expected failures=1\)") self.assertEqual(proc.poll(), 0) def test_message(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests.Case.test_subtest_message", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=1\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=3\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=5\)" ) self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=3\)") self.assertEqual(proc.poll(), 1) def test_all(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.mp", "--processes=2", "-v", "test_subtests", ) self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=3\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=5\)") self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=1\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=3\)" ) self.assertTestRunOutputMatches( proc, stderr=r"test_subtest_message.*\[msg\] \(i=5\)" ) self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=0\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_error.*\(i=2\)") self.assertTestRunOutputMatches( proc, stderr=r"FAILED \(failures=6, errors=3, expected failures=1\)" ) self.assertEqual(proc.poll(), 1) class TestSubtestsJunitXml(FunctionalTestCase): def setUp(self): super(TestSubtestsJunitXml, self).setUp() if sys.version_info < (3, 4): self.skipTest("Python >= 3.4 required") tmp = tempfile.NamedTemporaryFile(delete=False) tmp.close() self.junit_report = tmp.name def tearDown(self): os.remove(self.junit_report) def test_success(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests.Case.test_subtest_success", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "1") self.assertEqual(tree.get("failures"), "0") self.assertEqual(tree.get("errors"), "0") self.assertEqual(tree.get("skipped"), "0") self.assertEqual(len(tree.findall("testcase")), 1) for test_case in tree.findall("testcase"): self.assertEqual(test_case.get("name"), "test_subtest_success") def test_failure(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests.Case.test_subtest_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertEqual(proc.poll(), 1) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "1") self.assertEqual(tree.get("failures"), "3") self.assertEqual(tree.get("errors"), "0") self.assertEqual(tree.get("skipped"), "0") self.assertEqual(len(tree.findall("testcase")), 3) for index, test_case in enumerate(tree.findall("testcase")): self.assertEqual( test_case.get("name"), "test_subtest_failure (i={})".format(index * 2 + 1), ) def test_error(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests.Case.test_subtest_error", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertEqual(proc.poll(), 1) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "1") self.assertEqual(tree.get("failures"), "0") self.assertEqual(tree.get("errors"), "3") self.assertEqual(tree.get("skipped"), "0") self.assertEqual(len(tree.findall("testcase")), 3) for index, test_case in enumerate(tree.findall("testcase")): self.assertEqual( test_case.get("name"), "test_subtest_error (i={})".format(index) ) def test_expected_failure(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests.Case.test_subtest_expected_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertEqual(proc.poll(), 0) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "1") self.assertEqual(tree.get("failures"), "0") self.assertEqual(tree.get("errors"), "0") self.assertEqual(tree.get("skipped"), "1") self.assertEqual(len(tree.findall("testcase")), 1) for test_case in tree.findall("testcase"): self.assertEqual(test_case.get("name"), "test_subtest_expected_failure") def test_message(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests.Case.test_subtest_message", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertEqual(proc.poll(), 1) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "1") self.assertEqual(tree.get("failures"), "3") self.assertEqual(tree.get("errors"), "0") self.assertEqual(tree.get("skipped"), "0") self.assertEqual(len(tree.findall("testcase")), 3) for index, test_case in enumerate(tree.findall("testcase")): self.assertEqual( test_case.get("name"), "test_subtest_message [msg] (i={})".format(index * 2 + 1), ) def test_all(self): proc = self.runIn( "scenario/subtests", "--plugin=nose2.plugins.junitxml", "--junit-xml", "--junit-xml-path={}".format(self.junit_report), "-v", "test_subtests", ) self.assertTestRunOutputMatches(proc, stderr="Ran 5 tests") self.assertTestRunOutputMatches(proc, stderr="FAILED") self.assertEqual(proc.poll(), 1) tree = read_report(self.junit_report) self.assertEqual(tree.get("tests"), "5") self.assertEqual(tree.get("failures"), "6") self.assertEqual(tree.get("errors"), "3") self.assertEqual(tree.get("skipped"), "1") self.assertEqual(len(tree.findall("testcase")), 11) class TestSubtestsFailFast(FunctionalTestCase): def setUp(self): super(TestSubtestsFailFast, self).setUp() if sys.version_info < (3, 4): self.skipTest("Python >= 3.4 required") def test_failure(self): proc = self.runIn( "scenario/subtests", "-v", "test_subtests.Case.test_subtest_failure" ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=3\)") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=5\)") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=3\)") self.assertEqual(proc.poll(), 1) def test_failfast(self): proc = self.runIn( "scenario/subtests", "--fail-fast", "-v", "test_subtests.Case.test_subtest_failure", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertTestRunOutputMatches(proc, stderr=r"test_subtest_failure.*\(i=1\)") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(failures=1\)") self.assertEqual(proc.poll(), 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/functional/test_such_dsl.py0000664002342000234200000001206014176405443022362 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase from nose2.tools import such class TestSuchDSL(FunctionalTestCase): def test_runs_example(self): proc = self.runIn("such", "-v", "--plugin=nose2.plugins.layers", "test_such") self.assertTestRunOutputMatches(proc, stderr="Ran 9 tests") self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_load_top_level_by_name(self): proc = self.runIn( "such", "-v", "--plugin=nose2.plugins.layers", "test_such.A system with complex setup.should do something", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_load_sublayer_test_by_name(self): proc = self.runIn( "such", "-v", "--plugin=nose2.plugins.layers", "test_such.having an expensive fixture." "should do more things", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test") self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_regression_tests_with_the_same_having_description_under_different_fixtures_in_the_same_module_should_be_run( # noqa self, ): proc = self.runIn( "such", "-v", "--plugin=nose2.plugins.layers", "test_regression_same_havings", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 test") self.assertEqual(proc.poll(), 0, proc.stderr.getvalue()) def test_teardown_fail(self): proc = self.runIn( "scenario/layers_with_errors", "--plugin=nose2.plugins.layers", "-v", "test_such_teardown_fail", ) self.assertTestRunOutputMatches(proc, stderr="Ran 1 test in") self.assertTestRunOutputMatches(proc, stderr="ERROR: LayerSuite") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(errors=1\)") self.assertTestRunOutputMatches(proc, stderr="Bad Error in such tearDown") def test_setup_fail(self): proc = self.runIn( "scenario/layers_with_errors", "--plugin=nose2.plugins.layers", "-v", "test_such_setup_fail", ) self.assertTestRunOutputMatches(proc, stderr="Ran 0 tests in") self.assertTestRunOutputMatches(proc, stderr="ERROR: LayerSuite") self.assertTestRunOutputMatches(proc, stderr=r"FAILED \(errors=1\)") self.assertTestRunOutputMatches(proc, stderr="Bad Error in such setUp!") def test_param_plugin_with_such(self): proc = self.runIn( "scenario/such_with_params", "--plugin=nose2.plugins.layers", "-v", "such_with_params", ) self.assertTestRunOutputMatches(proc, stderr="Ran 6 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") self.assertTestRunOutputMatches(proc, stderr="test 0000: should do bar:3") self.assertTestRunOutputMatches( proc, stderr="test 0001: should do bar and extra:3" ) def test_such_without_layers_plugin(self): proc = self.runIn("such", "-v", "test_such_without_layers") self.assertTestRunOutputMatches(proc, stderr=r"FAILED") self.assertTestRunOutputMatches( proc, stderr=such.LAYERS_PLUGIN_NOT_LOADED_MESSAGE ) def test_testsetup_on_higher_layer_with_test(self): proc = self.runIn( "scenario/layers_setups", "--plugin=nose2.plugins.layers", "-v", "higher_layer_testsetup_with_test", ) self.assertTestRunOutputMatches(proc, stderr="Ran 3 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") def test_testsetup_on_higher_layer(self): proc = self.runIn( "scenario/layers_setups", "--plugin=nose2.plugins.layers", "-v", "higher_layer_testsetup_no_test", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") def test_testsetup_on_higher_layer_3layers(self): proc = self.runIn( "scenario/layers_setups", "--plugin=nose2.plugins.layers", "-v", "higher_layer_testsetup_3layers", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") def test_setup_on_higher_layer(self): proc = self.runIn( "scenario/layers_setups", "--plugin=nose2.plugins.layers", "-v", "higher_layer_setup", ) self.assertTestRunOutputMatches(proc, stderr="Ran 2 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") def test_long_setup(self): proc = self.runIn( "such", "-v", "--plugin=nose2.plugins.layers", "test_such_timing" ) self.assertTestRunOutputMatches(proc, stderr=r"Ran 2 tests in") self.assertTestRunOutputMatches(proc, stderr="OK") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/functional/test_util.py0000664002342000234200000000154214220574143021530 0ustar00sirosensirosen# -*- coding: utf-8 -*- from nose2 import util from nose2._vendor import six from nose2.tests._common import TestCase, support_file class UtilTests(TestCase): def test_name_from_path(self): test_module = support_file("scenario/tests_in_package/pkg1/test/test_things.py") test_package_path = support_file("scenario/tests_in_package") self.assertEqual( util.name_from_path(test_module), ("pkg1.test.test_things", test_package_path), ) def test_non_ascii_output(self): class D: def __init__(self): self.out = [] def write(self, arg): self.out.append(arg) stream = D() decorated = util._WritelnDecorator(stream) string = six.u("\u00dcnic\u00f6de") decorated.write(string) str("".join(stream.out)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1652471884.0 nose2-0.12.0/nose2/tests/functional/test_verbosity.py0000664002342000234200000000672214237534114022610 0ustar00sirosensirosenfrom nose2.tests._common import FunctionalTestCase, _method_name, windows_ci_skip _SUFFIX = """\ ---------------------------------------------------------------------- Ran 1 test """ Q_TEST_PATTERN = r"(?>> 2 == 2 True """ txt_event = self._handle_file("docs.txt", doc_test) rst_event = self._handle_file("docs.rst", doc_test) # Exercise loading of doctests from Python code py_event = self._handle_file( "docs.py", """\ \"\"\" >>> 2 == 2 True \"\"\" """, ) for event, ext in [(txt_event, "txt"), (rst_event, "rst")]: (test,) = event.extraTests self.assertTrue(isinstance(test, doctest.DocFileCase)) self.assertEqual(repr(test), "docs.%s" % ext) (testsuite,) = py_event.extraTests (test,) = list(testsuite) self.assertEqual(repr(test), "docs ()") def test_handle_file_python_without_doctests(self): """Test calling handleFile for a Python module without doctests.""" event = self._handle_file( "mod.py", """\ def func(): pass """, ) if sys.version_info >= (3, 5): self.assertEqual(event.extraTests, [doctest.DocTestSuite()]) else: self.assertEqual(event.extraTests, []) def test_handle_file_python_setup_py(self): # Test calling handleFile on a top-level setup.py file. # The file should be ignored by the plugin as it cannot safely be # imported. setup_py = dedent( """\ ''' >>> never executed ''' from setuptools import setup setup(name='foo') """ ) event = self._handle_file("setup.py", setup_py) self.assertEqual(event.extraTests, []) def _handle_file(self, fpath, content): """Have plugin handle a file with certain content. The file is created, then a plugin is instantiated and its handleFile method is called for the file. """ fh = open(fpath, "w") try: fh.write(content) finally: fh.close() event = events.HandleFileEvent(self.loader, fh.name, fpath, None, None) self.plugin.handleFile(event) return event ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_dundertest_plugin.py0000664002342000234200000000175414176405443023142 0ustar00sirosensirosenimport unittest from nose2 import session from nose2.plugins import dundertest from nose2.tests._common import TestCase class TestDunderTestPlugin(TestCase): tags = ["unit"] def setUp(self): class DummyCase(TestCase): def test_a(self): pass self.suite = unittest.TestSuite() self.caseClass = DummyCase self.session = session.Session() self.plugin = dundertest.DunderTestFilter(session=self.session) self.plugin.register() def test_undefined_dunder_test_attribute_keeps_test(self): self.suite.addTest(self.caseClass("test_a")) self.plugin.removeNonTests(self.suite) self.assertEqual(len(list(self.suite)), 1) def test_false_dunder_test_attribute_removes_test(self): dummyTest = self.caseClass("test_a") dummyTest.__test__ = False self.suite.addTest(dummyTest) self.plugin.removeNonTests(self.suite) self.assertEqual(len(list(self.suite)), 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_failfast.py0000664002342000234200000000320014176405443021160 0ustar00sirosensirosenimport unittest from nose2 import result, session from nose2.plugins import failfast from nose2.tests._common import TestCase class TestFailFast(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.result = result.PluggableTestResult(self.session) self.plugin = failfast.FailFast(session=self.session) self.plugin.register() class Test(TestCase): def test(self): pass def test_err(self): raise Exception("oops") def test_fail(self): assert False @unittest.expectedFailure def test_fail_expected(self): assert False @unittest.skipIf(True, "Always skip") def test_skip(self): pass self.case = Test def test_sets_shouldstop_on_unexpected_error(self): test = self.case("test_err") test(self.result) assert self.result.shouldStop def test_sets_shouldstop_on_unexpected_fail(self): test = self.case("test_fail") test(self.result) assert self.result.shouldStop def test_does_not_set_shouldstop_on_expected_fail(self): test = self.case("test_fail_expected") test(self.result) assert not self.result.shouldStop def test_does_not_set_shouldstop_on_success(self): test = self.case("test") test(self.result) assert not self.result.shouldStop def test_does_not_set_shouldstop_on_skip(self): test = self.case("test_skip") test(self.result) assert not self.result.shouldStop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_functions_loader.py0000664002342000234200000000531214176405443022733 0ustar00sirosensirosenimport unittest try: from unittest import mock except ImportError: # Python versions older than 3.3 don't have mock by default import mock from nose2 import events, loader, session from nose2.plugins.loader import functions from nose2.tests._common import TestCase class TestFunctionLoader(TestCase): def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(self.session) self.plugin = functions.Functions(session=self.session) def test_can_load_test_functions_from_module(self): class Mod(object): pass def test(): pass m = Mod() m.test = test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 1) assert isinstance(event.extraTests[0], unittest.FunctionTestCase) def test_ignores_generator_functions(self): class Mod(object): pass def test(): yield m = Mod() m.test = test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 0) def test_ignores_functions_that_take_args(self): class Mod(object): pass def test(a): pass m = Mod() m.test = test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 0) def test_can_load_test_functions_from_name(self): event = events.LoadFromNameEvent(self.loader, __name__ + ".func", None) suite = self.session.hooks.loadTestsFromName(event) self.assertNotEqual(suite, None) def test_ignores_test_methods_from_name(self): # Should ignore test methods even when specified directly event = events.LoadFromNameEvent( self.loader, __name__ + ".Case.test_method", None ) suite = self.session.hooks.loadTestsFromName(event) self.assertEqual(suite, None) def test_ignores_decorated_test_methods_from_name(self): # Should ignore test methods even when they are of FunctionType event = events.LoadFromNameEvent( self.loader, __name__ + ".Case.test_patched", None ) suite = self.session.hooks.loadTestsFromName(event) self.assertEqual(suite, None) def func(): pass def dummy(): pass class Case(unittest.TestCase): __test__ = False # do not run this def test_method(self): pass @mock.patch(__name__ + ".dummy") def test_patched(self, mock): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_generators_plugin.py0000664002342000234200000000525214176405443023127 0ustar00sirosensirosenfrom nose2 import events, loader, session, util from nose2.plugins.loader import generators, testcases from nose2.tests._common import TestCase class TestGeneratorUnpack(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(self.session) self.expect = [ (0, ("call", (0, 1))), (1, ("call", (1, 2))), (2, ("call", (2, 3))), ] self.plugin = generators.Generators(session=self.session) # need testcase loader to make the initial response to load from module self.tcl = testcases.TestCaseLoader(session=self.session) def test_unpack_handles_nose_style_generators(self): def gen(): for i in range(0, 3): yield "call", i, i + 1 out = list(self.plugin.unpack(gen())) self.assertEqual(out, self.expect) def test_unpack_handles_unittest2_style_generators(self): def gen(): for i in range(0, 3): yield "call", (i, i + 1) out = list(self.plugin.unpack(gen())) self.assertEqual(out, self.expect) def test_ignores_ordinary_functions(self): class Mod(object): pass def test(): pass m = Mod() m.test = test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 0) def test_can_load_tests_from_generator_functions(self): class Mod(object): __name__ = "themod" def check(x): assert x == 1 def test(): yield check, 1 yield check, 2 m = Mod() m.test = test test.__module__ = m.__name__ event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 2) # check that test names are sensible self.assertEqual(util.test_name(event.extraTests[0]), "themod.test:1") self.assertEqual(util.test_name(event.extraTests[1]), "themod.test:2") def test_can_load_tests_from_generator_methods(self): class Mod(object): pass def check(x): return x == 1 class Test(TestCase): def test(self): yield check, 1 yield check, 2 m = Mod() m.Test = Test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 1) self.assertEqual(len(event.extraTests[0]._tests), 2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/unit/test_junitxml.py0000664002342000234200000003332614220574143021247 0ustar00sirosensirosenimport datetime import logging import os import sys import time import unittest from xml.etree import ElementTree as ET from nose2 import events, loader, result, session, tools from nose2._vendor import six from nose2.plugins import junitxml, logcapture from nose2.plugins.loader import functions, generators, parameters, testcases from nose2.tests._common import TestCase def _fromisoformat(date_str): # use fromisoformat when it is available, but failover to strptime for python2 and # older python3 versions if hasattr(datetime.datetime, "fromisoformat"): return datetime.datetime.fromisoformat(date_str) return datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%f") class TestJunitXmlPlugin(TestCase): _RUN_IN_TEMP = True BAD_FOR_XML_U = six.u("A\x07 B\x0B C\x10 D\uD900 " "E\uFFFE F\x80 G\x90 H\uFDDD") # UTF-8 string with double null (invalid) BAD_FOR_XML_B = six.b( "A\x07 B\x0b C\x10 D\xed\xa4\x80 " "E\xef\xbf\xbe F\xc2\x80 G\xc2\x90 H\xef\xb7\x9d " "\x00\x00" ) # "byte" strings in PY2 and unicode in py3 works as expected will # will translate surrogates into UTF-16 characters so BAD_FOR_XML_U # should have 8 letters follows by 0xFFFD, but only 4 when keeping # the discouraged/restricted ranges. Respectively: # "A\uFFFD B\uFFFD C\uFFFD D\uFFFD E\uFFFD F\uFFFD G\uFFFD H\uFFFD" # "A\uFFFD B\uFFFD C\uFFFD D\uFFFD E\uFFFD F\x80 G\x90 H\uFDDD" # # In Python 2 Invalid ascii characters seem to get escaped out as part # of tracebace.format_traceback so full and partial replacements are: # "A\uFFFD B\uFFFD C\uFFFD D\\\\ud900 E\\\\ufffe F\\\\x80 G\\\\x90 H\\\\ufddd" # "A\uFFFD B\uFFFD C\uFFFD D\\\\ud900 E\\\\ufffe F\\\\x80 G\\\\x90 H\\\\ufddd" # # Byte strings in py3 as errors are replaced by their representation string # So these will be safe and not have any replacements # "b'A\\x07 B\\x0b C\\x10 D\\xed\\xa4\\x80 E\\xef\\xbf\\xbe F\\xc2\\x80 # G\\xc2\\x90 H\\xef\\xb7\\x9d \\x00\\x00" if sys.maxunicode <= 0xFFFF: EXPECTED_RE = six.u("^[\x09\x0A\x0D\x20\x21-\uD7FF\uE000-\uFFFD]*$") EXPECTED_RE_SAFE = six.u( "^[\x09\x0A\x0D\x20\x21-\x7E\x85" "\xA0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFD]*$" ) else: EXPECTED_RE = six.u( "^[\x09\x0A\x0D\x20\x21-\uD7FF\uE000-\uFFFD" "\u10000-\u10FFFF]*$" ) EXPECTED_RE_SAFE = six.u( "^[\x09\x0A\x0D\x20\x21-\x7E\x85" "\xA0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFD" "\u10000-\u1FFFD\u20000-\u2FFFD" "\u30000-\u3FFFD\u40000-\u4FFFD" "\u50000-\u5FFFD\u60000-\u6FFFD" "\u70000-\u7FFFD\u80000-\u8FFFD" "\u90000-\u8FFFD\uA0000-\uAFFFD" "\uB0000-\uBFFFD\uC0000-\uCFFFD" "\uD0000-\uDFFFD\uE0000-\uEFFFD" "\uF0000-\uFFFFD\u100000-\u10FFFD]*$" ) def setUp(self): super(TestJunitXmlPlugin, self).setUp() self.session = session.Session() self.loader = loader.PluggableTestLoader(self.session) self.result = result.PluggableTestResult(self.session) self.plugin = junitxml.JUnitXmlReporter(session=self.session) self.plugin.register() # Python 2.7 needs this # assertRegexpMatches() was renamed to assertRegex() in 3.2 if not hasattr(self, "assertRegex"): self.assertRegex = self.assertRegexpMatches class Test(unittest.TestCase): def test(self): pass def test_chdir(self): TEMP_SUBFOLDER = "test_chdir" os.mkdir(TEMP_SUBFOLDER) os.chdir(TEMP_SUBFOLDER) def test_fail(self): assert False def test_err(self): 1 / 0 def test_skip(self): self.skipTest("skip") def test_skip_no_reason(self): self.skipTest("") def test_bad_xml(self): raise RuntimeError(TestJunitXmlPlugin.BAD_FOR_XML_U) def test_bad_xml_b(self): raise RuntimeError(TestJunitXmlPlugin.BAD_FOR_XML_B) def test_gen(self): def check(a, b): # workaround: # for the test which ensures that the timestamp increases between # generator test runs, insert a very small sleep # # on py3.10 on Windows, we have observed both of these tests getting # the same timestamp time.sleep(0.001) self.assertEqual(a, b) yield check, 1, 1 yield check, 1, 2 @tools.params(1, 2, 3) def test_params(self, p): self.assertEqual(p, 2) def test_with_log(self): logging.info("log message") self.case = Test def test_success_added_to_xml(self): test = self.case("test") test(self.result) self.assertEqual(self.plugin.numtests, 1) self.assertEqual(len(self.plugin.tree.findall("testcase")), 1) def test_failure_includes_traceback(self): test = self.case("test_fail") test(self.result) case = self.plugin.tree.find("testcase") failure = case.find("failure") assert failure is not None assert "Traceback" in failure.text def test_error_bad_xml(self): self.plugin.keep_restricted = False test = self.case("test_bad_xml") test(self.result) case = self.plugin.tree.find("testcase") error = case.find("error") self.assertRegex(error.text, self.EXPECTED_RE_SAFE) def test_error_bad_xml_keep(self): self.plugin.keep_restricted = True test = self.case("test_bad_xml") test(self.result) case = self.plugin.tree.find("testcase") error = case.find("error") self.assertRegex(error.text, self.EXPECTED_RE) def test_error_bad_xml_b(self): self.plugin.keep_restricted = False test = self.case("test_bad_xml_b") test(self.result) case = self.plugin.tree.find("testcase") error = case.find("error") assert error is not None self.assertRegex(error.text, self.EXPECTED_RE_SAFE) def test_error_bad_xml_b_keep(self): self.plugin.keep_restricted = True test = self.case("test_bad_xml_b") test(self.result) case = self.plugin.tree.find("testcase") error = case.find("error") assert error is not None self.assertRegex(error.text, self.EXPECTED_RE) def test_error_includes_traceback(self): test = self.case("test_err") test(self.result) case = self.plugin.tree.find("testcase") error = case.find("error") assert error is not None assert "Traceback" in error.text def test_skip_includes_skipped(self): test = self.case("test_skip") test(self.result) case = self.plugin.tree.find("testcase") skip = case.find("skipped") assert skip is not None self.assertEqual(skip.get("message"), "test skipped: skip") self.assertEqual(skip.text, "skip") def test_skip_includes_skipped_no_reason(self): test = self.case("test_skip_no_reason") test(self.result) case = self.plugin.tree.find("testcase") skip = case.find("skipped") assert skip is not None self.assertIsNone(skip.get("message")) self.assertIsNone(skip.text) def test_generator_timestamp_increases(self): gen = generators.Generators(session=self.session) gen.register() event = events.LoadFromTestCaseEvent(self.loader, self.case) self.session.hooks.loadTestsFromTestCase(event) cases = event.extraTests for case in cases: case(self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 2) test1_timestamp_str = xml[0].get("timestamp") test1_timestamp = _fromisoformat(test1_timestamp_str) test2_timestamp_str = xml[1].get("timestamp") test2_timestamp = _fromisoformat(test2_timestamp_str) self.assertGreater(test2_timestamp, test1_timestamp) def test_generator_test_name_correct(self): gen = generators.Generators(session=self.session) gen.register() event = events.LoadFromTestCaseEvent(self.loader, self.case) self.session.hooks.loadTestsFromTestCase(event) cases = event.extraTests for case in cases: case(self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 2) self.assertEqual(xml[0].get("name"), "test_gen:1") self.assertEqual(xml[1].get("name"), "test_gen:2") def test_generator_test_full_name_correct(self): gen = generators.Generators(session=self.session) gen.register() self.plugin.test_fullname = True event = events.LoadFromTestCaseEvent(self.loader, self.case) self.session.hooks.loadTestsFromTestCase(event) cases = event.extraTests for case in cases: case(self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 2) self.assertEqual(xml[0].get("name"), "test_gen:1 (1, 1)") self.assertEqual(xml[1].get("name"), "test_gen:2 (1, 2)") def test_function_classname_is_module(self): fun = functions.Functions(session=self.session) fun.register() def test_func(): pass cases = fun._createTests(test_func) self.assertEqual(len(cases), 1) cases[0](self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 1) self.assertTrue(xml[0].get("classname").endswith("test_junitxml")) def test_params_test_name_correct(self): # param test loading is a bit more complex than generator # loading. XXX -- can these be reconciled so they both # support exclude and also both support loadTestsFromTestCase? plug1 = parameters.Parameters(session=self.session) plug1.register() plug2 = testcases.TestCaseLoader(session=self.session) plug2.register() # need module to fire top-level event class Mod(object): pass m = Mod() m.Test = self.case event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) for case in event.extraTests: case(self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 13) params = [x for x in xml if x.get("name").startswith("test_params")] self.assertEqual(len(params), 3) self.assertEqual(params[0].get("name"), "test_params:1") self.assertEqual(params[1].get("name"), "test_params:2") self.assertEqual(params[2].get("name"), "test_params:3") def test_params_test_full_name_correct(self): plug1 = parameters.Parameters(session=self.session) plug1.register() plug2 = testcases.TestCaseLoader(session=self.session) plug2.register() # need module to fire top-level event class Mod(object): pass m = Mod() m.Test = self.case event = events.LoadFromModuleEvent(self.loader, m) self.plugin.test_fullname = True self.session.hooks.loadTestsFromModule(event) for case in event.extraTests: case(self.result) xml = self.plugin.tree.findall("testcase") self.assertEqual(len(xml), 13) params = [x for x in xml if x.get("name").startswith("test_params")] self.assertEqual(len(params), 3) self.assertEqual(params[0].get("name"), "test_params:1 (1)") self.assertEqual(params[1].get("name"), "test_params:2 (2)") self.assertEqual(params[2].get("name"), "test_params:3 (3)") def test_writes_xml_file_at_end(self): test = self.case("test") test(self.result) event = events.StopTestRunEvent(None, self.result, 1, 1) self.plugin.stopTestRun(event) with open(self.plugin.path, "r") as fh: tree = ET.parse(fh).getroot() self.assertEqual(len(tree.findall("testcase")), 1) case = tree.find("testcase") assert "time" in case.attrib assert "timestamp" in case.attrib assert "classname" in case.attrib self.assertEqual(case.get("name"), "test") self.assertEqual(tree.get("errors"), "0") self.assertEqual(tree.get("failures"), "0") self.assertEqual(tree.get("skipped"), "0") self.assertEqual(tree.get("tests"), "1") assert "time" in tree.attrib def test_xml_file_path_is_not_affected_by_chdir_in_test(self): initial_dir = os.path.realpath(os.getcwd()) test = self.case("test_chdir") test(self.result) plugin_dir = os.path.realpath(os.path.dirname(self.plugin.path)) assert initial_dir == plugin_dir, self.plugin.path def test_xml_contains_empty_system_out_without_logcapture(self): test = self.case("test_with_log") test(self.result) case = self.plugin.tree.find("testcase") system_out = case.find("system-out") assert system_out is not None assert not system_out.text def test_xml_contains_log_message_in_system_out_with_logcapture(self): self.logcapture_plugin = logcapture.LogCapture(session=self.session) self.logcapture_plugin.register() test = self.case("test_with_log") test(self.result) case = self.plugin.tree.find("testcase") system_out = case.find("system-out") assert system_out is not None assert "log message" in system_out.text assert "INFO" in system_out.text ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_layers_plugin.py0000664002342000234200000002656114176405443022263 0ustar00sirosensirosenimport sys import unittest from nose2 import events, exceptions, loader, session from nose2.plugins import layers from nose2.tests._common import TestCase class TestLayers(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(session=self.session) self.session.testLoader = self.loader self.plugin = layers.Layers(session=self.session) def test_simple_layer_inheritance(self): class L1(object): pass class L2(L1): pass class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass suite = unittest.TestSuite([T2("test"), T1("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ [ "test (nose2.tests.unit.test_layers_plugin.T1)", ["test (nose2.tests.unit.test_layers_plugin.T2)"], ] ] self.assertEqual(self.names(event.suite), expect) def test_multiple_inheritance(self): class L1(object): pass class L2(L1): pass class L3(L1): pass class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass class T3(unittest.TestCase): layer = L3 def test(self): pass suite = unittest.TestSuite([T2("test"), T1("test"), T3("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ [ "test (nose2.tests.unit.test_layers_plugin.T1)", ["test (nose2.tests.unit.test_layers_plugin.T2)"], ["test (nose2.tests.unit.test_layers_plugin.T3)"], ] ] self.assertEqual(self.names(event.suite), expect) def test_deep_inheritance(self): class L1(object): pass class L2(L1): pass class L3(L1): pass class L4(L2, L1): pass class L5(L4): pass class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass class T3(unittest.TestCase): layer = L3 def test(self): pass class T4(unittest.TestCase): layer = L4 def test(self): pass class T5(unittest.TestCase): layer = L5 def test(self): pass suite = unittest.TestSuite( [T2("test"), T1("test"), T3("test"), T4("test"), T5("test")] ) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ [ "test (nose2.tests.unit.test_layers_plugin.T1)", [ "test (nose2.tests.unit.test_layers_plugin.T2)", [ "test (nose2.tests.unit.test_layers_plugin.T4)", ["test (nose2.tests.unit.test_layers_plugin.T5)"], ], ], ["test (nose2.tests.unit.test_layers_plugin.T3)"], ] ] self.assertEqual(self.names(event.suite), expect) def test_mixed_layers_no_layers(self): class L1(object): pass class L2(L1): pass class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass class T3(unittest.TestCase): def test(self): pass suite = unittest.TestSuite([T2("test"), T1("test"), T3("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ "test (nose2.tests.unit.test_layers_plugin.T3)", [ "test (nose2.tests.unit.test_layers_plugin.T1)", ["test (nose2.tests.unit.test_layers_plugin.T2)"], ], ] self.assertEqual(self.names(event.suite), expect) def test_ordered_layers(self): class L1(object): pass class L2(L1): position = 1 class L3(L1): position = 2 class L4(L1): position = 3 class L5(L2): position = 4 class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass class T3(unittest.TestCase): layer = L3 def test(self): pass class T4(unittest.TestCase): layer = L4 def test(self): pass class T5(unittest.TestCase): layer = L5 def test(self): pass suite = unittest.TestSuite( [T2("test"), T1("test"), T3("test"), T4("test"), T5("test")] ) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ [ "test (nose2.tests.unit.test_layers_plugin.T1)", [ "test (nose2.tests.unit.test_layers_plugin.T2)", ["test (nose2.tests.unit.test_layers_plugin.T5)"], ], ["test (nose2.tests.unit.test_layers_plugin.T3)"], ["test (nose2.tests.unit.test_layers_plugin.T4)"], ] ] self.assertEqual(self.names(event.suite), expect) def test_mixin_in_top_layer(self): class M1(object): pass class L1(object): mixins = (M1,) class T1(unittest.TestCase): layer = L1 def test(self): pass suite = unittest.TestSuite([T1("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [[["test (nose2.tests.unit.test_layers_plugin.T1)"]]] # M1 # L1 # T1 self.assertEqual(self.names(event.suite), expect) def test_mixin_in_inner_layer(self): class M1(object): pass class L1(object): pass class L2(L1): mixins = (M1,) class T1(unittest.TestCase): layer = L1 def test(self): pass class T2(unittest.TestCase): layer = L2 def test(self): pass suite = unittest.TestSuite([T1("test"), T2("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ # L1 [ "test (nose2.tests.unit.test_layers_plugin.T1)", # M1 [["test (nose2.tests.unit.test_layers_plugin.T2)"]], # L2 ] ] self.assertEqual(self.names(event.suite), expect) def test_mixin_inheritance(self): # without mixin # L1 # -> L3 # -> L4 # -> L5 # L2 # -> L6 # # with mixin new behavior: # the mixin (L4, which comes with L3 and L1) # is inserted after the parent layer (L2). # L2 # -> L1 # -> L3 # -> L4 # -> L6 # -> L5 # # with mixin old behavior # the mixin (L4, which comes with L3 and L1) # is inserted before the parent layer (L2). # L1 # -> L3 # -> L4 # -> L2 # -> L6 # -> L5 class L1(object): pass class L2(object): # a mixin, doesn't share a base w/L1 pass class L3(L1): pass class L4(L3): pass class L5(L4): pass class L6(L2): mixins = (L4,) class T1(unittest.TestCase): layer = L1 def test(self): pass class T3(unittest.TestCase): layer = L3 def test(self): pass class T4(unittest.TestCase): layer = L4 def test(self): pass class T5(unittest.TestCase): layer = L5 def test(self): pass class T6(unittest.TestCase): layer = L6 def test(self): pass suite = unittest.TestSuite( [T6("test"), T1("test"), T3("test"), T4("test"), T5("test")] ) event = events.StartTestRunEvent(None, suite, None, 0, None) self.plugin.startTestRun(event) expect = [ # L2 [ # L1 [ "test (nose2.tests.unit.test_layers_plugin.T1)", # T1 # L3 [ "test (nose2.tests.unit.test_layers_plugin.T3)", # T3 # L4 [ "test (nose2.tests.unit.test_layers_plugin.T4)", # T4 # L5 ["test (nose2.tests.unit.test_layers_plugin.T5)"], # L6 ["test (nose2.tests.unit.test_layers_plugin.T6)"], ], ], ] ] ] self.assertEqual(self.names(event.suite), expect) def test_invalid_top_layer(self): if sys.version_info >= (3, 0): # in python 3, L1 will automatically have `object` has base, so # this test does not make sense, and will actually fail. return class L1: pass class T1(unittest.TestCase): layer = L1 def test(self): pass suite = unittest.TestSuite([T1("test")]) event = events.StartTestRunEvent(None, suite, None, 0, None) with self.assertRaises(exceptions.LoadTestsFailure): self.plugin.startTestRun(event) def names(self, suite): return [n for n in self.iternames(suite)] def iternames(self, suite): for t in suite: if isinstance(t, unittest.TestCase): if sys.version_info >= (3, 5): test_module = t.__class__.__module__ test_class = t.__class__.__name__ test_method = t._testMethodName yield "%s (%s.%s)" % (test_method, test_module, test_class) else: yield str(t) else: yield [n for n in self.iternames(t)] def _listset(self, lst): n = set([]) for t in lst: if isinstance(t, list): n.add(self._listset(t)) else: n.add(t) return frozenset(n) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_loader.py0000664002342000234200000000673614176405443020656 0ustar00sirosensirosenfrom nose2 import events, loader, session from nose2.tests._common import TestCase class TestPluggableTestLoader(TestCase): def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(self.session) def test_failed_load_tests_exception(self): suite = self.loader.failedLoadTests("test", RuntimeError("err")) tc = suite._tests[0] with self.assertRaises(RuntimeError) as cm: tc.test() self.assertEqual(cm.exception.args, ("err",)) def test_failed_load_tests_exc_info(self): suite = self.loader.failedLoadTests( "test", (RuntimeError, RuntimeError("err"), None) ) tc = suite._tests[0] with self.assertRaises(RuntimeError) as cm: tc.test() self.assertEqual(cm.exception.args, ("err",)) def test_load_from_module_calls_hook(self): self.session.hooks.register("loadTestsFromModule", FakePlugin()) evt = events.LoadFromModuleEvent(self.loader, "some_module") self.session.hooks.loadTestsFromModule(evt) self.assertTrue( evt.fakeLoadFromModule, "FakePlugin.loadTestsFromModule() was not called" ) def test_load_from_name_calls_hook(self): self.session.hooks.register("loadTestsFromName", FakePlugin()) evt = events.LoadFromNameEvent(self.loader, "some_name", "some_module") self.session.hooks.loadTestsFromName(evt) self.assertTrue( evt.fakeLoadFromName, "FakePlugin.fakeLoadFromName() was not called" ) def test_load_from_names_calls_hook(self): self.session.hooks.register("loadTestsFromNames", FakePlugin()) evt = events.LoadFromNamesEvent(self.loader, ["some_name"], "some_module") self.session.hooks.loadTestsFromNames(evt) self.assertTrue( evt.fakeLoadFromNames, "FakePlugin.fakeLoadFromNames() was not called" ) def test_loader_from_names_calls_module_hook(self): fake_plugin = FakePlugin() self.session.hooks.register("loadTestsFromModule", fake_plugin) self.loader.loadTestsFromNames([], "some_module") self.assertTrue( fake_plugin.fakeLoadFromModule, "FakePlugin.loadTestsFromModule() was not called", ) def test_loader_from_names_calls_name_hook(self): fake_plugin = FakePlugin() self.session.hooks.register("loadTestsFromName", fake_plugin) self.loader.loadTestsFromNames(["some_name"]) self.assertTrue( fake_plugin.fakeLoadFromName, "FakePlugin.loadTestsFromName() was not called", ) def test_loader_from_names_calls_names_hook(self): fake_plugin = FakePlugin() self.session.hooks.register("loadTestsFromNames", fake_plugin) self.loader.loadTestsFromNames(["some_name"]) self.assertTrue( fake_plugin.fakeLoadFromNames, "FakePlugin.loadTestsFromNames() was not called", ) class FakePlugin(object): def __init__(self): self.fakeLoadFromModule = False self.fakeLoadFromName = False self.fakeLoadFromNames = False def loadTestsFromModule(self, event): event.fakeLoadFromModule = True self.fakeLoadFromModule = True def loadTestsFromName(self, event): event.fakeLoadFromName = True self.fakeLoadFromName = True def loadTestsFromNames(self, event): event.fakeLoadFromNames = True self.fakeLoadFromNames = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_logcapture_plugin.py0000664002342000234200000000420314176405443023116 0ustar00sirosensirosenimport logging from nose2 import session from nose2.plugins import logcapture from nose2.tests._common import TestCase log = logging.getLogger(__name__) class StubLogging(object): def __init__(self, name=None): self.name = name self.handlers = [] self.level = None def getLogger(self, _name=None): return self def addHandler(self, handler): self.handlers.append(handler) def setLevel(self, level): self.level = level def debug(self, message, *arg): # import pdb; pdb.set_trace() for handler in self.handlers: handler.emit(StubRecord(message % arg)) class StubRecord(object): def __init__(self, message): self.message = message self.name = "stub" self.levelname = "stub" self.exc_info = None self.exc_text = None self.stack_info = None def getMessage(self): return self.message class LogCaptureUnitTest(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.plugin = logcapture.LogCapture(session=self.session) self.logging = logcapture.logging logcapture.logging = StubLogging() def tearDown(self): logcapture.logging = self.logging def event(self, error=True, failed=False): e = Event() e.metadata = {} return e def test_buffer_cleared_after_each_test(self): self.plugin.startTestRun(None) self.plugin.startTest(None) logcapture.logging.getLogger("test").debug("hello") assert self.plugin.handler.buffer self.plugin.setTestOutcome(self.event()) assert self.plugin.handler.buffer self.plugin.stopTest(None) assert not self.plugin.handler.buffer def test_buffered_logs_attached_to_event(self): self.plugin.startTestRun(None) self.plugin.startTest(None) logcapture.logging.getLogger("test").debug("hello") assert self.plugin.handler.buffer e = self.event() self.plugin.setTestOutcome(e) assert "logs" in e.metadata, "No log in %s" % e.metadata class Event: pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/unit/test_mp_plugin.py0000664002342000234200000000544614220574143021371 0ustar00sirosensirosenimport sys from nose2 import session from nose2._vendor import six from nose2.plugins import mp from nose2.tests._common import Conn, TestCase class TestMPPlugin(TestCase): def setUp(self): self.session = session.Session() self.plugin = mp.MultiProcess(session=self.session) def test_gentests(self): conn = Conn([1, 2, 3]) res = [] for x in mp.gentests(conn): res.append(x) self.assertEqual(res, [1, 2, 3]) def test_recording_plugin_interface(self): rpi = mp.RecordingPluginInterface() # this one should record rpi.setTestOutcome(None) # none of these should record rpi.getTestCaseNames(None) rpi.startSubprocess(None) rpi.stopSubprocess(None) rpi.registerInSubprocess(None) rpi.loadTestsFromModule(None) rpi.loadTestsFromTestCase(None) rpi.moduleLoadedSuite(None) rpi.getTestMethodNames(None) self.assertEqual(rpi.flush(), [("setTestOutcome", None)]) def test_address(self): platform = sys.platform try: sys.platform = "linux" host = "1.2.3.4" port = 245 self.plugin.setAddress(host) self.assertEqual((self.plugin.bind_host, self.plugin.bind_port), (host, 0)) self.plugin.setAddress("%s:%i" % (host, port)) self.assertEqual( (self.plugin.bind_host, self.plugin.bind_port), (host, port) ) self.plugin.setAddress(None) self.assertEqual((self.plugin.bind_host, self.plugin.bind_port), (None, 0)) sys.platform = "win32" self.plugin.setAddress(host) self.assertEqual((self.plugin.bind_host, self.plugin.bind_port), (host, 0)) self.plugin.setAddress("%s:%i" % (host, port)) self.assertEqual( (self.plugin.bind_host, self.plugin.bind_port), (host, port) ) self.plugin.setAddress(None) self.assertEqual( (self.plugin.bind_host, self.plugin.bind_port), ("127.116.157.163", 0) ) finally: sys.platform = platform def test_session_import(self): config = six.moves.configparser.ConfigParser() config.add_section(mp.MultiProcess.configSection) export_session = { "config": config, "verbosity": None, "startDir": "", "topLevelDir": "", "pluginClasses": [mp.MultiProcess], } import logging session = mp.import_session(logging.root, export_session) self.assertIn("registerInSubprocess", session.hooks.methods) self.assertIn("startSubprocess", session.hooks.methods) self.assertIn("stopSubprocess", session.hooks.methods) pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_outcomes_plugin.py0000664002342000234200000000441314176405443022612 0ustar00sirosensirosenfrom nose2 import events, result, session from nose2.plugins import outcomes from nose2.tests._common import TestCase class TestOutComesPlugin(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.result = result.PluggableTestResult(self.session) self.plugin = outcomes.Outcomes(session=self.session) self.plugin.register() class Test(TestCase): def test_e1(self): raise KeyError("k") def test_e2(self): raise TypeError("x") def test_e3(self): raise IOError("o") self.case = Test class Watcher(events.Plugin): def __init__(self): self.outcomes = {} def testOutcome(self, event): self.outcomes.setdefault(event.outcome, []).append(event) self.watcher = Watcher(session=self.session) self.watcher.register() def test_labels_upper(self): self.assertEqual(self.plugin.labels("xxx"), ("X", "XXX")) def test_can_do_nothing_when_not_configured(self): test = self.case("test_e1") test(self.result) assert self.watcher.outcomes["error"] assert "failed" not in self.watcher.outcomes def test_can_treat_as_fail(self): self.plugin.treatAsFail.add("KeyError") test = self.case("test_e1") test(self.result) assert self.watcher.outcomes["failed"] assert "error" not in self.watcher.outcomes def test_can_treat_as_skip(self): self.plugin.treatAsSkip.add("KeyError") test = self.case("test_e1") test(self.result) assert self.watcher.outcomes["skipped"] assert "error" not in self.watcher.outcomes def test_can_handle_multiple_events_cleanly(self): self.plugin.treatAsSkip.add("KeyError") self.plugin.treatAsFail.add("TypeError") test = self.case("test_e1") test(self.result) test = self.case("test_e2") test(self.result) test = self.case("test_e3") test(self.result) self.assertEqual(len(self.watcher.outcomes["skipped"]), 1) self.assertEqual(len(self.watcher.outcomes["error"]), 1) self.assertEqual(len(self.watcher.outcomes["failed"]), 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_params_plugin.py0000664002342000234200000001272014176405443022237 0ustar00sirosensirosenfrom nose2 import events, loader, session, util from nose2.plugins.loader import parameters, testcases from nose2.tests._common import TestCase from nose2.tools import cartesian_params, params class TestParams(TestCase): tags = ["unit"] def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(self.session) self.plugin = parameters.Parameters(session=self.session) # need testcase loader to make the initial response to load from module self.tcl = testcases.TestCaseLoader(session=self.session) def test_ignores_ordinary_functions(self): class Mod(object): pass def test(): pass m = Mod() m.test = test event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 0) def test_can_load_tests_from_parameterized_by_params_functions(self): class Mod(object): __name__ = "themod" def check(x): assert x == 1 @params(1, 2) def test(a): check(a) m = Mod() m.test = test test.__module__ = m.__name__ event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 2) # check that test names are sensible self.assertEqual(util.test_name(event.extraTests[0]), "themod.test:1") self.assertEqual(util.test_name(event.extraTests[1]), "themod.test:2") def test_can_load_tests_from_parameterized_by_cartesian_params_functions(self): class Mod(object): __name__ = "themod" def check(x, y): assert x == y @cartesian_params((1, 2), (2, 3)) def test(a, b): check(a, b) m = Mod() m.test = test test.__module__ = m.__name__ event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 4) # check that test names are sensible self.assertEqual(util.test_name(event.extraTests[0]), "themod.test:1") self.assertEqual(util.test_name(event.extraTests[1]), "themod.test:2") self.assertEqual(util.test_name(event.extraTests[2]), "themod.test:3") self.assertEqual(util.test_name(event.extraTests[3]), "themod.test:4") def test_can_load_tests_from_parameterized_by_params_methods(self): class Mod(object): __name__ = "themod" class Test(TestCase): @params(1, 2) def test(self, a): assert a == 1 m = Mod() m.Test = Test Test.__module__ = m.__name__ event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 1) self.assertEqual(len(event.extraTests[0]._tests), 2) # check that test names are sensible t1 = util.test_name(event.extraTests[0]._tests[0], qualname=False) self.assertEqual(t1, "themod.Test.test:1") t2 = util.test_name(event.extraTests[0]._tests[1], qualname=False) self.assertEqual(t2, "themod.Test.test:2") def test_can_load_tests_from_parameterized_by_cartesian_params_methods(self): class Mod(object): __name__ = "themod" class Test(TestCase): @cartesian_params((1, 2), (2, 3)) def test(self, a, b): assert a == b m = Mod() m.Test = Test Test.__module__ = m.__name__ event = events.LoadFromModuleEvent(self.loader, m) self.session.hooks.loadTestsFromModule(event) self.assertEqual(len(event.extraTests), 1) self.assertEqual(len(event.extraTests[0]._tests), 4) # check that test names are sensible self.assertEqual( util.test_name(event.extraTests[0]._tests[0]), "themod.Test.test:1" ) self.assertEqual( util.test_name(event.extraTests[0]._tests[1]), "themod.Test.test:2" ) self.assertEqual( util.test_name(event.extraTests[0]._tests[2]), "themod.Test.test:3" ) self.assertEqual( util.test_name(event.extraTests[0]._tests[3]), "themod.Test.test:4" ) def test_params_creates_params_for_function(self): @params((1, 2), ("a", "b")) def test(a, b): assert a == b self.assertTupleEqual(tuple(test.paramList), ((1, 2), ("a", "b"))) def test_cartesian_params_creates_cartesian_product_of_params_for_function(self): @cartesian_params((1, 2), ("a", "b")) def test(a, b): assert a == b self.assertTupleEqual( tuple(test.paramList), ((1, "a"), (1, "b"), (2, "a"), (2, "b")) ) def test_params_creates_params_for_method(self): class Test(TestCase): @params((1, 2), ("a", "b")) def test(self, a, b): assert a == b self.assertTupleEqual(tuple(Test.test.paramList), ((1, 2), ("a", "b"))) def test_cartesian_params_creates_cartesian_product_of_params_for_method(self): class Test(TestCase): @cartesian_params((1, 2), ("a", "b")) def test(self, a, b): assert a == b self.assertTupleEqual( tuple(Test.test.paramList), ((1, "a"), (1, "b"), (2, "a"), (2, "b")) ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_plugin_api.py0000664002342000234200000000224614176405443021527 0ustar00sirosensirosenfrom nose2 import events, session from nose2.tests._common import TestCase class Example(events.Plugin): commandLineSwitch = ("X", "xxx", "triple x") def testOutcome(self, event): pass class TestPluginApi(TestCase): def setUp(self): self.session = session.Session() self.plug = Example(session=self.session) super(TestCase, self).setUp() def test_add_option_adds_option(self): helpt = self.session.argparse.format_help() assert "-X, --xxx" in helpt, ( "commandLineSwitch arg not found in help text: %s" % helpt ) def test_short_opt_registers_plugin(self): args, argv = self.session.argparse.parse_known_args(["-X"]) assert self.plug in self.session.plugins assert ( self.plug in self.session.hooks.testOutcome.plugins ), "short opt did not register plugin" def test_long_opt_registers_plugin(self): args, argv = self.session.argparse.parse_known_args(["--xxx"]) assert self.plug in self.session.plugins assert ( self.plug in self.session.hooks.testOutcome.plugins ), "long opt did not register plugin" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/unit/test_printhooks_plugin.py0000664002342000234200000001015214220574143023143 0ustar00sirosensirosenimport sys from nose2 import events, session from nose2._vendor import six from nose2.plugins import printhooks from nose2.tests._common import TestCase class CustomEvent(events.Event): _attrs = events.Event._attrs + ("args",) def __init__(self, args, **kw): self.args = args super(CustomEvent, self).__init__(**kw) class TestPluginA(events.Plugin): def register(self): super(TestPluginA, self).register() self.addMethods("pluginHookA") def register_with_nested_hook(self): super(TestPluginA, self).register() self.addMethods("pluginHookB") class TestPluginB(events.Plugin): def pluginHookA(self, event): event.handled = True return "TestPluginB.pluginHookA" class TestPluginC(events.Plugin): def register(self): super(TestPluginC, self).register() self.addMethods("pluginHookB1") def pluginHookB(self, event): nested_event = CustomEvent("level_two_args") self.session.hooks.pluginHookB1(nested_event) event.handled = True return "TestPluginC.pluginHookB" class IndentAwarePlugin(events.Plugin): def pluginHookA(self, event): event.handled = True return printhooks.INDENT.pop() class TestPrintHooksPlugin(TestCase): tags = ["unit"] def setUp(self): self.err = sys.stderr self.buf = six.StringIO() sys.stderr = self.buf self.addCleanup(self.restore_stderr) self.session = session.Session() self.print_hooks_plugin = printhooks.PrintHooks(session=self.session) self.plugin_a = TestPluginA(session=self.session) self.plugin_b = TestPluginB(session=self.session) def restore_stderr(self): sys.stderr = self.err def test_traces_hooks_created_after_own_registration(self): self.print_hooks_plugin.register() self.plugin_a.register() self.plugin_b.register() event = CustomEvent("args") result = self.session.hooks.pluginHookA(event) self.assertEqual(result, "TestPluginB.pluginHookA") self.assertEqual( "\n" "pluginHookA: " "CustomEvent(handled=False, args='args')", self.buf.getvalue(), ) def test_traces_hooks_created_before_own_registration(self): self.plugin_a.register() self.plugin_b.register() self.print_hooks_plugin.register() event = CustomEvent("args") result = self.session.hooks.pluginHookA(event) self.assertEqual(result, "TestPluginB.pluginHookA") self.assertEqual( "\n" "pluginHookA: " "CustomEvent(handled=False, args='args')", self.buf.getvalue(), ) def test_traces_hooks_that_nobody_implements(self): self.plugin_a.register() self.print_hooks_plugin.register() event = CustomEvent("args") result = self.session.hooks.pluginHookA(event) self.assertEqual(result, None) self.assertEqual( "\n" "pluginHookA: " "CustomEvent(handled=False, args='args')", self.buf.getvalue(), ) def test_indents_nested_hooks_in_trace(self): self.plugin_c = TestPluginC(session=self.session) self.plugin_a.register_with_nested_hook() self.plugin_c.register() self.print_hooks_plugin.register() event = CustomEvent("level_one_args") result = self.session.hooks.pluginHookB(event) self.assertEqual(result, "TestPluginC.pluginHookB") self.assertEqual( "\n" "pluginHookB: " "CustomEvent(handled=False, args='level_one_args')" "\n " "pluginHookB1: " "CustomEvent(handled=False, args='level_two_args')", self.buf.getvalue(), ) def test_hook_implementors_can_modify_trace_indent(self): self.indent_aware_plugin = IndentAwarePlugin(session=self.session) self.plugin_a.register() self.indent_aware_plugin.register() self.print_hooks_plugin.register() event = CustomEvent("args") result = self.session.hooks.pluginHookA(event) self.assertEqual(result, " ") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_prof_plugin.py0000664002342000234200000000172614176405443021726 0ustar00sirosensirosenfrom nose2 import session from nose2.events import StartTestRunEvent from nose2.plugins import prof from nose2.tests._common import Stub, TestCase class TestProfPlugin(TestCase): tags = ["unit"] def setUp(self): self.plugin = prof.Profiler(session=session.Session()) # stub out and save the cProfile and pstats modules self.cProfile = prof.cProfile self.pstats = prof.pstats prof.cProfile = Stub() prof.pstats = Stub() def tearDown(self): prof.cProfile = self.cProfile prof.pstats = self.pstats def test_startTestRun_sets_executeTests(self): _prof = Stub() _prof.runcall = object() prof.cProfile.Profile = lambda: _prof event = StartTestRunEvent( runner=None, suite=None, result=None, startTime=None, executeTests=None ) self.plugin.startTestRun(event) assert event.executeTests is _prof.runcall, "executeTests was not replaced" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_result.py0000664002342000234200000000122414176405443020711 0ustar00sirosensirosenfrom nose2 import result, session from nose2.tests._common import TestCase class TestPluggableTestResult(TestCase): def setUp(self): self.session = session.Session() self.result = result.PluggableTestResult(self.session) def test_skip_reason_not_discarded(self): class Test(TestCase): def test(self): pass plugin = FakePlugin() self.session.hooks.register("testOutcome", plugin) self.result.addSkip(Test("test"), "because") self.assertEqual(plugin.reason, "because") class FakePlugin(object): def testOutcome(self, event): self.reason = event.reason ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_session.py0000664002342000234200000000213414176405443021057 0ustar00sirosensirosenimport unittest from nose2 import events, session class SessionUnitTests(unittest.TestCase): def test_can_create_session(self): session.Session() def test_load_plugins_from_module_can_load_plugins(self): class fakemod: pass f = fakemod() class A(events.Plugin): pass f.A = A s = session.Session() s.loadPluginsFromModule(f) assert s.plugins a = s.plugins[0] self.assertEqual(a.session, s) def test_load_plugins_from_module_does_not_load_plain_Plugins(self): class fakemod: pass f = fakemod() f.A = events.Plugin s = session.Session() s.loadPluginsFromModule(f) self.assertEqual(len(s.plugins), 0) def test_load_plugins_from_module_does_not_duplicate_always_on_plugins(self): class fakemod: pass f = fakemod() class A(events.Plugin): alwaysOn = True f.A = A s = session.Session() s.loadPluginsFromModule(f) self.assertEqual(len(s.plugins), 1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_testcase_loader.py0000664002342000234200000000535614176405443022546 0ustar00sirosensirosenfrom nose2 import events, loader, session from nose2.plugins.loader.testcases import TestCaseLoader from nose2.tests._common import TestCase class TestTestCaseLoader(TestCase): def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(session=self.session) self.plugin = TestCaseLoader(session=self.session) class Mod(object): pass self.module = Mod() class A(TestCase): def test(self): pass class B(TestCase): def runTest(self): pass class C(TestCase): def foo(self): pass class Test(object): def test(self): pass self.module.A = A self.module.B = B self.module.C = C self.module.Test = Test def test_can_find_testcases_in_module(self): event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 1) # A self.assertEqual(len(event.extraTests[1]._tests), 1) # B self.assertEqual(len(event.extraTests[2]._tests), 0) # C def test_get_testcase_names_can_override_name_selection(self): class FooIsOnlyTest(events.Plugin): def getTestCaseNames(self, event): event.handled = True return ["foo"] if "foo" in dir(event.testCase) else [] foo = FooIsOnlyTest(session=self.session) foo.register() event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 0) # A self.assertEqual(len(event.extraTests[1]._tests), 1) # B (runTest) self.assertEqual(len(event.extraTests[2]._tests), 1) # C def test_plugins_can_exclude_test_names(self): class Excluder(events.Plugin): def getTestCaseNames(self, event): event.excludedNames.append("test") excl = Excluder(session=self.session) excl.register() event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 0) # A self.assertEqual(len(event.extraTests[1]._tests), 1) # B (runTest) self.assertEqual(len(event.extraTests[2]._tests), 0) # C ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tests/unit/test_testclass_loader.py0000664002342000234200000000740214176405443022732 0ustar00sirosensirosenfrom nose2 import events, loader, session from nose2.plugins.loader.testclasses import TestClassLoader from nose2.tests._common import TestCase class TestTestClassLoader(TestCase): def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(session=self.session) self.plugin = TestClassLoader(session=self.session) class Mod(object): pass self.module = Mod() class TestA(object): def test(self): pass class TestB(object): def runTest(self): pass class TestC(object): def foo(self): pass class Test(TestCase): def test(self): pass self.module.TestA = TestA self.module.TestB = TestB self.module.TestC = TestC self.module.Test = Test def test_can_find_testclasses_in_module(self): event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 1) # TestA self.assertEqual(len(event.extraTests[1]._tests), 0) # TestB self.assertEqual(len(event.extraTests[2]._tests), 0) # TestC def test_get_testmethod_names_can_override_name_selection(self): class FooIsOnlyTest(events.Plugin): def getTestMethodNames(self, event): event.handled = True return ["foo"] if "foo" in dir(event.testCase) else [] foo = FooIsOnlyTest(session=self.session) foo.register() event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 0) # TestA self.assertEqual(len(event.extraTests[1]._tests), 0) # TestB self.assertEqual(len(event.extraTests[2]._tests), 1) # TestC def test_plugins_can_exclude_test_names(self): class Excluder(events.Plugin): def getTestMethodNames(self, event): event.excludedNames.append("test") excl = Excluder(session=self.session) excl.register() event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 3) self.assertEqual(len(event.extraTests[0]._tests), 0) # TestA self.assertEqual(len(event.extraTests[1]._tests), 0) # TestB self.assertEqual(len(event.extraTests[2]._tests), 0) # TestC class TestFailingTestClassLoader(TestCase): def setUp(self): self.session = session.Session() self.loader = loader.PluggableTestLoader(session=self.session) self.plugin = TestClassLoader(session=self.session) class Mod(object): pass self.module = Mod() class TestA(object): def __init__(self): raise RuntimeError("Something bad happened!") def test(self): pass self.module.TestA = TestA def test_can_find_testclasses_in_module(self): event = events.LoadFromModuleEvent(self.loader, self.module) result = self.session.hooks.loadTestsFromModule(event) self.assertEqual(result, None) self.assertEqual(len(event.extraTests), 1) self.assertEqual(len(event.extraTests[0]._tests), 1) # TestA self.assertEqual( event.extraTests[0]._tests[0].__class__.__name__, "LoadTestsFailure" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tests/unit/test_testid_plugin.py0000664002342000234200000001054314220574143022243 0ustar00sirosensirosen"""Test testid plugin.""" import os.path import pickle from nose2 import session from nose2._vendor import six from nose2.events import ReportTestEvent from nose2.plugins import testid from nose2.tests._common import ( FakeLoadFromNameEvent, FakeLoadFromNamesEvent, FakeStartTestEvent, TestCase, ) class UnitTestTestId(TestCase): """Test class TestId. Tests are carried out in a temporary directory, since TestId stores state to file. The temporary directory is removed after testing. """ tags = ["unit"] _RUN_IN_TEMP = True def setUp(self): super(UnitTestTestId, self).setUp() self.stream = six.StringIO() self.session = session.Session() self.plugin = testid.TestId(session=self.session) def test___init__(self): """Test the __init__ method.""" plug = self.plugin # Test attributes for name, exp_val in [ ("configSection", "testid"), ("commandLineSwitch", ("I", "with-id", "Add test ids to output")), ("idfile", os.path.abspath(".noseids")), ("ids", {}), ("tests", {}), ("id", 0), ]: try: val = getattr(plug, name) except AttributeError: self.fail("TestId instance doesn't have attribute %s" % (name,)) self.assertEqual( val, exp_val, "Attribute %s should have value " "'%s', but has value %s" % (name, exp_val, val), ) def test_start_test(self): """Test reportStartTest method.""" self.session.verbosity = 2 event = ReportTestEvent(FakeStartTestEvent(self), self.stream) plug = self.plugin plug.reportStartTest(event) self.assertEqual(plug.id, 1) test_id = self.id() self.assertEqual(plug.ids, {1: test_id}) self.assertEqual(plug.tests, {test_id: 1}) self.assertEqual(self.stream.getvalue(), "#1 ") def test_start_test_twice(self): """Test calling reportStartTest twice.""" self.session.verbosity = 2 event = ReportTestEvent(FakeStartTestEvent(self), self.stream) plug = self.plugin plug.reportStartTest(event) plug.reportStartTest(event) self.assertEqual(plug.id, 1) test_id = self.id() self.assertEqual(plug.ids, {1: test_id}) self.assertEqual(plug.tests, {test_id: 1}) self.assertEqual(self.stream.getvalue(), "#1 #1 ") def test_stop_test_run(self): """Test stopTestRun method.""" plug = self.plugin plug.reportStartTest(ReportTestEvent(FakeStartTestEvent(self), self.stream)) plug.stopTestRun(None) fh = open(plug.idfile, "rb") try: data = pickle.load(fh) finally: fh.close() self.assertEqual(data, {"ids": plug.ids, "tests": plug.tests}) def test_load_tests_from_name(self): """Test loadTestsFromName method.""" plug = self.plugin # By first starting/stopping a test, an ID is assigned by the plugin plug.reportStartTest(ReportTestEvent(FakeStartTestEvent(self), self.stream)) plug.stopTestRun(None) event = FakeLoadFromNameEvent("1") plug.loadTestsFromName(event) # The numeric ID should be translated to this test's ID self.assertEqual(event.name, self.id()) def test_load_tests_from_name_no_ids(self): """Test calling loadTestsFromName when no IDs have been saved.""" plug = self.plugin event = FakeLoadFromNameEvent("1") plug.loadTestsFromName(event) # The event's name should be unchanged, since no IDs should be mapped self.assertEqual(event.name, "1") def test_load_tests_from_names(self): """Test loadTestsFromNames method.""" plug = self.plugin # By first starting/stopping a test, an ID is assigned by the plugin plug.reportStartTest(ReportTestEvent(FakeStartTestEvent(self), self.stream)) plug.stopTestRun(None) event = FakeLoadFromNamesEvent(["1", "2"]) plug.loadTestsFromNames(event) name1, name2 = event.names # The first numeric ID should be translated to this test's ID self.assertEqual(name1, self.id()) # The second one should not have a match self.assertEqual(name2, "2") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1647576546.0 nose2-0.12.0/nose2/tests/unit/test_util.py0000664002342000234200000001102614215002742020336 0ustar00sirosensirosenimport os import sys import unittest from nose2 import util from nose2.tests._common import TestCase class UtilTests(TestCase): _RUN_IN_TEMP = True def test_ensure_importable(self): test_dir = os.path.join(self._work_dir, "test_dir") # Make sure test data is suitable for the test self.assertNotIn(test_dir, sys.path) util.ensure_importable(test_dir) self.assertEqual(test_dir, sys.path[0]) def test_testcase_test_name(self): test = UtilTests("test_ensure_importable") self.assertEqual( test.id(), "nose2.tests.unit.test_util.UtilTests.test_ensure_importable" ) self.assertEqual( util.test_name(test), "nose2.tests.unit.test_util.UtilTests.test_ensure_importable", ) @unittest.skipIf(sys.version_info < (3, 4), "Python >= 3.4 required") def test_subtest_test_name(self): from unittest.case import _SubTest sentinel = getattr(unittest.case, "_subtest_msg_sentinel", None) test = UtilTests("test_ensure_importable") test = _SubTest(test, sentinel, {"i": 1, "j": 2}) self.assertEqual( test.id(), "nose2.tests.unit.test_util.UtilTests.test_ensure_importable (i=1, j=2)", ) self.assertEqual( util.test_name(test), "nose2.tests.unit.test_util.UtilTests.test_ensure_importable", ) class HasClassFixturesTests(TestCase): @unittest.skipIf(sys.version_info < (3,), "Python 3 required") def test_unittest_testcase(self): C = unittest.TestCase self.assertFalse(util.has_class_fixtures(C)) self.assertFalse(util.has_class_fixtures(C())) def test_derived_testcase(self): class C(unittest.TestCase): def runTest(self): pass self.assertFalse(util.has_class_fixtures(C)) self.assertFalse(util.has_class_fixtures(C())) def test_testcase_with_setup(self): class C(unittest.TestCase): @classmethod def setUpClass(cls): pass def runTest(self): pass self.assertTrue(util.has_class_fixtures(C)) self.assertTrue(util.has_class_fixtures(C())) def test_testcase_with_teardown(self): class C(unittest.TestCase): @classmethod def tearDownClass(cls): pass def runTest(self): pass self.assertTrue(util.has_class_fixtures(C)) self.assertTrue(util.has_class_fixtures(C())) def test_derived_derived_testcase(self): class C(unittest.TestCase): @classmethod def setUpClass(cls): pass @classmethod def tearDownClass(cls): pass class D(C): def runTest(self): pass self.assertTrue(util.has_class_fixtures(D)) self.assertTrue(util.has_class_fixtures(D())) class HasModuleFixturesTests(TestCase): def test_module_without_fixtures(self): class M(object): pass M.__name__ = "nose2.foo.bar" class C(unittest.TestCase): def runTest(self): pass C.__module__ = M.__name__ m = M() m.C = C sys.modules[M.__name__] = m try: self.assertFalse(util.has_module_fixtures(C)) self.assertFalse(util.has_module_fixtures(C())) finally: del sys.modules[M.__name__] def test_module_with_setup(self): class M(object): pass M.__name__ = "nose2.foo.bar" class C(unittest.TestCase): def runTest(self): pass C.__module__ = M.__name__ m = M() m.C = C m.setUpModule = lambda: None sys.modules[M.__name__] = m try: self.assertTrue(util.has_module_fixtures(C)) self.assertTrue(util.has_module_fixtures(C())) finally: del sys.modules[M.__name__] def test_module_with_teardown(self): class M(object): pass M.__name__ = "nose2.foo.bar" class C(unittest.TestCase): def runTest(self): pass C.__module__ = M.__name__ m = M() m.C = C m.tearDownModule = lambda: None sys.modules[M.__name__] = m try: self.assertTrue(util.has_module_fixtures(C)) self.assertTrue(util.has_module_fixtures(C())) finally: del sys.modules[M.__name__] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0394313 nose2-0.12.0/nose2/tools/0000775002342000234200000000000014264564615015007 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tools/__init__.py0000664002342000234200000000021414176405443017110 0ustar00sirosensirosenfrom . import decorators, such from .params import cartesian_params, params __all__ = ["cartesian_params", "params", "such", "decorators"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1540849712.0 nose2-0.12.0/nose2/tools/decorators.py0000664002342000234200000000152513365700060017514 0ustar00sirosensirosen""" This module provides decorators that assist the test author to write tests. """ def with_setup(setup): """ A decorator that sets the :func:`setup` method to be executed before the test. It currently works only for function test cases. :param setup: The method to be executed before the test. :type setup: function """ def decorator(testcase): testcase.setup = setup return testcase return decorator def with_teardown(teardown): """ A decorator that sets the :func:`teardown` method to be after before the test. It currently works only for function test cases. :param teardown: The method to be executed after the test. :type teardown: function """ def decorator(testcase): testcase.tearDownFunc = teardown return testcase return decorator ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1643776803.0 nose2-0.12.0/nose2/tools/params.py0000664002342000234200000000326014176405443016640 0ustar00sirosensirosen""" This module contains some code copied from :mod:`unittest2` and other code developed in reference to :mod:`unittest2`. unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved. See: http://docs.python.org/license.html """ import itertools __unittest = True def cartesian_params(*paramList): """Make a test function or method parameterized by cartesian product of parameters .. code-block :: python import unittest from nose2.tools import cartesian_params @cartesian_params((1, 2, 3), ('a', 'b')) def test_nums(num, char): assert num < ord(char) class Test(unittest.TestCase): @cartesian_params((1, 2, 3), ('a', 'b')) def test_less_than(self, num, char): self.assertLess(num, ord(char)) Parameters in the list must be defined as iterable objects (such as ``tuple`` or ``list``). """ def decorator(func): func.paramList = itertools.product(*paramList) return func return decorator def params(*paramList): """Make a test function or method parameterized by parameters. .. code-block :: python import unittest from nose2.tools import params @params(1, 2, 3) def test_nums(num): assert num < 4 class Test(unittest.TestCase): @params((1, 2), (2, 3), (4, 5)) def test_less_than(self, a, b): assert a < b Parameters in the list may be defined as simple values, or as tuples. To pass a tuple as a simple value, wrap it in another tuple. """ def decorator(func): func.paramList = paramList return func return decorator ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1648556131.0 nose2-0.12.0/nose2/tools/such.py0000664002342000234200000002765114220574143016323 0ustar00sirosensirosenimport logging import sys import unittest from contextlib import contextmanager from nose2 import util from nose2._vendor import six from nose2.main import PluggableTestProgram log = logging.getLogger(__name__) __unittest = True LAYERS_PLUGIN_NOT_LOADED_MESSAGE = ( "Warning: Such will not function properly if " 'the "nose2.plugins.layers" plugin not loaded!\n' ) @contextmanager def A(description): """Test scenario context manager. Returns a :class:`nose2.tools.such.Scenario` instance, which by convention is bound to ``it``: .. code-block :: python with such.A('test scenario') as it: # tests and fixtures """ yield Scenario(description) class Helper(unittest.TestCase): def runTest(self): pass helper = Helper() class Scenario(object): """A test scenario. A test scenario defines a set of fixtures and tests that depend on those fixtures. """ _helper = helper def __init__(self, description): self._group = Group("A %s" % description, 0) @contextmanager def having(self, description): """Define a new group under the current group. Fixtures and tests defined within the block will belong to the new group. .. code-block :: python with it.having('a description of this group'): # ... """ last = self._group self._group = self._group.child("having %s" % description) log.debug("starting new group from %s", description) yield self log.debug("leaving group %s", description) self._group = last def uses(self, layer): log.debug("Adding %s as mixin to %s", layer, self._group) self._group.mixins.append(layer) def has_setup(self, func): """Add a :func:`setup` method to this group. The :func:`setup` method will run once, before any of the tests in the containing group. A group may define any number of :func:`setup` functions. They will execute in the order in which they are defined. .. code-block :: python @it.has_setup def setup(): # ... """ self._group.addSetup(func) return func def has_teardown(self, func): """Add a :func:`teardown` method to this group. The :func:`teardown` method will run once, after all of the tests in the containing group. A group may define any number of :func:`teardown` functions. They will execute in the order in which they are defined. .. code-block :: python @it.has_teardown def teardown(): # ... """ self._group.addTeardown(func) return func def has_test_setup(self, func): """Add a test case :func:`setup` method to this group. The :func:`setup` method will run before each of the tests in the containing group. A group may define any number of test case :func:`setup` functions. They will execute in the order in which they are defined. Test :func:`setup` functions may optionally take one argument. If they do, they will be passed the :class:`unittest.TestCase` instance generated for the test. .. code-block :: python @it.has_test_setup def setup(case): # ... """ self._group.addTestSetUp(func) def has_test_teardown(self, func): """Add a test case :func:`teardown` method to this group. The :func:`teardown` method will run before each of the tests in the containing group. A group may define any number of test case :func:`teardown` functions. They will execute in the order in which they are defined. Test :func:`teardown` functions may optionally take one argument. If they do, they will be passed the :class:`unittest.TestCase` instance generated for the test. .. code-block :: python @it.has_test_teardown def teardown(case): # ... """ self._group.addTestTearDown(func) def should(self, desc): """Define a test case. Each function marked with this decorator becomes a test case in the current group. The decorator takes one optional argument, the description of the test case: what it **should** do. If this argument is not provided, the docstring of the decorated function will be used as the test case description. Test functions may optionally take one argument. If they do, they will be passed the :class:`unittest.TestCase` instance generated for the test. They can use this TestCase instance to execute assert methods, among other things. .. code-block :: python @it.should('do this') def dothis(case): # .... @it.should def dothat(): "do that also" # .... """ def decorator(f): _desc = desc if isinstance(desc, six.string_types) else f.__doc__ case = Case(self._group, f, "should %s" % _desc) self._group.addCase(case) return case if isinstance(desc, type(decorator)): return decorator(desc) return decorator def __getattr__(self, attr): return getattr(self._helper, attr) def createTests(self, mod): """Generate test cases for this scenario. .. warning :: You must call this, passing in :func:`globals`, to generate tests from the scenario. If you don't, **no tests will be created**. .. code-block :: python it.createTests(globals()) """ self._checkForLayersPlugin() self._makeGroupTest(mod, self._group) def _checkForLayersPlugin(self): currentSession = PluggableTestProgram.getCurrentSession() if not currentSession: return if not currentSession.isPluginLoaded("nose2.plugins.layers"): sys.stderr.write(LAYERS_PLUGIN_NOT_LOADED_MESSAGE) def _makeGroupTest(self, mod, group, parent_layer=None, position=0): layer = self._makeLayer(group, parent_layer, position) case = self._makeTestCase(group, layer, parent_layer) log.debug("Made test case %s with layer %s from %s", case, layer, group) mod[layer.__name__] = layer layer.__module__ = mod["__name__"] name = case.__name__ long_name = " ".join([n[0].description for n in util.ancestry(layer)] + [name]) mod[long_name] = case if name not in mod: mod[name] = case case.__module__ = mod["__name__"] for index, child in enumerate(group._children): self._makeGroupTest(mod, child, layer, index) def _makeTestCase(self, group, layer, parent_layer): attr = {"layer": layer, "group": group, "description": group.description} def _make_test_func(case): """ Needs to be outside of the for-loop scope, so that ``case`` is properly registered as a closure. """ def _test(s, *args): case(s, *args) return _test for index, case in enumerate(group._cases): name = "test %04d: %s" % (index, case.description) _test = _make_test_func(case) _test.__name__ = name _test.description = case.description _test.case = case _test.index = index if hasattr(case.func, "paramList"): _test.paramList = case.func.paramList attr[name] = _test # for collection and sorting attr[case.description] = _test # for random access by name setups = getattr(parent_layer, "testSetups", []) + group._test_setups if setups: def setUp(self): for func in setups: util.call_with_args_if_expected(func, self) attr["setUp"] = setUp teardowns = ( getattr(parent_layer, "testTeardowns", []) + group._test_teardowns[:] ) if teardowns: def tearDown(self): for func in teardowns: util.call_with_args_if_expected(func, self) attr["tearDown"] = tearDown def methodDescription(self): return getattr(self, self._testMethodName).description attr["methodDescription"] = methodDescription return type(group.description, (unittest.TestCase,), attr) def _makeLayer(self, group, parent_layer=None, position=0): if parent_layer is None: parent_layer = object def setUp(cls): for func in cls.setups: util.call_with_args_if_expected(func, self) def tearDown(cls): for func in cls.teardowns: util.call_with_args_if_expected(func, self) attr = { "description": group.description, "setUp": classmethod(setUp), "tearDown": classmethod(tearDown), "setups": group._setups[:], "testSetups": getattr(parent_layer, "testSetups", []) + group._test_setups, "teardowns": group._teardowns[:], "testTeardowns": getattr(parent_layer, "testTeardowns", []) + group._test_teardowns[:], "position": position, "mixins": (), } if group.base_layer: # inject this layer into the group class list # by making it a subclass of parent_layer layer = group.base_layer if parent_layer not in layer.__bases__: layer.mixins = (parent_layer,) else: layer = type("%s:layer" % group.description, (parent_layer,), attr) if group.mixins: layer.mixins = getattr(layer, "mixins", ()) + tuple(group.mixins) log.debug( "made layer %s with bases %s and mixins %s", layer, layer.__bases__, layer.mixins, ) return layer class Group(object): """A group of tests, with common fixtures and description""" def __init__(self, description, indent=0, parent=None, base_layer=None): self.description = description self.indent = indent self.parent = parent self.base_layer = base_layer self.mixins = [] self._cases = [] self._setups = [] self._teardowns = [] self._test_setups = [] self._test_teardowns = [] self._children = [] def addCase(self, case): if not self._cases: case.first = True case.indent = self.indent self._cases.append(case) def addSetup(self, func): self._setups.append(func) def addTeardown(self, func): self._teardowns.append(func) def addTestSetUp(self, func): self._test_setups.append(func) def addTestTearDown(self, func): self._test_teardowns.append(func) def fullDescription(self): d = [] p = self.parent while p: d.insert(0, p.description) p = p.parent d.append(self.description) return " ".join(d) def child(self, description, base_layer=None): child = Group(description, self.indent + 1, self, base_layer) self._children.append(child) return child class Case(object): """Information about a test case""" _helper = helper def __init__(self, group, func, description): self.group = group self.func = func self.description = description self._setups = [] self._teardowns = [] self.first = False self.full = False def __call__(self, testcase, *args): # ... only if it takes an arg self._helper = testcase util.call_with_args_if_expected(self.func, testcase, *args) def __getattr__(self, attr): return getattr(self._helper, attr) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657956646.0 nose2-0.12.0/nose2/util.py0000664002342000234200000003031314264464446015177 0ustar00sirosensirosen# This module contains some code copied from unittest2/loader.py and other # code developed in reference to that module and others within unittest2. # unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All # Rights Reserved. See: http://docs.python.org/license.html import inspect import logging import os import re import sys import traceback import types from inspect import isgeneratorfunction from nose2._vendor import six __unittest = True IDENT_RE = re.compile(r"^[_a-zA-Z]\w*$", re.UNICODE) VALID_MODULE_RE = re.compile(r"[_a-zA-Z]\w*\.py$", re.UNICODE) def ln(label, char="-", width=70): """Draw a divider, with ``label`` in the middle. >>> ln('hello there') '---------------------------- hello there -----------------------------' ``width`` and divider ``char`` may be specified. Defaults are ``70`` and ``'-'``, respectively. """ label_len = len(label) + 2 chunk = (width - label_len) // 2 out = "%s %s %s" % (char * chunk, label, char * chunk) pad = width - len(out) if pad > 0: out = out + (char * pad) return out def valid_module_name(path): """Is ``path`` a valid module name?""" return VALID_MODULE_RE.search(path) def name_from_path(path): """Translate ``path`` into module name Returns a two-element tuple: 1. a dotted module name that can be used in an import statement (e.g., ``pkg1.test.test_things``) 2. a full path to filesystem directory, which must be on ``sys.path`` for the import to succeed. """ # back up to find module root parts = [] path = os.path.normpath(path) base = os.path.splitext(path)[0] candidate, top = os.path.split(base) parts.append(top) while candidate: if ispackage(candidate): candidate, top = os.path.split(candidate) parts.append(top) else: break return ".".join(reversed(parts)), candidate def module_from_name(name): """Import module from ``name``""" __import__(name) return sys.modules[name] def test_from_name(name, module): """Import test from ``name``""" pos = name.find(":") index = None if pos != -1: real_name, digits = name[:pos], name[pos + 1 :] try: index = int(digits) except ValueError: pass else: name = real_name parent, obj = object_from_name(name, module) return parent, obj, name, index def object_from_name(name, module=None): """ Given a dotted name, return the corresponding object. Getting the object can fail for two reason: - the object is a module that cannot be imported. - the object is a class or a function that does not exists. Since we cannot distinguish between these two cases, we assume we are in the first one. We expect the stacktrace is explicit enough for the user to understand the error. """ import_error = None parts = name.split(".") if module is None: (module, import_error) = try_import_module_from_name(parts[:]) parts = parts[1:] parent = None obj = module for part in parts: try: parent, obj = obj, getattr(obj, part) except AttributeError as e: if is_package_or_module(obj) and import_error: # Re-raise the import error which got us here, since # it probably better describes the issue. _raise_custom_attribute_error(obj, part, e, import_error) else: raise return parent, obj def _raise_custom_attribute_error(obj, attr, attr_error_exc, prev_exc): if sys.version_info >= (3, 0): six.raise_from(attr_error_exc, prev_exc[1]) # for python 2, do exception chaining manually raise AttributeError( "'%s' has not attribute '%s'\n\nMaybe caused by\n\n%s" % (obj, attr, "\n".join(traceback.format_exception(*prev_exc))) ) def is_package_or_module(obj): if hasattr(obj, "__path__") or isinstance(obj, types.ModuleType): return True return False def try_import_module_from_name(splitted_name): """ Try to find the longest importable from the ``splitted_name``, and return the corresponding module, as well as the potential ``ImportError`` exception that occurs when trying to import a longer name. For instance, if ``splitted_name`` is ['a', 'b', 'c'] but only ``a.b`` is importable, this function: 1. tries to import ``a.b.c`` and fails 2. tries to import ``a.b`` and succeeds 3. return ``a.b`` and the exception that occurred at step 1. """ module = None import_error = None while splitted_name: try: module = __import__(".".join(splitted_name)) break except BaseException: import_error = sys.exc_info() del splitted_name[-1] if not splitted_name: six.reraise(*import_error) return (module, import_error) def name_from_args(name, index, args): """Create test name from test args""" summary = ", ".join(repr(arg) for arg in args) return "%s:%s\n%s" % (name, index + 1, summary[:79]) def test_name(test, qualname=True): # XXX does not work for test funcs; test.id() lacks module if hasattr(test, "_funcName"): tid = test._funcName elif hasattr(test, "_testFunc"): tid = "%s.%s" % (test._testFunc.__module__, test._testFunc.__name__) else: if sys.version_info >= (3, 5) and not qualname: test_module = test.__class__.__module__ test_class = test.__class__.__name__ test_method = test._testMethodName tid = "%s.%s.%s" % (test_module, test_class, test_method) else: tid = test.id() if "\n" in tid: tid = tid.split("\n")[0] # subtest support if " " in tid: tid = tid.split(" ")[0] return tid def ispackage(path): """Is this path a package directory?""" if os.path.isdir(path): # at least the end of the path must be a legal python identifier # and __init__.py[co] must exist end = os.path.basename(path) if IDENT_RE.match(end): for init in ("__init__.py", "__init__.pyc", "__init__.pyo"): if os.path.isfile(os.path.join(path, init)): return True if sys.platform.startswith("java") and os.path.isfile( os.path.join(path, "__init__$py.class") ): return True return False def ensure_importable(dirname): """Ensure a directory is on ``sys.path``.""" if dirname not in sys.path: sys.path.insert(0, dirname) def isgenerator(obj): """Is this object a generator?""" return isgeneratorfunction(obj) or getattr(obj, "testGenerator", None) is not None def has_module_fixtures(test): """Does this test live in a module with module fixtures?""" # test may be class or instance test_class = test if isinstance(test, type) else test.__class__ modname = test_class.__module__ try: mod = sys.modules[modname] except KeyError: return return hasattr(mod, "setUpModule") or hasattr(mod, "tearDownModule") def has_class_fixtures(test): # test may be class or instance test_class = test if isinstance(test, type) else test.__class__ # hasattr would be the obvious thing to use here. Unfortunately, all tests # inherit from unittest2.case.TestCase, and that *always* has setUpClass and # tearDownClass methods. Thus, exclude the unitest and unittest2 base # classes from the lookup. def is_not_base_class(c): return ( "unittest.case" not in c.__module__ and "unittest2.case" not in c.__module__ ) has_class_setups = any( "setUpClass" in c.__dict__ for c in test_class.__mro__ if is_not_base_class(c) ) has_class_teardowns = any( "tearDownClass" in c.__dict__ for c in test_class.__mro__ if is_not_base_class(c) ) return has_class_setups or has_class_teardowns def safe_decode(string): """Safely decode a byte string into unicode""" if string is None: return string try: return string.decode() except AttributeError: return string except UnicodeDecodeError: pass try: return string.decode("utf-8") except UnicodeDecodeError: return six.u("") def safe_encode(string, encoding="utf-8"): if string is None: return string if encoding is None: encoding = "utf-8" try: return string.encode(encoding) except AttributeError: return string except UnicodeDecodeError: # already encoded return string except UnicodeEncodeError: return six.u("") def exc_info_to_string(err, test): """Format exception info for output""" formatTraceback = getattr(test, "formatTraceback", None) if formatTraceback is not None: return test.formatTraceback(err) else: return format_traceback(test, err) def format_traceback(test, err): """Converts a :func:`sys.exc_info` -style tuple of values into a string.""" exctype, value, tb = err if not hasattr(tb, "tb_next"): msgLines = tb else: # Skip test runner traceback levels while tb and _is_relevant_tb_level(tb): tb = tb.tb_next failure = getattr(test, "failureException", AssertionError) if exctype is failure: # Skip assert*() traceback levels length = _count_relevant_tb_levels(tb) msgLines = traceback.format_exception(exctype, value, tb, length) else: msgLines = traceback.format_exception(exctype, value, tb) return "".join(msgLines) def transplant_class(cls, module): """Make ``cls`` appear to reside in ``module``. :param cls: A class :param module: A module name :returns: A subclass of ``cls`` that appears to have been defined in ``module``. The returned class's ``__name__`` will be equal to ``cls.__name__``, and its ``__module__`` equal to ``module``. """ class C(cls): pass C.__module__ = module C.__name__ = cls.__name__ return C def parse_log_level(lvl): """Return numeric log level given a string""" try: return int(lvl) except ValueError: pass return getattr(logging, lvl.upper(), logging.WARN) def _is_relevant_tb_level(tb): return "__unittest" in tb.tb_frame.f_globals def _count_relevant_tb_levels(tb): length = 0 while tb and not _is_relevant_tb_level(tb): length += 1 tb = tb.tb_next return length class _WritelnDecorator(object): """Used to decorate file-like objects with a handy :func:`writeln` method""" def __init__(self, stream): self.stream = stream def __getattr__(self, attr): if attr in ("stream", "__getstate__"): raise AttributeError(attr) return getattr(self.stream, attr) def write(self, arg): if sys.version_info[0] == 2: arg = safe_encode(arg, getattr(self.stream, "encoding", "utf-8")) self.stream.write(arg) def writeln(self, arg=None): if arg: self.write(arg) self.write("\n") # text-mode streams translate to \r\n if needed def ancestry(layer): layers = [[layer]] bases = [base for base in bases_and_mixins(layer) if base is not object] while bases: layers.append(bases) newbases = [] for b in bases: for bb in bases_and_mixins(b): if bb is not object: newbases.append(bb) bases = newbases layers.reverse() return layers def bases_and_mixins(layer): return layer.__bases__ + getattr(layer, "mixins", ()) def num_expected_args(func): """Return the number of arguments that :func: expects""" if six.PY2: return len(inspect.getargspec(func)[0]) else: return len(inspect.getfullargspec(func)[0]) def call_with_args_if_expected(func, *args): """Take :func: and call it with supplied :args:, in case that signature expects any. Otherwise call the function without any arguments. """ if num_expected_args(func) > 0: func(*args) else: func() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989516.9914317 nose2-0.12.0/nose2.egg-info/0000775002342000234200000000000014264564615015341 5ustar00sirosensirosen././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/PKG-INFO0000664002342000234200000001446114264564614016443 0ustar00sirosensirosenMetadata-Version: 2.1 Name: nose2 Version: 0.12.0 Summary: unittest2 with plugins, the successor to nose Home-page: https://github.com/nose-devs/nose2 Maintainer: Stephen Rosen Maintainer-email: dev@nose2.io Keywords: unittest,testing,tests Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Operating System :: OS Independent Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Testing Provides-Extra: coverage_plugin Provides-Extra: dev License-File: AUTHORS .. image:: https://results.pre-commit.ci/badge/github/nose-devs/nose2/main.svg :target: https://results.pre-commit.ci/latest/github/nose-devs/nose2/main :alt: pre-commit.ci status .. image:: https://github.com/nose-devs/nose2/workflows/build/badge.svg?event=push :alt: build status :target: https://github.com/nose-devs/nose2/actions?query=workflow%3Abuild .. image:: https://readthedocs.org/projects/nose2/badge/ :target: https://nose2.io/ :alt: Documentation .. image:: https://img.shields.io/pypi/v/nose2.svg :target: https://pypi.org/project/nose2/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/pyversions/nose2.svg :alt: Supported Python Versions :target: https://pypi.org/project/nose2/ .. image:: https://img.shields.io/badge/Mailing%20list-discuss%40nose2.io-blue.svg :target: https://groups.google.com/a/nose2.io/forum/#!forum/discuss :alt: Join discuss@nose2.io Welcome to nose2 ================ ``nose2`` is the successor to ``nose``. It's ``unittest`` with plugins. ``nose2`` is a new project and does not support all of the features of ``nose``. See `differences`_ for a thorough rundown. nose2's purpose is to extend ``unittest`` to make testing nicer and easier to understand. nose2 vs pytest --------------- ``nose2`` may or may not be a good fit for your project. If you are new to Python testing, we encourage you to also consider `pytest`_, a popular testing framework. Quickstart ---------- Because ``nose2`` is based on unittest, you can start from the Python Standard Library's `documentation for unittest `_ and then use nose2 to add value on top of that. ``nose2`` looks for tests in Python files whose names start with ``test`` and runs every test function it discovers. Here's an example of a simple test, written in typical unittest style: .. code-block:: python # in test_simple.py import unittest class TestStrings(unittest.TestCase): def test_upper(self): self.assertEqual("spam".upper(), "SPAM") You can then run this test like so:: $ nose2 -v test_upper (test_simple.TestStrings) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK However, ``nose2`` supports more testing configuration and provides more tools than ``unittest`` on its own. For example, this test exercises just a few of ``nose2``'s features: .. code-block:: python # in test_fancy.py from nose2.tools import params @params("Sir Bedevere", "Miss Islington", "Duck") def test_is_knight(value): assert value.startswith('Sir') and then run this like so:: $ nose2 -v --pretty-assert test_fancy.test_is_knight:1 'Sir Bedevere' ... ok test_fancy.test_is_knight:2 'Miss Islington' ... FAIL test_fancy.test_is_knight:3 'Duck' ... FAIL ====================================================================== FAIL: test_fancy.test_is_knight:2 'Miss Islington' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Miss Islington' value.startswith = ====================================================================== FAIL: test_fancy.test_is_knight:3 'Duck' ---------------------------------------------------------------------- Traceback (most recent call last): File "/mnt/ebs/home/sirosen/tmp/test_fancy.py", line 6, in test_is_knight assert value.startswith('Sir') AssertionError >>> assert value.startswith('Sir') values: value = 'Duck' value.startswith = ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (failures=2) Full Docs --------- Full documentation for ``nose2`` is available at `docs.nose2.io`_ Versions and Support -------------------- Changelog and Version Scheme ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ nose2 versions are numbered `0.MAJOR.MINOR`. Minor releases contain bugfixes or smaller features. Major features or backwards incompatible changes are done in major releases. For a full description of all past versions and changes, see the `changelog`_. Python Versions ~~~~~~~~~~~~~~~ nose2 supports all currently supported Python versions. It also will continue to support Python 2 for as long as it remains feasible and a significant percentage of nose2 users are using Python 2. Contributing ------------ If you want to make contributions, please read the `contributing`_ guide. .. _differences: https://docs.nose2.io/en/latest/differences.html .. _changelog: https://docs.nose2.io/en/latest/changelog.html .. _pytest: http://pytest.readthedocs.io/en/latest/ .. _contributing: https://github.com/nose-devs/nose2/blob/main/contributing.rst .. _docs.nose2.io: https://docs.nose2.io/en/latest/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/SOURCES.txt0000664002342000234200000004124114264564614017226 0ustar00sirosensirosenAUTHORS MANIFEST.in README.rst license.txt setup.cfg setup.py tox.ini unittest.cfg docs/Makefile docs/changelog.rst docs/conf.py docs/configuration.rst docs/contents.rst.inc docs/decorators.rst docs/differences.rst docs/getting_started.rst docs/index.rst docs/params.rst docs/plugins.rst docs/such_dsl.rst docs/tools.rst docs/usage.rst docs/dev/contributing.rst docs/dev/documenting_plugins.rst docs/dev/event_reference.rst docs/dev/exceptions.rst docs/dev/hook_reference.rst docs/dev/internals.rst docs/dev/loader.rst docs/dev/main.rst docs/dev/plugin_class_reference.rst docs/dev/result.rst docs/dev/runner.rst docs/dev/session_reference.rst docs/dev/utils.rst docs/dev/writing_plugins.rst docs/plugins/attrib.rst docs/plugins/attrib_example.py docs/plugins/buffer.rst docs/plugins/collect.rst docs/plugins/coverage.rst docs/plugins/debugger.rst docs/plugins/discovery.rst docs/plugins/doctests.rst docs/plugins/dundertests.rst docs/plugins/eggdiscovery.rst docs/plugins/failfast.rst docs/plugins/functions.rst docs/plugins/generators.rst docs/plugins/junitxml.rst docs/plugins/layers.rst docs/plugins/loadtests.rst docs/plugins/logcapture.rst docs/plugins/mp.rst docs/plugins/outcomes.rst docs/plugins/parameters.rst docs/plugins/prettyassert.rst docs/plugins/printhooks.rst docs/plugins/prof.rst docs/plugins/result.rst docs/plugins/testcases.rst docs/plugins/testclasses.rst docs/plugins/testid.rst nose2/__init__.py nose2/__main__.py nose2/collector.py nose2/config.py nose2/events.py nose2/exceptions.py nose2/loader.py nose2/main.py nose2/result.py nose2/runner.py nose2/session.py nose2/sphinxext.py nose2/suite.py nose2/util.py nose2.egg-info/PKG-INFO nose2.egg-info/SOURCES.txt nose2.egg-info/dependency_links.txt nose2.egg-info/entry_points.txt nose2.egg-info/requires.txt nose2.egg-info/top_level.txt nose2/_vendor/__init__.py nose2/_vendor/six.py nose2/plugins/__init__.py nose2/plugins/_constants.py nose2/plugins/attrib.py nose2/plugins/buffer.py nose2/plugins/collect.py nose2/plugins/coverage.py nose2/plugins/debugger.py nose2/plugins/doctests.py nose2/plugins/dundertest.py nose2/plugins/failfast.py nose2/plugins/junitxml.py nose2/plugins/layers.py nose2/plugins/logcapture.py nose2/plugins/mp.py nose2/plugins/outcomes.py nose2/plugins/prettyassert.py nose2/plugins/printhooks.py nose2/plugins/prof.py nose2/plugins/result.py nose2/plugins/testid.py nose2/plugins/loader/__init__.py nose2/plugins/loader/discovery.py nose2/plugins/loader/eggdiscovery.py nose2/plugins/loader/functions.py nose2/plugins/loader/generators.py nose2/plugins/loader/loadtests.py nose2/plugins/loader/parameters.py nose2/plugins/loader/testcases.py nose2/plugins/loader/testclasses.py nose2/tests/__init__.py nose2/tests/_common.py nose2/tests/functional/__init__.py nose2/tests/functional/test_attrib_plugin.py nose2/tests/functional/test_collect_plugin.py nose2/tests/functional/test_coverage.py nose2/tests/functional/test_decorators.py nose2/tests/functional/test_discovery_loader.py nose2/tests/functional/test_doctests_plugin.py nose2/tests/functional/test_dundertest_plugin.py nose2/tests/functional/test_eggdiscovery_loader.py nose2/tests/functional/test_junitxml_plugin.py nose2/tests/functional/test_layers_hooks.py nose2/tests/functional/test_layers_plugin.py nose2/tests/functional/test_loading.py nose2/tests/functional/test_loadtests_plugin.py nose2/tests/functional/test_logcapture_plugin.py nose2/tests/functional/test_main.py nose2/tests/functional/test_mp_plugin.py nose2/tests/functional/test_prettyassert.py nose2/tests/functional/test_printhooks_plugin.py nose2/tests/functional/test_session.py nose2/tests/functional/test_subtests.py nose2/tests/functional/test_such_dsl.py nose2/tests/functional/test_util.py nose2/tests/functional/test_verbosity.py nose2/tests/functional/support/cfg/a.cfg nose2/tests/functional/support/cfg/b.cfg nose2/tests/functional/support/lib/layer_hooks_plugin.py nose2/tests/functional/support/lib/plugin_a.py nose2/tests/functional/support/scenario/class_fixtures/test_cf_testcase.py nose2/tests/functional/support/scenario/colliding_test_modules/tests/test.py nose2/tests/functional/support/scenario/colliding_test_modules/tests/more_tests/test.py nose2/tests/functional/support/scenario/coverage_config_fail_under/.coveragerc nose2/tests/functional/support/scenario/coverage_config_fail_under/test_mod.py nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/__init__.py nose2/tests/functional/support/scenario/coverage_config_fail_under/covered_lib/mod1.py nose2/tests/functional/support/scenario/coverage_config_fail_under2/.coveragerc nose2/tests/functional/support/scenario/coverage_config_fail_under2/nose2.cfg nose2/tests/functional/support/scenario/coverage_config_fail_under2/test_part_covered_mod.py nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/__init__.py nose2/tests/functional/support/scenario/coverage_config_fail_under2/part_covered_lib/mod1.py nose2/tests/functional/support/scenario/coverage_of_imports/test_import_coverage.py nose2/tests/functional/support/scenario/coverage_of_imports/lib20171102/__init__.py nose2/tests/functional/support/scenario/coverage_of_imports/lib20171102/mod1.py nose2/tests/functional/support/scenario/decorators/test_decorators.py nose2/tests/functional/support/scenario/doctests/docs.py nose2/tests/functional/support/scenario/doctests/docs.rst nose2/tests/functional/support/scenario/doctests/docs.txt nose2/tests/functional/support/scenario/doctests/doctests_pkg1/__init__.py nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.py nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.rst nose2/tests/functional/support/scenario/doctests/doctests_pkg1/docs1.txt nose2/tests/functional/support/scenario/dundertest_attribute/test.py nose2/tests/functional/support/scenario/expected_failures/expected_failures.py nose2/tests/functional/support/scenario/junitxml/chdir/test_junitxml_chdir.py nose2/tests/functional/support/scenario/junitxml/empty_properties/properties.json nose2/tests/functional/support/scenario/junitxml/empty_properties/test_junitxml_empty_properties.py nose2/tests/functional/support/scenario/junitxml/empty_properties/unittest.cfg nose2/tests/functional/support/scenario/junitxml/fail_to_write/test_junitxml_fail_to_write.py nose2/tests/functional/support/scenario/junitxml/fail_to_write/unittest.cfg nose2/tests/functional/support/scenario/junitxml/happyday/test_junitxml_happyday.py nose2/tests/functional/support/scenario/junitxml/missing_properties/test_junitxml_missing_properties.py nose2/tests/functional/support/scenario/junitxml/missing_properties/unittest.cfg nose2/tests/functional/support/scenario/junitxml/non_default_path/test_junitxml_non_default_path.py nose2/tests/functional/support/scenario/junitxml/non_default_path/unittest.cfg nose2/tests/functional/support/scenario/junitxml/skip_reason/test_junitxml_skip_reason.py nose2/tests/functional/support/scenario/junitxml/skip_reason/unittest.cfg nose2/tests/functional/support/scenario/junitxml/with_properties/test_junitxml_with_properties.py nose2/tests/functional/support/scenario/junitxml/with_properties/unittest.cfg nose2/tests/functional/support/scenario/layers/test_layers.py nose2/tests/functional/support/scenario/layers_and_attributes/test_layers_and_attributes.py nose2/tests/functional/support/scenario/layers_and_non_layers/__init__.py nose2/tests/functional/support/scenario/layers_and_non_layers/common.py nose2/tests/functional/support/scenario/layers_and_non_layers/test_layers.py nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_has_setup.py nose2/tests/functional/support/scenario/layers_and_non_layers/test_such_with_uses_decorator.py nose2/tests/functional/support/scenario/layers_hooks/test_layers_simple.py nose2/tests/functional/support/scenario/layers_hooks/test_simple_such.py nose2/tests/functional/support/scenario/layers_setups/higher_layer_setup.py nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_3layers.py nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_no_test.py nose2/tests/functional/support/scenario/layers_setups/higher_layer_testsetup_with_test.py nose2/tests/functional/support/scenario/layers_with_errors/test_layer_setup_fail.py nose2/tests/functional/support/scenario/layers_with_errors/test_layer_teardown_fail.py nose2/tests/functional/support/scenario/layers_with_errors/test_layers_with_errors.py nose2/tests/functional/support/scenario/layers_with_errors/test_such_setup_fail.py nose2/tests/functional/support/scenario/layers_with_errors/test_such_teardown_fail.py nose2/tests/functional/support/scenario/layers_with_errors/test_such_with_errors.py nose2/tests/functional/support/scenario/layers_with_inheritance/test_layers_with_inheritance.py nose2/tests/functional/support/scenario/load_tests/test_filter.py nose2/tests/functional/support/scenario/load_tests/test_simple.py nose2/tests/functional/support/scenario/load_tests_pkg/unittest.cfg nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/__init__.py nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/tests/__init__.py nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg/tests/test_find_these.py nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/__init__.py nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/tests/__init__.py nose2/tests/functional/support/scenario/load_tests_pkg/ltpkg2/tests/test_skip_these.py nose2/tests/functional/support/scenario/logging/logging_keeps_copies_of_mutable_objects.py nose2/tests/functional/support/scenario/logging_config/logging_config.py nose2/tests/functional/support/scenario/logging_config/nose2.cfg nose2/tests/functional/support/scenario/many_tests/test_gen_many_func.py nose2/tests/functional/support/scenario/many_tests_socket/nose2.cfg nose2/tests/functional/support/scenario/many_tests_socket/test_gen_many_socket_func.py nose2/tests/functional/support/scenario/module_fixtures/test_mf_func.py nose2/tests/functional/support/scenario/module_fixtures/test_mf_gen_func.py nose2/tests/functional/support/scenario/module_fixtures/test_mf_param_func.py nose2/tests/functional/support/scenario/module_fixtures/test_mf_testcase.py nose2/tests/functional/support/scenario/module_import_err/test_import_err.py nose2/tests/functional/support/scenario/module_import_err/pkg/__init__.py nose2/tests/functional/support/scenario/module_import_err/pkg/test_attribute_err.py nose2/tests/functional/support/scenario/module_import_err/pkg/test_import_err.py nose2/tests/functional/support/scenario/no_tests/a.py nose2/tests/functional/support/scenario/one_test/tests.py nose2/tests/functional/support/scenario/package_in_lib/tests.py nose2/tests/functional/support/scenario/package_in_lib/lib/pkg2/__init__.py nose2/tests/functional/support/scenario/pretty_asserts/assign_after_assert/test_assign_after_assert.py nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution/test_prettyassert_attribute_resolution.py nose2/tests/functional/support/scenario/pretty_asserts/attribute_resolution2/test_prettyassert_attribute_resolution2.py nose2/tests/functional/support/scenario/pretty_asserts/conf_on/nose2.cfg nose2/tests/functional/support/scenario/pretty_asserts/conf_on/test_conf_on.py nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/__init__.py nose2/tests/functional/support/scenario/pretty_asserts/ignore_passing/test_prettyassert_ignore_passing.py nose2/tests/functional/support/scenario/pretty_asserts/multiline_funcdef/test_multiline_funcdef.py nose2/tests/functional/support/scenario/pretty_asserts/multiline_statement/test_multiline_statement.py nose2/tests/functional/support/scenario/pretty_asserts/simple_global/test_simple_global.py nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/__init__.py nose2/tests/functional/support/scenario/pretty_asserts/unittest_assertion/test_prettyassert_unittestassertion.py nose2/tests/functional/support/scenario/slow/test_slow.py nose2/tests/functional/support/scenario/subtests/test_subtests.py nose2/tests/functional/support/scenario/such_with_params/such_with_params.py nose2/tests/functional/support/scenario/test_class_fail/test_class_fail.py nose2/tests/functional/support/scenario/test_classes/test_classes.py nose2/tests/functional/support/scenario/test_classes/test_fixtures.py nose2/tests/functional/support/scenario/test_classes_mp/test_classes_mp.py nose2/tests/functional/support/scenario/test_classes_mp/test_fixtures_mp.py nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/.coveragerc nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/test_coveragerc.py nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_coveragerc/__init__.py nose2/tests/functional/support/scenario/test_coverage_config/coveragerc/covered_lib_coveragerc/mod1.py nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/nose2.cfg nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/test_nose2cfg.py nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose2cfg/__init__.py nose2/tests/functional/support/scenario/test_coverage_config/nose2cfg/covered_lib_nose2cfg/mod1.py nose2/tests/functional/support/scenario/test_with_module/test_coverage.py nose2/tests/functional/support/scenario/test_with_module/lib/__init__.py nose2/tests/functional/support/scenario/test_with_module/lib/mod1.py nose2/tests/functional/support/scenario/tests_in_package/docs.rst nose2/tests/functional/support/scenario/tests_in_package/docs.txt nose2/tests/functional/support/scenario/tests_in_package/setup.py nose2/tests/functional/support/scenario/tests_in_package/unittest.cfg nose2/tests/functional/support/scenario/tests_in_package/pkg1/__init__.py nose2/tests/functional/support/scenario/tests_in_package/pkg1/mod1.py nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/__init__.py nose2/tests/functional/support/scenario/tests_in_package/pkg1/test/test_things.py nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/docs.rst nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/docs.txt nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/setup.py nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/unittest.cfg nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/SOURCES.txt nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/dependency_links.txt nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/EGG-INFO/top_level.txt nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/__init__.py nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/mod1.py nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/test/__init__.py nose2/tests/functional/support/scenario/tests_in_unzipped_eggs/pkgunegg-0.0.0-py2.7.egg/pkgunegg/test/test_things.py nose2/tests/functional/support/scenario/tests_in_zipped_eggs/docs.rst nose2/tests/functional/support/scenario/tests_in_zipped_eggs/docs.txt nose2/tests/functional/support/scenario/tests_in_zipped_eggs/pkgegg-0.0.0-py2.7.egg nose2/tests/functional/support/scenario/tests_in_zipped_eggs/setup.py nose2/tests/functional/support/scenario/tests_in_zipped_eggs/unittest.cfg nose2/tests/functional/support/such/output.txt nose2/tests/functional/support/such/test_regression_same_havings.py nose2/tests/functional/support/such/test_such.py nose2/tests/functional/support/such/test_such_timing.py nose2/tests/functional/support/such/test_such_without_layers.py nose2/tests/unit/__init__.py nose2/tests/unit/test_attrib_plugin.py nose2/tests/unit/test_buffer_plugin.py nose2/tests/unit/test_collect_plugin.py nose2/tests/unit/test_collector.py nose2/tests/unit/test_config.py nose2/tests/unit/test_debugger_plugin.py nose2/tests/unit/test_decorators.py nose2/tests/unit/test_doctest_plugin.py nose2/tests/unit/test_dundertest_plugin.py nose2/tests/unit/test_failfast.py nose2/tests/unit/test_functions_loader.py nose2/tests/unit/test_generators_plugin.py nose2/tests/unit/test_junitxml.py nose2/tests/unit/test_layers_plugin.py nose2/tests/unit/test_loader.py nose2/tests/unit/test_logcapture_plugin.py nose2/tests/unit/test_mp_plugin.py nose2/tests/unit/test_outcomes_plugin.py nose2/tests/unit/test_params_plugin.py nose2/tests/unit/test_plugin_api.py nose2/tests/unit/test_printhooks_plugin.py nose2/tests/unit/test_prof_plugin.py nose2/tests/unit/test_result.py nose2/tests/unit/test_session.py nose2/tests/unit/test_testcase_loader.py nose2/tests/unit/test_testclass_loader.py nose2/tests/unit/test_testid_plugin.py nose2/tests/unit/test_util.py nose2/tools/__init__.py nose2/tools/decorators.py nose2/tools/params.py nose2/tools/such.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/dependency_links.txt0000664002342000234200000000000114264564614021406 0ustar00sirosensirosen ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/entry_points.txt0000664002342000234200000000005114264564614020632 0ustar00sirosensirosen[console_scripts] nose2 = nose2:discover ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/requires.txt0000664002342000234200000000011614264564614017736 0ustar00sirosensirosen [coverage_plugin] coverage [dev] Sphinx sphinx_rtd_theme mock sphinx-issues ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989516.0 nose2-0.12.0/nose2.egg-info/top_level.txt0000664002342000234200000000000614264564614020066 0ustar00sirosensirosennose2 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1657989517.0394313 nose2-0.12.0/setup.cfg0000664002342000234200000000040114264564615014435 0ustar00sirosensirosen[bdist_wheel] universal = 1 [isort] profile = black known_third_party = six,coverage,mock [flake8] extend-ignore = E203 max-line-length = 88 per-file-ignores = nose2/tests/*.py:B011 nose2/plugins/loader/*.py:B004 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657989191.0 nose2-0.12.0/setup.py0000664002342000234200000000414214264564107014330 0ustar00sirosensirosenimport os import re from setuptools import find_packages, setup def read_version(filename): # use of " over ' will be enforced by "black" version_pattern = re.compile(r'__version__ = "([^"]*)"') with open(filename) as fp: for line in fp: m = version_pattern.match(line) if m: return m.group(1) raise Exception("could not parse version from {}".format(filename)) MAINTAINER = "Stephen Rosen" MAINTAINER_EMAIL = "dev@nose2.io" LONG_DESCRIPTION = open(os.path.join(os.path.dirname(__file__), "README.rst")).read() setup( name="nose2", version=read_version("nose2/__init__.py"), packages=find_packages(), extras_require={ "coverage_plugin": ["coverage"], "dev": [ "Sphinx", "sphinx_rtd_theme", "mock", "sphinx-issues", ], }, entry_points={"console_scripts": ["nose2 = nose2:discover"]}, # descriptive package info below description="unittest2 with plugins, the successor to nose", long_description=LONG_DESCRIPTION, maintainer=MAINTAINER, maintainer_email=MAINTAINER_EMAIL, url="https://github.com/nose-devs/nose2", classifiers=[ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", ], keywords=["unittest", "testing", "tests"], ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1657946477.0 nose2-0.12.0/tox.ini0000664002342000234200000000145214264440555014132 0ustar00sirosensirosen[tox] envlist=py{27,36,37,38,39,310,311}{,-nocov},pypy,pypy3,docs,lint [testenv] passenv = CI extras = dev deps = !nocov: coverage setenv = PYTHONPATH={toxinidir} commands = nocov: nose2 -v --pretty-assert {posargs} !nocov: coverage erase !nocov: coverage run nose2 -v --pretty-assert {posargs} !nocov: coverage report [testenv:lint] deps = pre-commit~=2.9.3 skip_install = true commands = pre-commit run --all-files [testenv:docs] extras = dev changedir = docs commands = sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html [testenv:build] deps = build twine skip_install = true whitelist_externals = rm commands_pre = rm -rf dist/ commands = python -m build twine check dist/* [testenv:publish] deps = twine skip_install = true commands = twine upload dist/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1611593607.0 nose2-0.12.0/unittest.cfg0000664002342000234200000000006514003573607015152 0ustar00sirosensirosen[log-capture] always-on = True clear-handlers = true