Merge remote-tracking branch 'upstream/master' into merge-master-into-features
This commit is contained in:
		
						commit
						802755ceed
					
				|  | @ -25,7 +25,7 @@ env: | ||||||
|     - TESTENV=py35-trial |     - TESTENV=py35-trial | ||||||
|     - TESTENV=py27-nobyte |     - TESTENV=py27-nobyte | ||||||
|     - TESTENV=doctesting |     - TESTENV=doctesting | ||||||
|     - TESTENV=py27-cxfreeze |     - TESTENV=freeze | ||||||
| 
 | 
 | ||||||
| script: tox --recreate -e $TESTENV | script: tox --recreate -e $TESTENV | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -254,6 +254,15 @@ time or change existing behaviors in order to make them less surprising/more use | ||||||
| 
 | 
 | ||||||
| * ``optparse`` backward compatibility supports float/complex types (`#457`_). | * ``optparse`` backward compatibility supports float/complex types (`#457`_). | ||||||
| 
 | 
 | ||||||
|  | * Refined logic for determining the ``rootdir``, considering only valid | ||||||
|  |   paths which fixes a number of issues: `#1594`_, `#1435`_ and `#1471`_. | ||||||
|  |   Thanks to `@blueyed`_ and `@davehunt`_ for the PR. | ||||||
|  | 
 | ||||||
|  | * Always include full assertion explanation. The previous behaviour was hiding | ||||||
|  |   sub-expressions that happened to be False, assuming this was redundant information. | ||||||
|  |   Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and | ||||||
|  |   `@tomviner`_ for PR. | ||||||
|  | 
 | ||||||
| * Renamed the pytest ``pdb`` module (plugin) into ``debugging``. | * Renamed the pytest ``pdb`` module (plugin) into ``debugging``. | ||||||
| 
 | 
 | ||||||
| * Better message in case of not using parametrized variable (see `#1539`_). | * Better message in case of not using parametrized variable (see `#1539`_). | ||||||
|  | @ -322,11 +331,13 @@ time or change existing behaviors in order to make them less surprising/more use | ||||||
| .. _#1421: https://github.com/pytest-dev/pytest/issues/1421 | .. _#1421: https://github.com/pytest-dev/pytest/issues/1421 | ||||||
| .. _#1426: https://github.com/pytest-dev/pytest/issues/1426 | .. _#1426: https://github.com/pytest-dev/pytest/issues/1426 | ||||||
| .. _#1428: https://github.com/pytest-dev/pytest/pull/1428 | .. _#1428: https://github.com/pytest-dev/pytest/pull/1428 | ||||||
|  | .. _#1435: https://github.com/pytest-dev/pytest/issues/1435 | ||||||
| .. _#1441: https://github.com/pytest-dev/pytest/pull/1441 | .. _#1441: https://github.com/pytest-dev/pytest/pull/1441 | ||||||
| .. _#1444: https://github.com/pytest-dev/pytest/pull/1444 | .. _#1444: https://github.com/pytest-dev/pytest/pull/1444 | ||||||
| .. _#1454: https://github.com/pytest-dev/pytest/pull/1454 | .. _#1454: https://github.com/pytest-dev/pytest/pull/1454 | ||||||
| .. _#1461: https://github.com/pytest-dev/pytest/pull/1461 | .. _#1461: https://github.com/pytest-dev/pytest/pull/1461 | ||||||
| .. _#1468: https://github.com/pytest-dev/pytest/pull/1468 | .. _#1468: https://github.com/pytest-dev/pytest/pull/1468 | ||||||
|  | .. _#1471: https://github.com/pytest-dev/pytest/issues/1471 | ||||||
| .. _#1474: https://github.com/pytest-dev/pytest/pull/1474 | .. _#1474: https://github.com/pytest-dev/pytest/pull/1474 | ||||||
| .. _#1479: https://github.com/pytest-dev/pytest/issues/1479 | .. _#1479: https://github.com/pytest-dev/pytest/issues/1479 | ||||||
| .. _#1502: https://github.com/pytest-dev/pytest/pull/1502 | .. _#1502: https://github.com/pytest-dev/pytest/pull/1502 | ||||||
|  | @ -341,6 +352,7 @@ time or change existing behaviors in order to make them less surprising/more use | ||||||
| .. _#1562: https://github.com/pytest-dev/pytest/issues/1562 | .. _#1562: https://github.com/pytest-dev/pytest/issues/1562 | ||||||
| .. _#1579: https://github.com/pytest-dev/pytest/issues/1579 | .. _#1579: https://github.com/pytest-dev/pytest/issues/1579 | ||||||
| .. _#1580: https://github.com/pytest-dev/pytest/pull/1580 | .. _#1580: https://github.com/pytest-dev/pytest/pull/1580 | ||||||
|  | .. _#1594: https://github.com/pytest-dev/pytest/issues/1594 | ||||||
| .. _#1597: https://github.com/pytest-dev/pytest/pull/1597 | .. _#1597: https://github.com/pytest-dev/pytest/pull/1597 | ||||||
| .. _#1605: https://github.com/pytest-dev/pytest/issues/1605 | .. _#1605: https://github.com/pytest-dev/pytest/issues/1605 | ||||||
| .. _#1616: https://github.com/pytest-dev/pytest/pull/1616 | .. _#1616: https://github.com/pytest-dev/pytest/pull/1616 | ||||||
|  | @ -367,6 +379,7 @@ time or change existing behaviors in order to make them less surprising/more use | ||||||
| .. _#717: https://github.com/pytest-dev/pytest/issues/717 | .. _#717: https://github.com/pytest-dev/pytest/issues/717 | ||||||
| .. _#925: https://github.com/pytest-dev/pytest/issues/925 | .. _#925: https://github.com/pytest-dev/pytest/issues/925 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| .. _@anntzer: https://github.com/anntzer | .. _@anntzer: https://github.com/anntzer | ||||||
| .. _@bagerard: https://github.com/bagerard | .. _@bagerard: https://github.com/bagerard | ||||||
| .. _@BeyondEvil: https://github.com/BeyondEvil | .. _@BeyondEvil: https://github.com/BeyondEvil | ||||||
|  | @ -397,8 +410,8 @@ time or change existing behaviors in order to make them less surprising/more use | ||||||
| .. _@RedBeardCode: https://github.com/RedBeardCode | .. _@RedBeardCode: https://github.com/RedBeardCode | ||||||
| .. _@sallner: https://github.com/sallner | .. _@sallner: https://github.com/sallner | ||||||
| .. _@sober7: https://github.com/sober7 | .. _@sober7: https://github.com/sober7 | ||||||
| .. _@suzaku: https://github.com/suzaku |  | ||||||
| .. _@Stranger6667: https://github.com/Stranger6667 | .. _@Stranger6667: https://github.com/Stranger6667 | ||||||
|  | .. _@suzaku: https://github.com/suzaku | ||||||
| .. _@tareqalayan: https://github.com/tareqalayan | .. _@tareqalayan: https://github.com/tareqalayan | ||||||
| .. _@taschini: https://github.com/taschini | .. _@taschini: https://github.com/taschini | ||||||
| .. _@tramwaj29: https://github.com/tramwaj29 | .. _@tramwaj29: https://github.com/tramwaj29 | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								README.rst
								
								
								
								
							
							
						
						
									
										23
									
								
								README.rst
								
								
								
								
							|  | @ -1,5 +1,5 @@ | ||||||
| .. image:: http://pytest.org/latest/_static/pytest1.png | .. image:: http://docs.pytest.org/en/latest/_static/pytest1.png | ||||||
|    :target: http://pytest.org |    :target: http://docs.pytest.org | ||||||
|    :align: center |    :align: center | ||||||
|    :alt: pytest |    :alt: pytest | ||||||
| 
 | 
 | ||||||
|  | @ -51,33 +51,34 @@ To execute it:: | ||||||
|     test_sample.py:5: AssertionError |     test_sample.py:5: AssertionError | ||||||
|     ======= 1 failed in 0.12 seconds ======== |     ======= 1 failed in 0.12 seconds ======== | ||||||
| 
 | 
 | ||||||
| Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://pytest.org/latest/getting-started.html#our-first-test-run>`_ for more examples. | 
 | ||||||
|  | Due to ``py.test``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://docs.pytest.org/en/latest/getting-started.html#our-first-test-run>`_ for more examples. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Features | Features | ||||||
| -------- | -------- | ||||||
| 
 | 
 | ||||||
| - Detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names); | - Detailed info on failing `assert statements <http://docs.pytest.org/en/latest/assert.html>`_ (no need to remember ``self.assert*`` names); | ||||||
| 
 | 
 | ||||||
| - `Auto-discovery | - `Auto-discovery | ||||||
|   <http://pytest.org/latest/goodpractices.html#python-test-discovery>`_ |   <http://docs.pytest.org/en/latest/goodpractices.html#python-test-discovery>`_ | ||||||
|   of test modules and functions; |   of test modules and functions; | ||||||
| 
 | 
 | ||||||
| - `Modular fixtures <http://pytest.org/latest/fixture.html>`_  for | - `Modular fixtures <http://docs.pytest.org/en/latest/fixture.html>`_  for | ||||||
|   managing small or parametrized long-lived test resources; |   managing small or parametrized long-lived test resources; | ||||||
| 
 | 
 | ||||||
