Merged in nocoddemus/pytest/cx_freeze-support (pull request #189)
This commit is contained in:
		
						commit
						eae1055fb0
					
				|  | @ -1,6 +1,10 @@ | ||||||
| NEXT | NEXT | ||||||
| ----------- | ----------- | ||||||
| 
 | 
 | ||||||
|  | - Added function pytest.freeze_includes(), which makes it easy to embed | ||||||
|  |   pytest into executables using tools like cx_freeze. | ||||||
|  |   See docs for examples and rationale. Thanks Bruno Oliveira. | ||||||
|  | 
 | ||||||
| - Improve assertion rewriting cache invalidation precision. | - Improve assertion rewriting cache invalidation precision. | ||||||
| 
 | 
 | ||||||
| - fixed issue561: adapt autouse fixture example for python3. | - fixed issue561: adapt autouse fixture example for python3. | ||||||
|  |  | ||||||
|  | @ -1,6 +1,12 @@ | ||||||
| """ generate a single-file self-contained version of pytest """ | """ generate a single-file self-contained version of pytest """ | ||||||
| import py | import os | ||||||
| import sys | import sys | ||||||
|  | import pkgutil | ||||||
|  | 
 | ||||||
|  | import py | ||||||
|  | 
 | ||||||
|  | import _pytest | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def find_toplevel(name): | def find_toplevel(name): | ||||||
|  | @ -80,3 +86,42 @@ def pytest_cmdline_main(config): | ||||||
|         tw.line("generated pytest standalone script: %s" % genscript, |         tw.line("generated pytest standalone script: %s" % genscript, | ||||||
|                 bold=True) |                 bold=True) | ||||||
|         return 0 |         return 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def pytest_namespace(): | ||||||
|  |     return {'freeze_includes': freeze_includes} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def freeze_includes(): | ||||||
|  |     """ | ||||||
|  |     Returns a list of module names used by py.test that should be | ||||||
|  |     included by cx_freeze. | ||||||
|  |     """ | ||||||
|  |     result = list(_iter_all_modules(py)) | ||||||
|  |     result += list(_iter_all_modules(_pytest)) | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def _iter_all_modules(package, prefix=''): | ||||||
|  |     """ | ||||||
|  |     Iterates over the names of all modules that can be found in the given | ||||||
|  |     package, recursively. | ||||||
|  | 
 | ||||||
|  |     Example: | ||||||
|  |         _iter_all_modules(_pytest) -> | ||||||
|  |             ['_pytest.assertion.newinterpret', | ||||||
|  |              '_pytest.capture', | ||||||
|  |              '_pytest.core', | ||||||
|  |              ... | ||||||
|  |             ] | ||||||
|  |     """ | ||||||
|  |     if type(package) is not str: | ||||||
|  |         path, prefix = package.__path__[0], package.__name__ + '.' | ||||||
|  |     else: | ||||||
|  |         path = package | ||||||
|  |     for _, name, is_package in pkgutil.iter_modules([path]): | ||||||
|  |         if is_package: | ||||||
|  |             for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'): | ||||||
|  |                 yield prefix + m | ||||||
|  |         else: | ||||||
|  |             yield prefix + name | ||||||
|  |  | ||||||
|  | @ -682,33 +682,27 @@ 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 | send test files to users so they can run them in their machines, which can be | ||||||
| invaluable to obtain more information about a hard to reproduce bug. | invaluable to obtain more information about a hard to reproduce bug. | ||||||
| 
 | 
 | ||||||
| Unfortunately embedding the ``pytest`` runner into a frozen executable using | Unfortunately ``cx_freeze`` can't discover them | ||||||
| ``cx_freeze`` is not as straightforward as one would like, | automatically because of ``pytest``'s use of dynamic module loading, so you | ||||||
| because ``pytest`` makes heavy use of dynamic module loading which | must declare them explicitly by using ``pytest.freeze_includes()``:: | ||||||
| ``cx_freeze`` can't resolve by itself. |  | ||||||
| 
 |  | ||||||
| To solve this, you have to manually include ``pytest`` and ``py`` |  | ||||||
| modules by using the ``build_exe`` option in your ``setup.py`` script, like this:: |  | ||||||
| 
 | 
 | ||||||
|     # contents of setup.py |     # contents of setup.py | ||||||
|     from cx_Freeze import setup, Executable |     from cx_Freeze import setup, Executable | ||||||
|  |     import pytest | ||||||
| 
 | 
 | ||||||
|     includes = [ |  | ||||||
|         '_pytest.doctest', |  | ||||||
|         '_pytest.unittest', |  | ||||||
|         # ... lots more |  | ||||||
|     ] |  | ||||||
|     setup( |     setup( | ||||||
|         name="runtests", |         name="app_main", | ||||||
|         options={"build_exe": {'includes': includes}}, |         executables=[Executable("app_main.py")], | ||||||
|  |         options={"build_exe": | ||||||
|  |             { | ||||||
|  |             'includes': pytest.freeze_includes()} | ||||||
|  |             }, | ||||||
|         # ... other options |         # ... other options | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| (For the complete list, check out the modules under ``_pytest`` in your | If you don't want to ship a different executable just in order to run your tests, | ||||||
| site-packages). | you can make your program check for a certain flag and pass control | ||||||
| 
 | over to ``pytest`` instead. For example:: | ||||||
| With that, you can make your program check for a certain flag and pass control |  | ||||||
| over to ``pytest``:: |  | ||||||
| 
 | 
 | ||||||
|     # contents of app_main.py |     # contents of app_main.py | ||||||
|     import sys |     import sys | ||||||
|  | @ -722,7 +716,6 @@ over to ``pytest``:: | ||||||
|         ... |         ... | ||||||
| 
 | 
 | ||||||
| This makes it convenient to execute your tests from within your frozen | This makes it convenient to execute your tests from within your frozen | ||||||
| application, using standard ``py.test`` command-line:: | application, using standard ``py.test`` command-line options:: | ||||||
| 
 | 
 | ||||||
|     $ ./app_main --pytest --verbose --tb=long --junit-xml=results.xml test-suite/    /bin/sh: 1: ./app_main: not found |     $ ./app_main --pytest --verbose --tb=long --junit-xml=results.xml test-suite/ | ||||||
|     /bin/sh: 1: ./app_main: not found |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | """ | ||||||
|  | This is the script that is actually frozen into an executable: simply executes | ||||||
|  | py.test main(). | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     import sys | ||||||
|  |     import pytest | ||||||
|  |     sys.exit(pytest.main()) | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | """ | ||||||
|  | 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="exemple of how embedding py.test into an executable using cx_freeze", | ||||||
|  |         executables=[Executable("runtests_script.py")], | ||||||
|  |         options={"build_exe": {'includes': pytest.freeze_includes()}}, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Testing doctest:: | ||||||
|  | 
 | ||||||
|  |     >>> 1 + 1 | ||||||
|  |     2 | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | 
 | ||||||
|  | def test_upper(): | ||||||
|  |     assert 'foo'.upper() == 'FOO' | ||||||
|  | 
 | ||||||
|  | def test_lower(): | ||||||
|  |     assert 'FOO'.lower() == 'foo' | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | """ | ||||||
|  | Called by tox.ini: uses the generated executable to run the tests in ./tests/ | ||||||
|  | directory. | ||||||
|  | 
 | ||||||
|  | .. note:: somehow calling "build/runtests_script" directly from tox doesn't | ||||||
|  |           seem to work (at least on Windows). | ||||||
|  | """ | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     import os | ||||||
|  |     import sys | ||||||
|  | 
 | ||||||
|  |     executable = os.path.join(os.getcwd(), 'build', 'runtests_script') | ||||||
|  |     if sys.platform.startswith('win'): | ||||||
|  |         executable += '.exe' | ||||||
|  |     sys.exit(os.system('%s tests' % executable)) | ||||||
|  | @ -36,3 +36,13 @@ def test_gen(testdir, anypython, standalone): | ||||||
|     result = standalone.run(anypython, testdir, p) |     result = standalone.run(anypython, testdir, p) | ||||||
|     assert result.ret != 0 |     assert result.ret != 0 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | def test_freeze_includes(): | ||||||
|  |     """ | ||||||
|  |     Smoke test for freeze_includes(), to ensure that it works across all | ||||||
|  |     supported python versions. | ||||||
|  |     """ | ||||||
|  |     includes = pytest.freeze_includes() | ||||||
|  |     assert len(includes) > 1 | ||||||
|  |     assert '_pytest.genscript' in includes | ||||||
|  | 
 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								tox.ini
								
								
								
								
							
							
						
						
									
										10
									
								
								tox.ini
								
								
								
								
							|  | @ -1,6 +1,6 @@ | ||||||
| [tox] | [tox] | ||||||
| distshare={homedir}/.tox/distshare | distshare={homedir}/.tox/distshare | ||||||
| envlist=flakes,py26,py27,py34,pypy,py27-pexpect,py33-pexpect,py27-nobyte,py32,py33,py27-xdist,py33-xdist,py27-trial,py33-trial,doctesting | envlist=flakes,py26,py27,py34,pypy,py27-pexpect,py33-pexpect,py27-nobyte,py32,py33,py27-xdist,py33-xdist,py27-trial,py33-trial,doctesting,py27-cxfreeze | ||||||
| 
 | 
 | ||||||
| [testenv] | [testenv] | ||||||
| changedir=testing | changedir=testing | ||||||
|  | @ -123,6 +123,14 @@ commands= | ||||||
|     {envpython} {envbindir}/py.test-jython \ |     {envpython} {envbindir}/py.test-jython \ | ||||||
|         -rfsxX --junitxml={envlogdir}/junit-{envname}2.xml [] |         -rfsxX --junitxml={envlogdir}/junit-{envname}2.xml [] | ||||||
| 
 | 
 | ||||||
|  | [testenv:py27-cxfreeze] | ||||||
|  | deps=cx_freeze | ||||||
|  | changedir=testing/cx_freeze | ||||||
|  | basepython=python2.7 | ||||||
|  | commands= | ||||||
|  |     {envpython} runtests_setup.py build --build-exe build | ||||||
|  |     {envpython} tox_run.py | ||||||
|  | 
 | ||||||
| [pytest] | [pytest] | ||||||
| minversion=2.0 | minversion=2.0 | ||||||
| plugins=pytester | plugins=pytester | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue