Skip to content

Commit ed36d62

Browse files
committed
Use PyInstaller for freeze test env
cx_freeze doesn't seem to be very well supported in Python 3.5. Using pyinstaller instead and rename environment to "freeze" which is a more generic term for freezing python code into standalone executables. Fix #1769
1 parent d911bfc commit ed36d62

File tree

13 files changed

+70
-139
lines changed

13 files changed

+70
-139
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ env:
2525
- TESTENV=py35-trial
2626
- TESTENV=py27-nobyte
2727
- TESTENV=doctesting
28-
- TESTENV=py27-cxfreeze
28+
- TESTENV=freeze
2929

3030
script: tox --recreate -e $TESTENV
3131

_pytest/genscript.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ def pytest_namespace():
100100
def freeze_includes():
101101
"""
102102
Returns a list of module names used by py.test that should be
103-
included by cx_freeze.
103+
included by cx_freeze/pyinstaller to generate a standalone
104+
pytest executable.
104105
"""
105106
result = list(_iter_all_modules(py))
106107
result += list(_iter_all_modules(_pytest))

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ environment:
1010
# builds timing out in AppVeyor
1111
- TOXENV: "linting,py26,py27,py33,py34,py35,pypy"
1212
- TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial"
13-
- TOXENV: "py27-nobyte,doctesting,py27-cxfreeze"
13+
- TOXENV: "py27-nobyte,doctesting,freeze"
1414

1515
install:
1616
- echo Installed Pythons

doc/en/example/simple.rst

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -699,36 +699,33 @@ and run it::
699699
You'll see that the fixture finalizers could use the precise reporting
700700
information.
701701

702-
Integrating pytest runner and cx_freeze
703-
-----------------------------------------------------------
702+
Integrating pytest runner and PyInstaller
703+
-----------------------------------------
704704

705705
If you freeze your application using a tool like
706-
`cx_freeze <https://cx-freeze.readthedocs.io>`_ in order to distribute it
707-
to your end-users, it is a good idea to also package your test runner and run
708-
your tests using the frozen application.
709-
710-
This way packaging errors such as dependencies not being
711-
included into the executable can be detected early while also allowing you to
712-
send test files to users so they can run them in their machines, which can be
713-
invaluable to obtain more information about a hard to reproduce bug.
714-
715-
Unfortunately ``cx_freeze`` can't discover them
706+
`PyInstaller <https://pyinstaller.readthedocs.io>`_
707+
in order to distribute it to your end-users, it is a good idea to also package
708+
your test runner and run your tests using the frozen application. This way packaging
709+
errors such as dependencies not being included into the executable can be detected early
710+
while also allowing you to send test files to users so they can run them in their
711+
machines, which can be invaluable to obtain more information about a hard to reproduce bug.
712+
713+
Unfortunately ``PyInstaller`` can't discover them
716714
automatically because of ``pytest``'s use of dynamic module loading, so you
717-
must declare them explicitly by using ``pytest.freeze_includes()``::
715+
must declare them explicitly by using ``pytest.freeze_includes()`` and an
716+
auxiliary script:
718717

719-
# contents of setup.py
720-
from cx_Freeze import setup, Executable
718+
.. code-block:: python
719+
720+
# contents of create_executable.py
721721
import pytest
722+
import subprocess
722723
723-
setup(
724-
name="app_main",
725-
executables=[Executable("app_main.py")],
726-
options={"build_exe":
727-
{
728-
'includes': pytest.freeze_includes()}
729-
},
730-
# ... other options
731-
)
724+
hidden = []
725+
for x in pytest.freeze_includes():
726+
hidden.extend(['--hidden-import', x])
727+
args = ['pyinstaller'] + hidden + ['runtests_script.py']
728+
subprocess.check_call(' '.join(args), shell=True)
732729
733730
If you don't want to ship a different executable just in order to run your tests,
734731
you can make your program check for a certain flag and pass control

testing/cx_freeze/install_cx_freeze.py

Lines changed: 0 additions & 64 deletions
This file was deleted.

testing/cx_freeze/runtests_setup.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

testing/freeze/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/
2+
dist/
3+
*.spec

testing/freeze/create_executable.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
Generates an executable with pytest runner embedded using PyInstaller.
3+
"""
4+
if __name__ == '__main__':
5+
import pytest
6+
import subprocess
7+
8+
hidden = []
9+
for x in pytest.freeze_includes():
10+
hidden.extend(['--hidden-import', x])
11+
args = ['pyinstaller', '--noconfirm'] + hidden + ['runtests_script.py']
12+
subprocess.check_call(' '.join(args), shell=True)
13+
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
"""
2-
This is the script that is actually frozen into an executable: simply executes
3-
py.test main().
4-
"""
5-
6-
if __name__ == '__main__':
7-
import sys
8-
import pytest
1+
"""
2+
This is the script that is actually frozen into an executable: simply executes
3+
py.test main().
4+
"""
5+
6+
if __name__ == '__main__':
7+
import sys
8+
import pytest
99
sys.exit(pytest.main())

0 commit comments

Comments
 (0)