| - Can run `unittest <http://pytest.org/latest/unittest.html>`_ (or trial), | - Can run `unittest <http://docs.pytest.org/en/latest/unittest.html>`_ (or trial), | ||||||
|   `nose <http://pytest.org/latest/nose.html>`_ test suites out of the box; |   `nose <http://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box; | ||||||
| 
 | 
 | ||||||
| - Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested); | - Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested); | ||||||
| 
 | 
 | ||||||
| - Rich plugin architecture, with over 150+ `external plugins <http://pytest.org/latest/plugins.html#installing-external-plugins-searching>`_ and thriving community; | - Rich plugin architecture, with over 150+ `external plugins <http://docs.pytest.org/en/latest/plugins.html#installing-external-plugins-searching>`_ and thriving community; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Documentation | Documentation | ||||||
| ------------- | ------------- | ||||||
| 
 | 
 | ||||||
| For full documentation, including installation, tutorials and PDF documents, please see http://pytest.org. | For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Bugs/Requests | Bugs/Requests | ||||||
|  | @ -89,7 +90,7 @@ Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issue | ||||||
| Changelog | Changelog | ||||||
| --------- | --------- | ||||||
| 
 | 
 | ||||||
| Consult the `Changelog <http://pytest.org/latest/changelog.html>`_ page for fixes and enhancements of each version. | Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`_ page for fixes and enhancements of each version. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| License | License | ||||||
|  |  | ||||||
|  | @ -1181,6 +1181,8 @@ def get_common_ancestor(args): | ||||||
|         if str(arg)[0] == "-": |         if str(arg)[0] == "-": | ||||||
|             continue |             continue | ||||||
|         p = py.path.local(arg) |         p = py.path.local(arg) | ||||||
|  |         if not p.exists(): | ||||||
|  |             continue | ||||||
|         if common_ancestor is None: |         if common_ancestor is None: | ||||||
|             common_ancestor = p |             common_ancestor = p | ||||||
|         else: |         else: | ||||||
|  | @ -1194,21 +1196,28 @@ def get_common_ancestor(args): | ||||||
|                     common_ancestor = shared |                     common_ancestor = shared | ||||||
|     if common_ancestor is None: |     if common_ancestor is None: | ||||||
|         common_ancestor = py.path.local() |         common_ancestor = py.path.local() | ||||||
|     elif not common_ancestor.isdir(): |     elif common_ancestor.isfile(): | ||||||
|         common_ancestor = common_ancestor.dirpath() |         common_ancestor = common_ancestor.dirpath() | ||||||
|     return common_ancestor |     return common_ancestor | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def get_dirs_from_args(args): | ||||||
|  |     return [d for d in (py.path.local(x) for x in args | ||||||
|  |                         if not str(x).startswith("-")) | ||||||
|  |             if d.exists()] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def determine_setup(inifile, args): | def determine_setup(inifile, args): | ||||||
|  |     dirs = get_dirs_from_args(args) | ||||||
|     if inifile: |     if inifile: | ||||||
|         iniconfig = py.iniconfig.IniConfig(inifile) |         iniconfig = py.iniconfig.IniConfig(inifile) | ||||||
|         try: |         try: | ||||||
|             inicfg = iniconfig["pytest"] |             inicfg = iniconfig["pytest"] | ||||||
|         except KeyError: |         except KeyError: | ||||||
|             inicfg = None |             inicfg = None | ||||||
|         rootdir = get_common_ancestor(args) |         rootdir = get_common_ancestor(dirs) | ||||||
|     else: |     else: | ||||||
|         ancestor = get_common_ancestor(args) |         ancestor = get_common_ancestor(dirs) | ||||||
|         rootdir, inifile, inicfg = getcfg( |         rootdir, inifile, inicfg = getcfg( | ||||||
|             [ancestor], ["pytest.ini", "tox.ini", "setup.cfg"]) |             [ancestor], ["pytest.ini", "tox.ini", "setup.cfg"]) | ||||||
|         if rootdir is None: |         if rootdir is None: | ||||||
|  | @ -1216,7 +1225,13 @@ def determine_setup(inifile, args): | ||||||
|                 if rootdir.join("setup.py").exists(): |                 if rootdir.join("setup.py").exists(): | ||||||
|                     break |                     break | ||||||
|             else: |             else: | ||||||
|                 rootdir = ancestor |                 rootdir, inifile, inicfg = getcfg( | ||||||
|  |                     dirs, ["pytest.ini", "tox.ini", "setup.cfg"]) | ||||||
|  |                 if rootdir is None: | ||||||
|  |                     rootdir = get_common_ancestor([py.path.local(), ancestor]) | ||||||
|  |                     is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep | ||||||
|  |                     if is_fs_root: | ||||||
|  |                         rootdir = ancestor | ||||||
|     return rootdir, inifile, inicfg or {} |     return rootdir, inifile, inicfg or {} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ environment: | ||||||
|   # builds timing out in AppVeyor |   # builds timing out in AppVeyor | ||||||
|   - TOXENV: "linting,py26,py27,py33,py34,py35,pypy" |   - TOXENV: "linting,py26,py27,py33,py34,py35,pypy" | ||||||
|   - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" |   - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" | ||||||
|   - TOXENV: "py27-nobyte,doctesting,py27-cxfreeze" |   - TOXENV: "py27-nobyte,doctesting,freeze" | ||||||
| 
 | 
 | ||||||
| install: | install: | ||||||
|   - echo Installed Pythons |   - echo Installed Pythons | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
| Full pytest documentation | Full pytest documentation | ||||||
| =========================== | =========================== | ||||||
| 
 | 
 | ||||||
| `Download latest version as PDF <pytest.pdf>`_ | `Download latest version as PDF <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_ | ||||||
| 
 | 
 | ||||||
| .. `Download latest version as EPUB <http://media.readthedocs.org/epub/pytest/latest/pytest.epub>`_ | .. `Download latest version as EPUB <http://media.readthedocs.org/epub/pytest/latest/pytest.epub>`_ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,25 +29,29 @@ project/testrun-specific information. | ||||||
| 
 | 
 | ||||||
| Here is the algorithm which finds the rootdir from ``args``: | Here is the algorithm which finds the rootdir from ``args``: | ||||||
| 
 | 
 | ||||||
| - determine the common ancestor directory for the specified ``args``. | - determine the common ancestor directory for the specified ``args`` that are | ||||||
|  |   recognised as paths that exist in the file system. If no such paths are | ||||||
|  |   found, the common ancestor directory is set to the current working directory. | ||||||
| 
 | 
 | ||||||
| - look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the | - look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the ancestor | ||||||
|   ancestor directory and upwards.  If one is matched, it becomes the |   directory and upwards.  If one is matched, it becomes the ini-file and its | ||||||
|   ini-file and its directory becomes the rootdir.  An existing |   directory becomes the rootdir. | ||||||
|   ``pytest.ini`` file will always be considered a match whereas |  | ||||||
|   ``tox.ini`` and ``setup.cfg`` will only match if they contain |  | ||||||
|   a ``[pytest]`` section. |  | ||||||
| 
 | 
 | ||||||
| - if no ini-file was found, look for ``setup.py`` upwards from | - if no ini-file was found, look for ``setup.py`` upwards from the common | ||||||
|   the common ancestor directory to determine the ``rootdir``. |   ancestor directory to determine the ``rootdir``. | ||||||
| 
 | 
 | ||||||
| - if no ini-file and no ``setup.py`` was found, use the already | - if no ``setup.py`` was found, look for ``pytest.ini``, ``tox.ini`` and | ||||||
|   determined common ancestor as root directory.  This allows to |   ``setup.cfg`` in each of the specified ``args`` and upwards. If one is | ||||||
|   work with pytest in structures that are not part of a package |   matched, it becomes the ini-file and its directory becomes the rootdir. | ||||||
|   and don't have any particular ini-file configuration. |  | ||||||
| 
 | 
 | ||||||
| Note that options from multiple ini-files candidates are never merged, | - if no ini-file was found, use the already determined common ancestor as root | ||||||
| the first one wins (``pytest.ini`` always wins even if it does not |   directory. This allows to work with pytest in structures that are not part of | ||||||
|  |   a package and don't have any particular ini-file configuration. | ||||||
|  | 
 | ||||||
|  | Note that an existing ``pytest.ini`` file will always be considered a match, | ||||||
|  | whereas ``tox.ini`` and ``setup.cfg`` will only match if they contain a | ||||||
|  | ``[pytest]`` section. Options from multiple ini-files candidates are never | ||||||
|  | merged - the first one wins (``pytest.ini`` always wins, even if it does not | ||||||
| contain a ``[pytest]`` section). | contain a ``[pytest]`` section). | ||||||
| 
 | 
 | ||||||
| The ``config`` object will subsequently carry these attributes: | The ``config`` object will subsequently carry these attributes: | ||||||
|  |  | ||||||
|  | @ -720,40 +720,29 @@ and run it:: | ||||||
| You'll see that the fixture finalizers could use the precise reporting | You'll see that the fixture finalizers could use the precise reporting | ||||||
| information. | information. | ||||||
| 
 | 
 | ||||||
| Integrating pytest runner and cx_freeze | Freezing pytest  | ||||||
| ----------------------------------------------------------- | --------------- | ||||||
| 
 | 
 | ||||||
| If you freeze your application using a tool like | If you freeze your application using a tool like | ||||||
| `cx_freeze <https://cx-freeze.readthedocs.io>`_ in order to distribute it | `PyInstaller <https://pyinstaller.readthedocs.io>`_ | ||||||
| to your end-users, it is a good idea to also package your test runner and run | in order to distribute it to your end-users, it is a good idea to also package | ||||||
| your tests using the frozen application. | your test runner and run your tests using the frozen application. This way packaging | ||||||
|  | errors such as dependencies not being included into the executable can be detected early | ||||||
|  | while also allowing you to send test files to users so they can run them in their | ||||||
|  | machines, which can be useful to obtain more information about a hard to reproduce bug. | ||||||
| 
 | 
 | ||||||
| This way packaging errors such as dependencies not being | Fortunately recent ``PyInstaller`` releases already have a custom hook | ||||||
| included into the executable can be detected early while also allowing you to | for pytest, but if you are using another tool to freeze executables  | ||||||
| send test files to users so they can run them in their machines, which can be | such as ``cx_freeze`` or ``py2exe``, you can use ``pytest.freeze_includes()`` | ||||||
| invaluable to obtain more information about a hard to reproduce bug. | to obtain the full list of internal pytest modules. How to configure the tools | ||||||
|  | to find the internal modules varies from tool to tool, however. | ||||||
| 
 | 
 | ||||||
| Unfortunately ``cx_freeze`` can't discover them | Instead of freezing the pytest runner as a separate executable, you can make  | ||||||
| automatically because of ``pytest``'s use of dynamic module loading, so you | your frozen program work as the pytest runner by some clever | ||||||
| must declare them explicitly by using ``pytest.freeze_includes()``:: | argument handling during program startup. This allows you to  | ||||||
|  | have a single executable, which is usually more convenient. | ||||||
| 
 | 
 | ||||||
|     # contents of setup.py | .. code-block:: python | ||||||
|     from cx_Freeze import setup, Executable |  | ||||||
|     import pytest |  | ||||||
| 
 |  | ||||||
|     setup( |  | ||||||
|         name="app_main", |  | ||||||
|         executables=[Executable("app_main.py")], |  | ||||||
|         options={"build_exe": |  | ||||||
|             { |  | ||||||
|             'includes': pytest.freeze_includes()} |  | ||||||
|             }, |  | ||||||
|         # ... other options |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
| If you don't want to ship a different executable just in order to run your tests, |  | ||||||
| you can make your program check for a certain flag and pass control |  | ||||||
| over to ``pytest`` instead. For example:: |  | ||||||
| 
 | 
 | ||||||
|     # contents of app_main.py |     # contents of app_main.py | ||||||
|     import sys |     import sys | ||||||
|  | @ -766,7 +755,8 @@ over to ``pytest`` instead. For example:: | ||||||
|         # by your argument-parsing library of choice as usual |         # by your argument-parsing library of choice as usual | ||||||
|         ... |         ... | ||||||
| 
 | 
 | ||||||
| This makes it convenient to execute your tests from within your frozen | 
 | ||||||
| application, using standard ``pytest`` command-line options:: | This allows you to execute tests using the frozen | ||||||
|  | application with standard ``pytest`` command-line options:: | ||||||
| 
 | 
 | ||||||
|     ./app_main --pytest --verbose --tb=long --junitxml=results.xml test-suite/ |     ./app_main --pytest --verbose --tb=long --junitxml=results.xml test-suite/ | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ Installation and Getting Started | ||||||
| `colorama (Windows) <http://pypi.python.org/pypi/colorama>`_, | `colorama (Windows) <http://pypi.python.org/pypi/colorama>`_, | ||||||
| `argparse (py26) <http://pypi.python.org/pypi/argparse>`_. | `argparse (py26) <http://pypi.python.org/pypi/argparse>`_. | ||||||
| 
 | 
 | ||||||
| **documentation as PDF**: `download latest <http://pytest.org/latest/pytest.pdf>`_ | **documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_ | ||||||
| 
 | 
 | ||||||
| .. _`getstarted`: | .. _`getstarted`: | ||||||
| .. _installation: | .. _installation: | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ pytest: helps you write better programs | ||||||
|  - free and open source software, distributed under the terms of the :ref:`MIT license <license>` |  - free and open source software, distributed under the terms of the :ref:`MIT license <license>` | ||||||
|  - **well tested** with more than a thousand tests against itself |  - **well tested** with more than a thousand tests against itself | ||||||
|  - **strict backward compatibility policy** for safe pytest upgrades |  - **strict backward compatibility policy** for safe pytest upgrades | ||||||
|  - :ref:`comprehensive online <toc>` and `PDF documentation <pytest.pdf>`_ |  - :ref:`comprehensive online <toc>` and `PDF documentation <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_ | ||||||
|  - many :ref:`third party plugins <extplugins>` and :ref:`builtin helpers <pytest helpers>`, |  - many :ref:`third party plugins <extplugins>` and :ref:`builtin helpers <pytest helpers>`, | ||||||
|  - used in :ref:`many small and large projects and organisations <projects>` |  - used in :ref:`many small and large projects and organisations <projects>` | ||||||
|  - comes with many :ref:`tested examples <examples>` |  - comes with many :ref:`tested examples <examples>` | ||||||
|  |  | ||||||
|  | @ -1,64 +0,0 @@ | ||||||
| """ |  | ||||||
| Installs cx_freeze from source, but first patching |  | ||||||
| setup.py as described here: |  | ||||||
| 
 |  | ||||||
| http://stackoverflow.com/questions/25107697/compiling-cx-freeze-under-ubuntu |  | ||||||
| """ |  | ||||||
| import glob |  | ||||||
| import tarfile |  | ||||||
| import os |  | ||||||
| import sys |  | ||||||
| import platform |  | ||||||
| import py |  | ||||||
| 
 |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     if 'ubuntu' not in platform.version().lower(): |  | ||||||
| 
 |  | ||||||
|         print('Not Ubuntu, installing using pip. (platform.version() is %r)' % |  | ||||||
|               platform.version()) |  | ||||||
|         res = os.system('pip install cx_freeze') |  | ||||||
|         if res != 0: |  | ||||||
|             sys.exit(res) |  | ||||||
|         sys.exit(0) |  | ||||||
| 
 |  | ||||||
|     rootdir = py.path.local.make_numbered_dir(prefix='cx_freeze') |  | ||||||
| 
 |  | ||||||
|     res = os.system('pip install --download %s --no-use-wheel ' |  | ||||||
|                     'cx_freeze' % rootdir) |  | ||||||
|     if res != 0: |  | ||||||
|         sys.exit(res) |  | ||||||
| 
 |  | ||||||
|     packages = glob.glob('%s/*.tar.gz' % rootdir) |  | ||||||
|     assert len(packages) == 1 |  | ||||||
|     tar_filename = packages[0] |  | ||||||
| 
 |  | ||||||
|     tar_file = tarfile.open(tar_filename) |  | ||||||
|     try: |  | ||||||
|         tar_file.extractall(path=str(rootdir)) |  | ||||||
|     finally: |  | ||||||
|         tar_file.close() |  | ||||||
| 
 |  | ||||||
|     basename = os.path.basename(tar_filename).replace('.tar.gz', '') |  | ||||||
|     setup_py_filename = '%s/%s/setup.py' % (rootdir, basename) |  | ||||||
|     with open(setup_py_filename) as f: |  | ||||||
|         lines = f.readlines() |  | ||||||
| 
 |  | ||||||
|     line_to_patch = 'if not vars.get("Py_ENABLE_SHARED", 0):' |  | ||||||
|     for index, line in enumerate(lines): |  | ||||||
|         if line_to_patch in line: |  | ||||||
|             indent = line[:line.index(line_to_patch)] |  | ||||||
|             lines[index] = indent + 'if True:\n' |  | ||||||
|             print('Patched line %d' % (index + 1)) |  | ||||||
|             break |  | ||||||
|     else: |  | ||||||
|         sys.exit('Could not find line in setup.py to patch!') |  | ||||||
| 
 |  | ||||||
|     with open(setup_py_filename, 'w') as f: |  | ||||||
|         f.writelines(lines) |  | ||||||
| 
 |  | ||||||
|     os.chdir('%s/%s' % (rootdir, basename)) |  | ||||||
|     res = os.system('python setup.py install') |  | ||||||
|     if res != 0: |  | ||||||
|         sys.exit(res) |  | ||||||
| 
 |  | ||||||
|     sys.exit(0) |  | ||||||
|  | @ -1,15 +0,0 @@ | ||||||
| """ |  | ||||||
| Sample setup.py script that generates an executable with pytest runner embedded. |  | ||||||
| """ |  | ||||||
| if __name__ == '__main__': |  | ||||||
|     from cx_Freeze import setup, Executable |  | ||||||
|     import pytest |  | ||||||
| 
 |  | ||||||
|     setup( |  | ||||||
|         name="runtests", |  | ||||||
|         version="0.1", |  | ||||||
|         description="example of how embedding pytest into an executable using cx_freeze", |  | ||||||
|         executables=[Executable("runtests_script.py")], |  | ||||||
|         options={"build_exe": {'includes': pytest.freeze_includes()}}, |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | build/ | ||||||
|  | dist/ | ||||||
|  | *.spec | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | """ | ||||||
|  | Generates an executable with pytest runner embedded using PyInstaller. | ||||||
|  | """ | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     import pytest | ||||||
|  |     import subprocess | ||||||
|  | 
 | ||||||
|  |     hidden = [] | ||||||
|  |     for x in pytest.freeze_includes(): | ||||||
|  |         hidden.extend(['--hidden-import', x]) | ||||||
|  |     args = ['pyinstaller', '--noconfirm'] + hidden + ['runtests_script.py'] | ||||||
|  |     subprocess.check_call(' '.join(args), shell=True) | ||||||
|  | 
 | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| """ | """ | ||||||
| This is the script that is actually frozen into an executable: simply executes | This is the script that is actually frozen into an executable: simply executes | ||||||
| pytest main(). | py.test main(). | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     import sys |     import sys | ||||||
|     import pytest |     import pytest | ||||||
|     sys.exit(pytest.main()) |     sys.exit(pytest.main()) | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| 
 | 
 | ||||||
| def test_upper(): | def test_upper(): | ||||||
|     assert 'foo'.upper() == 'FOO' |     assert 'foo'.upper() == 'FOO' | ||||||
| 
 | 
 | ||||||
| def test_lower(): | def test_lower(): | ||||||
|     assert 'FOO'.lower() == 'foo' |     assert 'FOO'.lower() == 'foo' | ||||||
|  | @ -1,15 +1,12 @@ | ||||||
| """ | """ | ||||||
| Called by tox.ini: uses the generated executable to run the tests in ./tests/ | Called by tox.ini: uses the generated executable to run the tests in ./tests/ | ||||||
| directory. | directory. | ||||||
| 
 | """ | ||||||
| .. note:: somehow calling "build/runtests_script" directly from tox doesn't | if __name__ == '__main__': | ||||||
|           seem to work (at least on Windows). |     import os | ||||||
| """ |     import sys | ||||||
| if __name__ == '__main__': | 
 | ||||||
|     import os |     executable = os.path.join(os.getcwd(), 'dist', 'runtests_script', 'runtests_script') | ||||||
|     import sys |     if sys.platform.startswith('win'): | ||||||
| 
 |         executable += '.exe' | ||||||
|     executable = os.path.join(os.getcwd(), 'build', 'runtests_script') |  | ||||||
|     if sys.platform.startswith('win'): |  | ||||||
|         executable += '.exe' |  | ||||||
|     sys.exit(os.system('%s tests' % executable)) |     sys.exit(os.system('%s tests' % executable)) | ||||||
|  | @ -493,7 +493,8 @@ class TestSession: | ||||||
| class Test_getinitialnodes: | class Test_getinitialnodes: | ||||||
|     def test_global_file(self, testdir, tmpdir): |     def test_global_file(self, testdir, tmpdir): | ||||||
|         x = tmpdir.ensure("x.py") |         x = tmpdir.ensure("x.py") | ||||||
|         config = testdir.parseconfigure(x) |         with tmpdir.as_cwd(): | ||||||
|  |             config = testdir.parseconfigure(x) | ||||||
|         col = testdir.getnode(config, x) |         col = testdir.getnode(config, x) | ||||||
|         assert isinstance(col, pytest.Module) |         assert isinstance(col, pytest.Module) | ||||||
|         assert col.name == 'x.py' |         assert col.name == 'x.py' | ||||||
|  | @ -507,7 +508,8 @@ class Test_getinitialnodes: | ||||||
|         subdir = tmpdir.join("subdir") |         subdir = tmpdir.join("subdir") | ||||||
|         x = subdir.ensure("x.py") |         x = subdir.ensure("x.py") | ||||||
|         subdir.ensure("__init__.py") |         subdir.ensure("__init__.py") | ||||||
|         config = testdir.parseconfigure(x) |         with subdir.as_cwd(): | ||||||
|  |             config = testdir.parseconfigure(x) | ||||||
|         col = testdir.getnode(config, x) |         col = testdir.getnode(config, x) | ||||||
|         assert isinstance(col, pytest.Module) |         assert isinstance(col, pytest.Module) | ||||||
|         assert col.name == 'x.py' |         assert col.name == 'x.py' | ||||||
|  |  | ||||||
|  | @ -483,7 +483,8 @@ def test_consider_args_after_options_for_rootdir_and_inifile(testdir, args): | ||||||
|             args[i] = d1 |             args[i] = d1 | ||||||
|         elif arg == 'dir2': |         elif arg == 'dir2': | ||||||
|             args[i] = d2 |             args[i] = d2 | ||||||
|     result = testdir.runpytest(*args) |     with root.as_cwd(): | ||||||
|  |         result = testdir.runpytest(*args) | ||||||
|     result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile: ']) |     result.stdout.fnmatch_lines(['*rootdir: *myroot, inifile: ']) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -566,10 +567,14 @@ class TestWarning: | ||||||
| class TestRootdir: | class TestRootdir: | ||||||
|     def test_simple_noini(self, tmpdir): |     def test_simple_noini(self, tmpdir): | ||||||
|         assert get_common_ancestor([tmpdir]) == tmpdir |         assert get_common_ancestor([tmpdir]) == tmpdir | ||||||
|         assert get_common_ancestor([tmpdir.mkdir("a"), tmpdir]) == tmpdir |         a = tmpdir.mkdir("a") | ||||||
|         assert get_common_ancestor([tmpdir, tmpdir.join("a")]) == tmpdir |         assert get_common_ancestor([a, tmpdir]) == tmpdir | ||||||
|  |         assert get_common_ancestor([tmpdir, a]) == tmpdir | ||||||
|         with tmpdir.as_cwd(): |         with tmpdir.as_cwd(): | ||||||
|             assert get_common_ancestor([]) == tmpdir |             assert get_common_ancestor([]) == tmpdir | ||||||
|  |             no_path = tmpdir.join('does-not-exist') | ||||||
|  |             assert get_common_ancestor([no_path]) == tmpdir | ||||||
|  |             assert get_common_ancestor([no_path.join('a')]) == tmpdir | ||||||
| 
 | 
 | ||||||
|     @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) |     @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) | ||||||
|     def test_with_ini(self, tmpdir, name): |     def test_with_ini(self, tmpdir, name): | ||||||
|  | @ -604,7 +609,8 @@ class TestRootdir: | ||||||
|         assert inifile is None |         assert inifile is None | ||||||
|         assert inicfg == {} |         assert inicfg == {} | ||||||
| 
 | 
 | ||||||
|     def test_nothing(self, tmpdir): |     def test_nothing(self, tmpdir, monkeypatch): | ||||||
|  |         monkeypatch.chdir(str(tmpdir)) | ||||||
|         rootdir, inifile, inicfg = determine_setup(None, [tmpdir]) |         rootdir, inifile, inicfg = determine_setup(None, [tmpdir]) | ||||||
|         assert rootdir == tmpdir |         assert rootdir == tmpdir | ||||||
|         assert inifile is None |         assert inifile is None | ||||||
|  | @ -685,3 +691,36 @@ class TestOverrideIniArgs: | ||||||
|                                      "ini2:url=/tmp/user2?a=b&d=e", |                                      "ini2:url=/tmp/user2?a=b&d=e", | ||||||
|                                      "ini3:True", |                                      "ini3:True", | ||||||
|                                      "ini4:False"]) |                                      "ini4:False"]) | ||||||
|  | 
 | ||||||
|  |     def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch): | ||||||
|  |         monkeypatch.chdir(str(tmpdir)) | ||||||
|  |         a = tmpdir.mkdir("a") | ||||||
|  |         b = tmpdir.mkdir("b") | ||||||
|  |         rootdir, inifile, inicfg = determine_setup(None, [a, b]) | ||||||
|  |         assert rootdir == tmpdir | ||||||
|  |         assert inifile is None | ||||||
|  | 
 | ||||||
|  |     def test_with_arg_outside_cwd_with_inifile(self, tmpdir): | ||||||
|  |         a = tmpdir.mkdir("a") | ||||||
|  |         b = tmpdir.mkdir("b") | ||||||
|  |         inifile = a.ensure("pytest.ini") | ||||||
|  |         rootdir, parsed_inifile, inicfg = determine_setup(None, [a, b]) | ||||||
|  |         assert rootdir == a | ||||||
|  |         assert inifile == parsed_inifile | ||||||
|  | 
 | ||||||
|  |     @pytest.mark.parametrize('dirs', ([], ['does-not-exist'], | ||||||
|  |                                       ['a/does-not-exist'])) | ||||||
|  |     def test_with_non_dir_arg(self, dirs, tmpdir): | ||||||
|  |         with tmpdir.ensure(dir=True).as_cwd(): | ||||||
|  |             rootdir, inifile, inicfg = determine_setup(None, dirs) | ||||||
|  |             assert rootdir == tmpdir | ||||||
|  |             assert inifile is None | ||||||
|  | 
 | ||||||
|  |     def test_with_existing_file_in_subdir(self, tmpdir): | ||||||
|  |         a = tmpdir.mkdir("a") | ||||||
|  |         a.ensure("exist") | ||||||
|  |         with tmpdir.as_cwd(): | ||||||
|  |             rootdir, inifile, inicfg = determine_setup(None, ['a/exist']) | ||||||
|  |             assert rootdir == tmpdir | ||||||
|  |             assert inifile is None | ||||||
|  | 
 | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								tox.ini
								
								
								
								
							
							
						
						
									
										11
									
								
								tox.ini
								
								
								
								
							|  | @ -5,7 +5,7 @@ distshare={homedir}/.tox/distshare | ||||||
| envlist= | envlist= | ||||||
|      linting,py26,py27,py33,py34,py35,pypy, |      linting,py26,py27,py33,py34,py35,pypy, | ||||||
|      {py27,py35}-{pexpect,xdist,trial}, |      {py27,py35}-{pexpect,xdist,trial}, | ||||||
|      py27-nobyte,doctesting,py27-cxfreeze |      py27-nobyte,doctesting,freeze | ||||||
| 
 | 
 | ||||||
| [testenv] | [testenv] | ||||||
| commands= pytest --lsof -rfsxX {posargs:testing} | commands= pytest --lsof -rfsxX {posargs:testing} | ||||||
|  | @ -128,12 +128,11 @@ changedir=testing | ||||||
| commands= | commands= | ||||||
|     {envpython} {envbindir}/py.test-jython -rfsxX {posargs} |     {envpython} {envbindir}/py.test-jython -rfsxX {posargs} | ||||||
| 
 | 
 | ||||||
| [testenv:py27-cxfreeze] | [testenv:freeze] | ||||||
| changedir=testing/cx_freeze | changedir=testing/freeze | ||||||
| platform=linux|darwin | deps=pyinstaller | ||||||
| commands= | commands= | ||||||
|     {envpython} install_cx_freeze.py |     {envpython} create_executable.py | ||||||
|     {envpython} runtests_setup.py build --build-exe build |  | ||||||
|     {envpython} tox_run.py |     {envpython} tox_run.py | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue