1
0
Эх сурвалжийг харах

Merge pull request #131 from takluyver/drop-installer-mode

Drop installer mode
Thomas Kluyver 7 жил өмнө
parent
commit
25e4715f0f

+ 3 - 0
.gitignore

@@ -5,3 +5,6 @@ MANIFEST
 dist/
 doc/_build
 pynsist_pkgs/
+
+# This is a big file, so let it sit here after download
+examples/pygi_mpl_numpy/pygi.exe

+ 0 - 5
.travis.yml

@@ -2,16 +2,11 @@ language: python
 python:
   - "3.6"
   - "3.5"
-  - "3.4"
-  - "3.3"
-  - "2.7"
 # command to run tests
 script: nosetests
 # Ensure dependencies are installed
 install:
   - pip install requests requests_download jinja2 yarg win_cli_launchers testpath
-  - if [[ ${TRAVIS_PYTHON_VERSION} == '2.7' ]]; then pip install configparser pathlib2; fi
-  - if [[ ${TRAVIS_PYTHON_VERSION} == '3.3' ]]; then pip install pathlib2; fi
 
 # Enable new Travis stack, should speed up builds
 sudo: false

+ 1 - 1
README.rst

@@ -25,7 +25,7 @@ Quickstart
        icon=myapp.ico
 
        [Python]
-       version=3.4.0
+       version=3.6.3
 
        [Include]
        # Importable packages that your application requires, one per line

+ 10 - 46
doc/cfgfile.rst

@@ -39,7 +39,7 @@ Application section
 
    Ensure that this boilerplate code is at the top of your script::
 
-       #!python3.3
+       #!python3.6
        import sys
        sys.path.insert(0, 'pkgs')
 
@@ -146,8 +146,9 @@ Python section
 
 .. describe:: version
 
-  The Python version to download and bundle with your application, e.g. ``3.4.3``.
-  Python 3.3 or later and 2.7 are supported.
+  The Python version to download and bundle with your application, e.g. ``3.6.3``.
+  Python 3.5 or later are supported. For older versions of Python, use Pynsist
+  1.x.
 
 .. describe:: bitness (optional)
 
@@ -155,22 +156,9 @@ Python section
   defaults to the version you're using, so that compiled modules will match. On
   other platforms, it defaults to 32-bit.
 
-.. describe:: format (optional)
-
-  - ``installer`` includes a copy of the Python MSI installer in your application
-    and runs it at install time, setting up Python systemwide. This is the
-    default for Python up to 3.5.
-  - ``bundled`` includes an embeddable Python build, which will be installed as
-    part of your application. This is available for Python 3.5 and above, and is
-    the default for Python 3.6 and above.
-
-  .. versionchanged:: 1.9
-
-     The default switched to ``bundled`` for Python 3.6 and above.
-
 .. describe:: include_msvcrt (optional)
 
-  This option is only relevant with ``format = bundled``. The default is ``true``,
+  The default is ``true``,
   which will include an app-local copy of the Microsoft Visual C++ Runtime,
   required for Python to run. The installer will only install this if it doesn't
   detect a system installation of the runtime.
@@ -187,35 +175,11 @@ Python section
 
   .. versionadded:: 1.9
 
-.. _python_bundled:
-
-Bundled Python
-~~~~~~~~~~~~~~
-
-.. versionadded:: 1.6
-   Support for bundling Python into the application.
-
-Using ``format = bundled``, an embeddable Python build will be downloaded at
-build time and packaged along with the application. When the installer runs, it
-will create a ``Python`` subfolder inside the install directory with the files
-Python needs to run.
-
-This has the advantage of producing smaller, quicker installers (~7.5 MB for a
-trivial application), and more standalone installations. But it has a number of
-limitations:
-
-- This option is only available for Python 3.5 and above. These versions of
-  Python have dropped support for Windows XP, so your application will only work
-  on Windows Vista and newer.
-- Installing in Windows Vista to 8.1 (inclusive) may install an app-local copy
-  of the Visual C++ runtime (see above). This isn't
-  needed on Windows 10, which includes the necessary files.
-- The embeddable Python builds don't include ``tkinter``, to save space.
-  Applications with a tkinter GUI can't easily use bundled Python. Workarounds
-  may be found in the future.
-- The user cannot easily install extra Python packages in the application's
-  Python. If your application has plugins based on Python packages, this might
-  require extra thought about how and where plugins are installed.
+.. note::
+
+   Pynsist 1.x also included a ``format=`` option to select between two ways to
+   use Python: *bundled* or *installer*. Pynsist 2 only supports *bundled*
+   Python. For the installer option, use Pynsist 1.x.
 
 .. _cfg_include:
 

+ 10 - 0
doc/releasenotes.rst

@@ -1,6 +1,16 @@
 Release notes
 =============
 
+Version 2.0
+-----------
+
+Pynsist 2 only supports 'bundled' Python, and therefore only Python 3.5 and
+above. For 'installer' format Python and older Python versions, use Pynsist 1.x
+(``pip install pynsist<2``).
+
+* Pynsist installers can now install into a per-user directory, allowing them
+  to be used without admin access.
+
 Version 1.12
 ------------
 

+ 1 - 2
examples/pygi_mpl_numpy/1_download.sh

@@ -1,4 +1,3 @@
 # Download the necessary files
 # Python-GI bindings, Matplotlib (64-bit, Python 3.4)
-wget -O pygi.exe http://sourceforge.net/projects/pygobjectwin32/files/pygi-aio-3.14.0_rev21-setup.exe
-wget -O matplotlib.exe http://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.4.3/windows/matplotlib-1.4.3.win-amd64-py3.4.exe
+wget -O pygi.exe https://sourceforge.net/projects/pygobjectwin32/files/pygi-aio-3.24.1_rev1-setup_049a323fe25432b10f7e9f543b74598d4be74a39.exe

+ 2 - 8
examples/pygi_mpl_numpy/2_extract.sh

@@ -1,20 +1,14 @@
 # Extracts all dependencies and places them in the pynsist_pkgs folder
 # You might need to rename the "7z" calls to "7za" depending on your distribution
+set -e
 
 mkdir pynsist_pkgs
 
 # Unzip the bindings
-7z x numpy.whl -onumpy
-7z x matplotlib.exe -omatplotlib
 7z x pygi.exe -opygi
 
-# Copy matplotlib and numpy into the pynsist_pkgs folder and delete the folders
-cp -r matplotlib/PLATLIB/matplotlib pynsist_pkgs
-rm -r matplotlib
-cp -r numpy/numpy pynsist_pkgs
-rm -r numpy
-
 # Copy the PyGI packages into the pynsist_pkgs folder
+# TODO: Update to Python 3.6
 7z x pygi/binding/py3.4-64/py3.4-64.7z -obindings
 cp -r bindings/* pynsist_pkgs
 rm -r bindings

+ 9 - 9
examples/pygi_mpl_numpy/README.rst

@@ -1,4 +1,9 @@
-This example shows how to package a program that uses the PyGI-bindings of Gtk (or PyGObject). Python 3.4.3 64-bit will be used together with 64-bit dependencies.
+**This example does not currently work**: Pynsist 2 requires Python 3.5 or above,
+but PyGI is only available for Python 3.4 at most (as of October 2017).
+Hopefully it will be possible again in the future.
+
+This example shows how to package a program that uses the PyGI-bindings of Gtk (or PyGObject).
+Python 3.4.3 64-bit will be used together with 64-bit dependencies.
 
 The example program consists of a window with a matplotlib-plot and a button that triggers the window to close.
 
@@ -15,19 +20,14 @@ Debian-style distributions using:
 Building the program
 --------------------
 
-A shell script can be used to download some of the dependencies:
+A shell script can be used to download the PyGI Windows installer:
 
 ::
 
     sh 1_download.sh
 
-The numpy 64-bit wheel can be downloaded here (numpy‑1.9.2+mkl‑cp34‑none‑win_amd64.whl):
-
-http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy
-
-Rename it to numpy.whl before starting the second script.
-
-The next script will copy all the dependencies into the ``pynsist_pkgs`` folder.
+The next script will extract the necessary GTK components into the
+``pynsist_pkgs`` folder.
 
 ::
 

+ 8 - 7
examples/pygi_mpl_numpy/installer.cfg

@@ -5,17 +5,18 @@ entry_point=pygi_test:main
 extra_preamble=gnome_preamble.py
 
 [Python]
-version=3.4.3
+version=3.6.3
 bitness=64
 
 [Include]
+pypi_wheels = numpy==1.13.3
+    matplotlib==2.1.0
+    six==1.11.0
+    python-dateutil==2.6.1
+    pyparsing==2.2.0
+
 packages=gi
     cairo
-    dbus
+    #dbus  # needed?
     gnome
     pygtkcompat
-    numpy
-    matplotlib
-    six
-    dateutil
-    pyparsing

+ 0 - 21
examples/pygtk/README.rst

@@ -1,21 +0,0 @@
-This is an example of building a Windows installer for a pygtk application. This
-is a bit more complex than the other examples, because the GTK runtime needs to
-be set up. This needs two things:
-
-1. The pieces of the GTK runtime and its Python bindings. The script ``grab_files.sh``
-   downloads these, unpacks them, trims out unnecessary pieces, and places them
-   where pynsist will find them.
-2. The ``PATH`` environment variable must be modified before we try to import
-   the Python GTK bindings. This is done by the ``extra_preamble`` field in
-   ``installer.cfg``.
-
-I referred to the following sources of information to work this out:
-
-Bundling pygtk using py2exe:
-http://faq.pygtk.org/index.py?file=faq21.005.htp&req=show
-https://web.archive.org/web/20060208162511/http://www.anti-particle.com/py2exe-0.5.shtml
-
-Installing pygtk & deps: http://www.pygtk.org/downloads.html
-(inc links for pygtk, pycairo and pygobject installers)
-
-GTK bundles for Windows: http://www.gtk.org/download/win32.php

+ 0 - 40
examples/pygtk/grab_files.sh

@@ -1,40 +0,0 @@
-# Download the necessary files
-wget -O gtkbundle.zip http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip
-wget -O pygobject.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pygobject/2.28/pygobject-2.28.3.win32-py2.7.exe
-wget -O pycairo.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.8/pycairo-1.8.10.win32-py2.7.exe
-wget -O pygtk.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.24/pygtk-2.24.0.win32-py2.7.exe
-
-# GTK runtime
-mkdir gtkbundle
-unzip -d gtkbundle gtkbundle.zip
-cd gtkbundle
-rm -r src man include share/doc share/man share/gtk-doc share/gtk-2.0/demo bin/gtk-demo.exe etc/bash_completion.d
-cd ..
-
-# Python bindings
-mkdir pygobject
-unzip -d pygobject pygobject.exe
-mkdir pycairo
-unzip -d pycairo pycairo.exe
-mkdir pygtk
-unzip -d pygtk pygtk.exe
-
-# Reassemble into pynsist_pkgs
-echo -n "Assembling GTK files into pynsist_pkgs... "
-rm -r pynsist_pkgs
-mkdir pynsist_pkgs
-mv gtkbundle pynsist_pkgs/gtk
-
-cp -r pygobject/PLATLIB/* pynsist_pkgs
-rm -r pygobject
-
-cp -r pycairo/PLATLIB/* pynsist_pkgs
-cp -r pycairo/DATA/lib/site-packages/cairo/* pynsist_pkgs/cairo
-rm -r pycairo
-
-cp -r pygtk/PLATLIB/* pynsist_pkgs
-rm -r pygtk
-
-rm -r pynsist_pkgs/gtk-2.0/tests
-
-echo "done"

+ 0 - 2
examples/pygtk/gtk_preamble.py

@@ -1,2 +0,0 @@
-os.environ['PATH'] += os.pathsep + os.path.join(pkgdir, 'gtk/lib') + \
-    os.pathsep + os.path.join(pkgdir, 'gtk/bin')

+ 0 - 84
examples/pygtk/helloworld.py

@@ -1,84 +0,0 @@
-#!/usr/bin/env python
-
-# This example was adapted from http://pygtk.org/pygtk2tutorial/examples/helloworld.py
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-
-class HelloWorld:
-    def msgbox(self, text):
-        "Display a simple message box"
-        md = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT,
-                          gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, text)
-        md.run()
-
-    # This is a callback function. The data arguments are ignored
-    # in this example. More on callbacks below.
-    def hello(self, widget, data=None):
-        self.msgbox("Hello, world!")
-
-    def delete_event(self, widget, event, data=None):
-        # If you return FALSE in the "delete_event" signal handler,
-        # GTK will emit the "destroy" signal. Returning TRUE means
-        # you don't want the window to be destroyed.
-        # This is useful for popping up 'are you sure you want to quit?'
-        # type dialogs.
-        self.msgbox("delete event occurred")
-
-        # Change FALSE to TRUE and the main window will not be destroyed
-        # with a "delete_event".
-        return False
-
-    def destroy(self, widget, data=None):
-        gtk.main_quit()
-
-    def __init__(self):
-        # create a new window
-        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
-    
-        # When the window is given the "delete_event" signal (this is given
-        # by the window manager, usually by the "close" option, or on the
-        # titlebar), we ask it to call the delete_event () function
-        # as defined above. The data passed to the callback
-        # function is NULL and is ignored in the callback function.
-        self.window.connect("delete_event", self.delete_event)
-    
-        # Here we connect the "destroy" event to a signal handler.  
-        # This event occurs when we call gtk_widget_destroy() on the window,
-        # or if we return FALSE in the "delete_event" callback.
-        self.window.connect("destroy", self.destroy)
-    
-        # Sets the border width of the window.
-        self.window.set_border_width(10)
-    
-        # Creates a new button with the label "Hello World".
-        self.button = gtk.Button("Hello World")
-    
-        # When the button receives the "clicked" signal, it will call the
-        # function hello() passing it None as its argument.  The hello()
-        # function is defined above.
-        self.button.connect("clicked", self.hello, None)
-    
-        # This will cause the window to be destroyed by calling
-        # gtk_widget_destroy(window) when "clicked".  Again, the destroy
-        # signal could come from here, or the window manager.
-        self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
-    
-        # This packs the button into the window (a GTK container).
-        self.window.add(self.button)
-    
-        # The final step is to display this newly created widget.
-        self.button.show()
-    
-        # and the window
-        self.window.show()
-
-    def main(self):
-        # All PyGTK applications must have a gtk.main(). Control ends here
-        # and waits for an event to occur (like a key press or mouse event).
-        gtk.main()
-
-def main():
-    hello = HelloWorld()
-    hello.main()

+ 0 - 11
examples/pygtk/installer.cfg

@@ -1,11 +0,0 @@
-[Application]
-name=Hello World (PyGTK)
-version=1.0
-entry_point=helloworld:main
-extra_preamble=gtk_preamble.py
-
-[Python]
-version=2.7.7
-
-[Include]
-packages=pygtk

+ 0 - 101
examples/pygtk_mpl_numpy/README.rst

@@ -1,101 +0,0 @@
-This is an example of building a Windows installer for a pygtk application that
-includes matplotlib and numpy.
-
-Requirements
-------------
-
-This example needs 7zip in order to work. You can install it for example on
-Debian-style distributions using:
-
-::
-
-    sudo apt-get install p7zip
-
-Running the Example
--------------------
-
-In order to build the example application on Linux you have to run the following
-two commands in the example directory:
-
-::
-
-    sh grab_files.sh
-    python -m nsist installer.cfg
-
-The first line will download the dependencies, extract them and copy them into
-the :code:`pynsist_pkgs`-directory. It will then remove the temporary directories
-used for extraction, but will leave the downloaded archives intact in the
-example directory.
-
-Matplotlib
-----------
-
-The example downloads the 32-bit Python 2.7 bindings of Matplotlib 1.4.3
-(matplotlib-1.4.3.win32-py2.7.exe).
-
-In the :code:`installer.cfg` Matplotlib additionally requires the six, dateutil
-and pyparsing packages:
-
-::
-
-    [Include]
-    packages=pygtk
-        numpy
-        matplotlib
-        six
-        dateutil
-        pyparsing
-
-Numpy
------
-
-The example downloads the 32-bit Python 2.7 bindings of Numpy 1.9.2
-(numpy-1.9.2-win32-superpack-python2.7.exe).
-
-PyGTK
------
-
-PyGTK is a bit more complex than the other examples, because the GTK runtime
-needs to be set up. This needs two things:
-
-1. The pieces of the GTK runtime and its Python bindings. The script ``grab_files.sh``
-   downloads these, unpacks them, trims out unnecessary pieces, and places them
-   where pynsist will find them.
-2. The ``PATH`` environment variable must be modified before we try to import
-   the Python GTK bindings. This is done by the ``extra_preamble`` field in
-   ``installer.cfg``.
-
-I referred to the following sources of information to work this out:
-
-Bundling pygtk using py2exe:
-http://faq.pygtk.org/index.py?file=faq21.005.htp&req=show
-https://web.archive.org/web/20060208162511/http://www.anti-particle.com/py2exe-0.5.shtml
-
-Installing pygtk & deps: http://www.pygtk.org/downloads.html
-(inc links for pygtk, pycairo and pygobject installers)
-
-GTK bundles for Windows: http://www.gtk.org/download/win32.php
-
-Installer.cfg
--------------
-
-The example is customized for 32-bit and Python 2.7. This is expressed in the
-:code:`installer.cfg`-file like this:
-
-::
-
-    version=2.7.9
-    bitness=32
-
-The include section requires pygtk, numpy and matplotlib. In order to satisfy the
-requirements of Matplotlib the packages six, dateutil, and pyparsing are needed.
-
-::
-
-    [Include]
-    packages=pygtk
-        numpy
-        matplotlib
-        six
-        dateutil
-        pyparsing

+ 0 - 56
examples/pygtk_mpl_numpy/grab_files.sh

@@ -1,56 +0,0 @@
-# Download the necessary files
-wget -O gtkbundle.zip http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-bundle_2.24.10-20120208_win32.zip
-wget -O pygobject.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pygobject/2.28/pygobject-2.28.3.win32-py2.7.exe
-wget -O pycairo.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.8/pycairo-1.8.10.win32-py2.7.exe
-wget -O pygtk.exe http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.24/pygtk-2.24.0.win32-py2.7.exe
-wget -O numpy.exe http://downloads.sourceforge.net/project/numpy/NumPy/1.9.2/numpy-1.9.2-win32-superpack-python2.7.exe
-wget -O matplotlib.exe https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.4.3/windows/matplotlib-1.4.3.win32-py2.7.exe
-
-# GTK runtime
-mkdir gtkbundle
-unzip -d gtkbundle gtkbundle.zip
-cd gtkbundle
-rm -r src man include share/doc share/man share/gtk-doc share/gtk-2.0/demo bin/gtk-demo.exe etc/bash_completion.d
-cd ..
-
-# Python bindings
-mkdir pygobject
-unzip -d pygobject pygobject.exe
-mkdir pycairo
-unzip -d pycairo pycairo.exe
-mkdir pygtk
-unzip -d pygtk pygtk.exe
-mkdir numpy
-unzip -d numpy numpy.exe
-mkdir matplotlib
-unzip -d matplotlib matplotlib.exe
-
-# Reassemble into pynsist_pkgs
-echo -n "Assembling GTK files into pynsist_pkgs... "
-rm -r pynsist_pkgs
-mkdir pynsist_pkgs
-mv gtkbundle pynsist_pkgs/gtk
-
-cp -r pygobject/PLATLIB/* pynsist_pkgs
-rm -r pygobject
-
-cp -r pycairo/PLATLIB/* pynsist_pkgs
-cp -r pycairo/DATA/lib/site-packages/cairo/* pynsist_pkgs/cairo
-rm -r pycairo
-
-cp -r pygtk/PLATLIB/* pynsist_pkgs
-rm -r pygtk
-
-cp -r matplotlib/PLATLIB/* pynsist_pkgs
-rm -r matplotlib
-
-#Unzip numpy into base directory
-7z e numpy.exe
-#Unzip the NoSSE package into the numpy directory
-7z x numpy-1.9.2-nosse.exe -onumpy
-cp -r numpy/PLATLIB/* pynsist_pkgs
-rm -r numpy
-
-rm -r pynsist_pkgs/gtk-2.0/tests
-
-echo "done"

+ 0 - 2
examples/pygtk_mpl_numpy/gtk_preamble.py

@@ -1,2 +0,0 @@
-os.environ['PATH'] += os.pathsep + os.path.join(pkgdir, 'gtk/lib') + \
-    os.pathsep + os.path.join(pkgdir, 'gtk/bin')

+ 0 - 42
examples/pygtk_mpl_numpy/hellomatplotlib.py

@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-
-# This example was adapted from http://matplotlib.org/examples/user_interfaces/embedding_in_gtk.html, and http://pygtk.org/pygtk2tutorial/examples/helloworld.py
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-from matplotlib.figure import Figure
-from numpy import arange, sin, pi
-from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
-
-class HelloMatplotlib:
-    def __init__(self):
-        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
-        self.window.connect("delete_event", self.delete_event)
-        self.window.connect("destroy", self.destroy)
-        self.window.set_size_request(400, 400)
-        self.window.set_border_width(10)
-
-        f = Figure(figsize=(5,4), dpi=100)
-        a = f.add_subplot(111)
-        t = arange(0.0,3.0,0.01)
-        s = sin(2*pi*t)
-        a.plot(t,s)
-
-        self.canvas = FigureCanvas(f)
-        self.canvas.show()
-        self.window.add(self.canvas)
-        self.window.show()
-
-    def delete_event(self, widget, event, data=None):
-        gtk.main_quit()
-
-    def destroy(self, widget, data=None):
-        gtk.main_quit()
-
-    def main(self):
-        gtk.main()
-
-def main():
-    hello = HelloMatplotlib()
-    hello.main()

+ 0 - 17
examples/pygtk_mpl_numpy/installer.cfg

@@ -1,17 +0,0 @@
-[Application]
-name=Hello Matplotlib (PyGTK)
-version=1.0
-entry_point=hellomatplotlib:main
-extra_preamble=gtk_preamble.py
-
-[Python]
-version=2.7.9
-bitness=32
-
-[Include]
-packages=pygtk
-    numpy
-    matplotlib
-    six
-    dateutil
-    pyparsing

+ 0 - 14
examples/pyqt4/README.md

@@ -1,14 +0,0 @@
-This is an example that uses PyQt4 binary packages.
-
-To make the installer on a non-Windows system, first run fetch_pyqt_windows.sh.
-This will download a PyQt Windows installer from Sourceforge, unpack the files
-from it, and copy the necessary ones into pynsist_pkgs where pynsist will
-pick them up.
-
-If you want to use PyQt in a '[bundled format](https://pynsist.readthedocs.io/en/latest/cfgfile.html#bundled-python)'
-installer with Python 3.5 or later, you'll need to ensure the file `msvcp140.dll`
-is included. If you have a Visual Studio installation, you can find it in there;
-otherwise download the [Visual C++ Redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145).
-On Linux, you can extract the DLL from the exe using `cabextract` (after extracting
-files from the exe, run it again on a file called `a10`). Place `msvcp140.dll`
-inside the `PyQt4` folder, next to files like `QtCore4.dll`.

+ 0 - 31
examples/pyqt4/fetch_pyqt_windows.sh

@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-# Download and the PyQt4 Windows installer and unpack files from it into
-# pynsist_pkgs
-
-set -e
-
-PY_VERSION=3.4
-PYQT_VERSION=4.11.3
-QT_VERSION=4.8.6
-BITNESS=32
-
-INSTALLER_FILE=PyQt4-${PYQT_VERSION}-gpl-Py${PY_VERSION}-Qt${QT_VERSION}-x${BITNESS}.exe
-URL=http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-${PYQT_VERSION}/${INSTALLER_FILE}
-wget -O "$INSTALLER_FILE" "$URL"
-
-rm -rf pyqt4-windows
-mkdir pyqt4-windows
-7z x -opyqt4-windows "$INSTALLER_FILE"
-
-rm -rf pynsist_pkgs
-mkdir pynsist_pkgs
-
-echo "Rearranging files into pynsist_pkgs..."
-mv 'pyqt4-windows/Lib/site-packages'/* pynsist_pkgs/
-rm pynsist_pkgs/PyQt4/assistant.exe pynsist_pkgs/PyQt4/designer.exe
-mv 'pyqt4-windows/$_OUTDIR/'*.pyd pynsist_pkgs/PyQt4/
-# These may not be necessary:
-mv 'pyqt4-windows/$_OUTDIR/qsci/' 'pyqt4-windows/$_OUTDIR/sip/' pynsist_pkgs/PyQt4/
-
-rm -r pyqt4-windows
-echo "Done"

+ 0 - 13
examples/pyqt4/installer.cfg

@@ -1,13 +0,0 @@
-[Application]
-name=List App (PyQt)
-version=1.0
-entry_point=listapp:main
-
-[Python]
-version=3.3.5
-
-[Include]
-packages=listapp
-    PyQt4
-    sip
-files = README.md

+ 0 - 33
examples/pyqt4/listapp/__init__.py

@@ -1,33 +0,0 @@
-import sys
-from PyQt4 import QtGui
-
-from .main import Ui_MainWindow
-
-class Main(QtGui.QMainWindow):
-    def __init__(self):
-        super().__init__()
-        self.ui = Ui_MainWindow()
-        self.ui.setupUi(self)
-        
-        self.ui.add_button.clicked.connect(self.add_item)
-
-    def get_radio_option(self):
-        if self.ui.radio_1.isChecked():
-            return 'Thing 1'
-        elif self.ui.radio_2.isChecked():
-            return 'Thing 2'
-        elif self.ui.radio_3.isChecked():
-            return 'Thing 3'
-        elif self.ui.radio_4.isChecked():
-            return 'Last thing'
-        return 'No thing'
-        
-    def add_item(self):
-        text = self.get_radio_option()
-        QtGui.QListWidgetItem(text, self.ui.listWidget)        
-
-def main():
-    app = QtGui.QApplication(sys.argv)
-    window = Main()
-    window.show()
-    sys.exit(app.exec_())

+ 0 - 95
examples/pyqt4/listapp/main.py

@@ -1,95 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'buttonapp/main.ui'
-#
-# Created: Wed Apr  2 16:57:10 2014
-#      by: PyQt4 UI code generator 4.10.3
-#
-# WARNING! All changes made in this file will be lost!
-
-from PyQt4 import QtCore, QtGui
-
-try:
-    _fromUtf8 = QtCore.QString.fromUtf8
-except AttributeError:
-    def _fromUtf8(s):
-        return s
-
-try:
-    _encoding = QtGui.QApplication.UnicodeUTF8
-    def _translate(context, text, disambig):
-        return QtGui.QApplication.translate(context, text, disambig, _encoding)
-except AttributeError:
-    def _translate(context, text, disambig):
-        return QtGui.QApplication.translate(context, text, disambig)
-
-class Ui_MainWindow(object):
-    def setupUi(self, MainWindow):
-        MainWindow.setObjectName(_fromUtf8("MainWindow"))
-        MainWindow.resize(393, 606)
-        self.centralwidget = QtGui.QWidget(MainWindow)
-        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
-        self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
-        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
-        self.groupBox = QtGui.QGroupBox(self.centralwidget)
-        self.groupBox.setObjectName(_fromUtf8("groupBox"))
-        self.verticalLayout = QtGui.QVBoxLayout(self.groupBox)
-        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
-        self.radio_1 = QtGui.QRadioButton(self.groupBox)
-        self.radio_1.setObjectName(_fromUtf8("radio_1"))
-        self.verticalLayout.addWidget(self.radio_1)
-        self.radio_2 = QtGui.QRadioButton(self.groupBox)
-        self.radio_2.setObjectName(_fromUtf8("radio_2"))
-        self.verticalLayout.addWidget(self.radio_2)
-        self.radio_3 = QtGui.QRadioButton(self.groupBox)
-        self.radio_3.setObjectName(_fromUtf8("radio_3"))
-        self.verticalLayout.addWidget(self.radio_3)
-        self.radio_4 = QtGui.QRadioButton(self.groupBox)
-        self.radio_4.setObjectName(_fromUtf8("radio_4"))
-        self.verticalLayout.addWidget(self.radio_4)
-        self.add_button = QtGui.QPushButton(self.groupBox)
-        self.add_button.setObjectName(_fromUtf8("add_button"))
-        self.verticalLayout.addWidget(self.add_button)
-        spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
-        self.verticalLayout.addItem(spacerItem)
-        self.horizontalLayout.addWidget(self.groupBox)
-        self.listWidget = QtGui.QListWidget(self.centralwidget)
-        self.listWidget.setObjectName(_fromUtf8("listWidget"))
-        self.horizontalLayout.addWidget(self.listWidget)
-        MainWindow.setCentralWidget(self.centralwidget)
-        self.menubar = QtGui.QMenuBar(MainWindow)
-        self.menubar.setGeometry(QtCore.QRect(0, 0, 393, 24))
-        self.menubar.setObjectName(_fromUtf8("menubar"))
-        self.menuFile = QtGui.QMenu(self.menubar)
-        self.menuFile.setObjectName(_fromUtf8("menuFile"))
-        MainWindow.setMenuBar(self.menubar)
-        self.statusbar = QtGui.QStatusBar(MainWindow)
-        self.statusbar.setObjectName(_fromUtf8("statusbar"))
-        MainWindow.setStatusBar(self.statusbar)
-        self.actionNew = QtGui.QAction(MainWindow)
-        self.actionNew.setObjectName(_fromUtf8("actionNew"))
-        self.actionOpen = QtGui.QAction(MainWindow)
-        self.actionOpen.setObjectName(_fromUtf8("actionOpen"))
-        self.actionSave = QtGui.QAction(MainWindow)
-        self.actionSave.setObjectName(_fromUtf8("actionSave"))
-        self.menuFile.addAction(self.actionNew)
-        self.menuFile.addAction(self.actionOpen)
-        self.menuFile.addAction(self.actionSave)
-        self.menubar.addAction(self.menuFile.menuAction())
-
-        self.retranslateUi(MainWindow)
-        QtCore.QMetaObject.connectSlotsByName(MainWindow)
-
-    def retranslateUi(self, MainWindow):
-        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
-        self.groupBox.setTitle(_translate("MainWindow", "Click things", None))
-        self.radio_1.setText(_translate("MainWindow", "Thing 1", None))
-        self.radio_2.setText(_translate("MainWindow", "Thing 2", None))
-        self.radio_3.setText(_translate("MainWindow", "Thing 3", None))
-        self.radio_4.setText(_translate("MainWindow", "Last thing", None))
-        self.add_button.setText(_translate("MainWindow", "Add to list", None))
-        self.menuFile.setTitle(_translate("MainWindow", "File", None))
-        self.actionNew.setText(_translate("MainWindow", "New", None))
-        self.actionOpen.setText(_translate("MainWindow", "Open", None))
-        self.actionSave.setText(_translate("MainWindow", "Save", None))
-

+ 0 - 118
examples/pyqt4/listapp/main.ui

@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>393</width>
-    <height>606</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>MainWindow</string>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <layout class="QHBoxLayout" name="horizontalLayout">
-    <item>
-     <widget class="QGroupBox" name="groupBox">
-      <property name="title">
-       <string>Click things</string>
-      </property>
-      <layout class="QVBoxLayout" name="verticalLayout">
-       <item>
-        <widget class="QRadioButton" name="radio_1">
-         <property name="text">
-          <string>Thing 1</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QRadioButton" name="radio_2">
-         <property name="text">
-          <string>Thing 2</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QRadioButton" name="radio_3">
-         <property name="text">
-          <string>Thing 3</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QRadioButton" name="radio_4">
-         <property name="text">
-          <string>Last thing</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="add_button">
-         <property name="text">
-          <string>Add to list</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <spacer name="verticalSpacer">
-         <property name="orientation">
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>20</width>
-           <height>40</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
-     </widget>
-    </item>
-    <item>
-     <widget class="QListWidget" name="listWidget"/>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>393</width>
-     <height>24</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuFile">
-    <property name="title">
-     <string>File</string>
-    </property>
-    <addaction name="actionNew"/>
-    <addaction name="actionOpen"/>
-    <addaction name="actionSave"/>
-   </widget>
-   <addaction name="menuFile"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
-  <action name="actionNew">
-   <property name="text">
-    <string>New</string>
-   </property>
-  </action>
-  <action name="actionOpen">
-   <property name="text">
-    <string>Open</string>
-   </property>
-  </action>
-  <action name="actionSave">
-   <property name="text">
-    <string>Save</string>
-   </property>
-  </action>
- </widget>
- <resources/>
- <connections/>
-</ui>

+ 0 - 13
examples/tkinter/exampleapp.py

@@ -1,13 +0,0 @@
-from tkinter import *
-
-def main():
-    root = Tk()
-    root.title("Python Example App")
-    t = Text(root)
-    t.insert(END, "Type stuff here.")
-    t.pack()
-
-    w = Label(root, text="Hello, world!")
-    w.pack()
-
-    root.mainloop()

+ 0 - 7
examples/tkinter/installer.cfg

@@ -1,7 +0,0 @@
-[Application]
-name=My App
-version=1.0
-entry_point=exampleapp:main
-
-[Include]
-packages=exampleapp

+ 1 - 3
flit.ini

@@ -5,19 +5,17 @@ author-email = thomas@kluyver.me.uk
 dist-name = pynsist
 home-page = https://pynsist.readthedocs.io/en/latest/
 description-file = README.rst
+requires-python = >=3.5
 requires = requests
     requests_download
     jinja2
     yarg
     win_cli_launchers
-    configparser; python_version == '2.7'
-    pathlib2; python_version == '2.7' or python_version == '3.3'
 dev-requires = testpath
 classifiers = License :: OSI Approved :: MIT License
     Intended Audience :: Developers
     Environment :: Win32 (MS Windows)
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 2.7
     Topic :: Software Development
     Topic :: System :: Installation/Setup
     Topic :: System :: Software Distribution

+ 28 - 88
nsist/__init__.py

@@ -6,10 +6,7 @@ import logging
 import ntpath
 import operator
 import os
-try:
-    from pathlib import Path
-except ImportError:
-    from pathlib2 import Path  # Backport
+from pathlib import Path
 import re
 import shutil
 from subprocess import call
@@ -17,13 +14,8 @@ import sys
 import fnmatch
 import zipfile
 
-PY2 = sys.version_info[0] == 2
-
 if os.name == 'nt':
-    if PY2:
-        import _winreg as winreg
-    else:
-        import winreg
+    import winreg
 else:
     winreg = None
 
@@ -34,13 +26,13 @@ from .nsiswriter import NSISFileWriter
 from .pypi import fetch_pypi_wheels
 from .util import download, text_types, get_cache_dir
 
-__version__ = '1.12'
+__version__ = '2.0'
 
 pjoin = os.path.join
 logger = logging.getLogger(__name__)
 
 _PKGDIR = os.path.abspath(os.path.dirname(__file__))
-DEFAULT_PY_VERSION = '2.7.13' if PY2 else '3.6.1'
+DEFAULT_PY_VERSION = '3.6.3'
 DEFAULT_BUILD_DIR = pjoin('build', 'nsis')
 DEFAULT_ICON = pjoin(_PKGDIR, 'glossyorb.ico')
 if os.name == 'nt' and sys.maxsize == (2**63)-1:
@@ -88,10 +80,10 @@ class InstallerBuilder(object):
     :param list exclude: Paths of files to exclude that would otherwise be included
     :param str py_version: Full version of Python to bundle
     :param int py_bitness: Bitness of bundled Python (32 or 64)
-    :param str py_format: 'installer' or 'bundled'. Default 'bundled' for Python
-            >= 3.6, 'installer' for older versions.
+    :param str py_format: (deprecated) 'bundled'. Use Pynsist 1.x for
+            'installer' option.
     :param bool inc_msvcrt: True to include the Microsoft C runtime with 'bundled'
-            Python. Ignored when py_format='installer'.
+            Python.
     :param str build_dir: Directory to run the build in
     :param str installer_name: Filename of the installer to produce
     :param str nsi_template: Path to a template NSI file to use
@@ -99,7 +91,7 @@ class InstallerBuilder(object):
     def __init__(self, appname, version, shortcuts, publisher=None,
                 icon=DEFAULT_ICON, packages=None, extra_files=None,
                 py_version=DEFAULT_PY_VERSION, py_bitness=DEFAULT_BITNESS,
-                py_format=None, inc_msvcrt=True, build_dir=DEFAULT_BUILD_DIR,
+                py_format='bundled', inc_msvcrt=True, build_dir=DEFAULT_BUILD_DIR,
                 installer_name=None, nsi_template=None,
                 exclude=None, pypi_wheel_reqs=None, commands=None):
         self.appname = appname
@@ -119,6 +111,9 @@ class InstallerBuilder(object):
             if not os.environ.get('PYNSIST_PY_PRERELEASE'):
                 raise InputError('py_version', py_version,
                                  "a full Python version like '3.4.0'")
+        if self.py_version_tuple < (3, 5):
+            raise InputError('py_version', py_version,
+                             "Python >= 3.5.0 (use Pynsist 1.x for older Python.")
         self.py_bitness = py_bitness
         if py_bitness not in {32, 64}:
             raise InputError('py_bitness', py_bitness, "32 or 64")
@@ -126,18 +121,11 @@ class InstallerBuilder(object):
         if self.py_bitness == 32:
             self.py_qualifier += '-32'
 
-        if py_format is not None:
-            self.py_format = py_format
-        elif self.py_version_tuple >= (3, 6):
-            self.py_format = 'bundled'
-        else:
-            self.py_format = 'installer'
-        if self.py_version_tuple >= (3, 5):
-            if self.py_format not in {'installer', 'bundled'}:
-                raise InputError('py_format', self.py_format, "installer or bundled")
-        else:
-            if self.py_format != 'installer':
-                raise InputError('py_format', self.py_format, "installer (for Python < 3.5)")
+        if py_format == 'installer':
+            raise InputError('py_format', py_format, "'bundled' (use Pynsist 1.x for 'installer')")
+        elif py_format != 'bundled':
+            raise InputError('py_format', py_format, "'bundled'")
+
         self.inc_msvcrt = inc_msvcrt
 
         # Build details
@@ -145,15 +133,10 @@ class InstallerBuilder(object):
         self.installer_name = installer_name or self.make_installer_name()
         self.nsi_template = nsi_template
         if self.nsi_template is None:
-            if self.py_format == 'bundled':
-                if self.inc_msvcrt:
-                    self.nsi_template = 'pyapp_msvcrt.nsi'
-                else:
-                    self.nsi_template = 'pyapp.nsi'
-            elif self.py_version_tuple < (3, 3):
-                self.nsi_template = 'pyapp_w_pylauncher.nsi'
+            if self.inc_msvcrt:
+                self.nsi_template = 'pyapp_msvcrt.nsi'
             else:
-                self.nsi_template = 'pyapp_installpy.nsi'
+                self.nsi_template = 'pyapp.nsi'
 
         self.nsi_file = pjoin(self.build_dir, 'installer.nsi')
 
@@ -180,39 +163,19 @@ class InstallerBuilder(object):
     def _python_download_url_filename(self):
         version = self.py_version
         bitness = self.py_bitness
-        if self.py_version_tuple >= (3, 5):
-            if self.py_format == 'bundled':
-                filename = 'python-{}-embed-{}.zip'.format(version,
-                                           'amd64' if bitness==64 else 'win32')
-            else:
-                filename = 'python-{}{}.exe'.format(version,
-                                            '-amd64' if bitness==64 else '')
-        else:
-            filename = 'python-{0}{1}.msi'.format(version,
-                                            '.amd64' if bitness==64 else '')
+        filename = 'python-{}-embed-{}.zip'.format(version,
+                                   'amd64' if bitness==64 else 'win32')
 
         version_minus_prerelease = re.sub(r'(a|b|rc)\d+$', '', self.py_version)
         return 'https://www.python.org/ftp/python/{0}/{1}'.format(
                 version_minus_prerelease, filename), filename
 
-    def fetch_python(self):
-        """Fetch the MSI for the specified version of Python.
+    def fetch_python_embeddable(self):
+        """Fetch the embeddable Windows build for the specified Python version
 
-        It will be placed in the build directory.
+        It will be unpacked into the build directory.
         """
         url, filename = self._python_download_url_filename()
-
-        cache_file = get_cache_dir(ensure_existence=True) / filename
-        if not cache_file.is_file():
-            logger.info('Downloading Python installer...')
-            logger.info('Getting %s', url)
-            download(url, cache_file)
-
-        logger.info('Copying Python installer to build directory')
-        shutil.copy2(str(cache_file), self.build_dir)
-
-    def fetch_python_embeddable(self):
-        url, filename = self._python_download_url_filename()
         cache_file = get_cache_dir(ensure_existence=True) / filename
         if not cache_file.is_file():
             logger.info('Downloading embeddable Python build...')
@@ -246,21 +209,6 @@ class InstallerBuilder(object):
 
         shutil.copytree(src, dst)
 
-    def fetch_pylauncher(self):
-        """Fetch the MSI for PyLauncher (required for Python2.x).
-
-        It will be placed in the build directory.
-        """
-        arch_tag = '.amd64' if (self.py_bitness == 64) else ''
-        url = ("https://bitbucket.org/vinay.sajip/pylauncher/downloads/"
-               "launchwin{0}.msi".format(arch_tag))
-        target = pjoin(self.build_dir, 'launchwin{0}.msi'.format(arch_tag))
-        if os.path.isfile(target):
-            logger.info('PyLauncher MSI already in build directory.')
-            return
-        logger.info('Downloading PyLauncher MSI...')
-        download(url, target)
-
     SCRIPT_TEMPLATE = """#!python{qualifier}
 import sys, os
 scriptdir, script = os.path.split(__file__)
@@ -340,10 +288,7 @@ if __name__ == '__main__':
                 else:
                     shutil.copy2(sc['script'], self.build_dir)
 
-                if self.py_format == 'bundled':
-                    target = '$INSTDIR\Python\python{}.exe'
-                else:
-                    target = 'py{}'
+                target = '$INSTDIR\Python\python{}.exe'
                 sc['target'] = target.format('' if sc['console'] else 'w')
                 sc['parameters'] = '"%s"' % ntpath.join('$INSTDIR', sc['script'])
                 files.add(os.path.basename(sc['script']))
@@ -477,14 +422,9 @@ if __name__ == '__main__':
             if e.errno != errno.EEXIST:
                 raise e
 
-        if self.py_format == 'bundled':
-            self.fetch_python_embeddable()
-            if self.inc_msvcrt:
-                self.prepare_msvcrt()
-        else:
-            self.fetch_python()
-            if self.py_version < '3.3':
-                self.fetch_pylauncher()
+        self.fetch_python_embeddable()
+        if self.inc_msvcrt:
+            self.prepare_msvcrt()
 
         self.prepare_shortcuts()
 

+ 0 - 1
nsist/configreader.py

@@ -223,7 +223,6 @@ def get_installer_builder_args(config):
     args['extra_files'] = read_extra_files(config)
     args['py_version'] = config.get('Python', 'version', fallback=DEFAULT_PY_VERSION)
     args['py_bitness'] = config.getint('Python', 'bitness', fallback=DEFAULT_BITNESS)
-    args['py_format'] = config.get('Python', 'format', fallback=None)
     args['inc_msvcrt'] = config.getboolean('Python', 'include_msvcrt', fallback=True)
     args['build_dir'] = config.get('Build', 'directory', fallback=DEFAULT_BUILD_DIR)
     args['installer_name'] = config.get('Build', 'installer_name', fallback=None)

+ 1 - 5
nsist/nsiswriter.py

@@ -56,13 +56,9 @@ class NSISFileWriter(object):
             'single_shortcut': len(installerbuilder.shortcuts) == 1,
             'pynsist_pkg_dir': _PKGDIR,
             'has_commands': len(installerbuilder.commands) > 0,
+            'python': '"$INSTDIR\\Python\\python"'
         }
 
-        if installerbuilder.py_format == 'bundled':
-            self.namespace['python'] = '"$INSTDIR\\Python\\python"'
-        else:
-            self.namespace['python'] = 'py -{}'.format(installerbuilder.py_qualifier)
-
     def write(self, target):
         """Fill out the template and write the result to 'target'.
         

+ 0 - 16
nsist/pyapp.nsi

@@ -12,7 +12,6 @@
  
 SetCompressor lzma
 
-[% if ib.py_format == 'bundled' %]
 !define MULTIUSER_EXECUTIONLEVEL Highest
 !define MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
 !define MULTIUSER_MUI
@@ -22,7 +21,6 @@ SetCompressor lzma
 !define MULTIUSER_INSTALLMODE_FUNCTION correct_prog_files
 [% endif %]
 !include MultiUser.nsh
-[% endif %]
 
 [% block modernui %]
 ; Modern UI installer stuff 
@@ -33,9 +31,7 @@ SetCompressor lzma
 ; UI pages
 [% block ui_pages %]
 !insertmacro MUI_PAGE_WELCOME
-[% if ib.py_format == 'bundled' %]
 !insertmacro MULTIUSER_PAGE_INSTALLMODE
-[% endif %]
 !insertmacro MUI_PAGE_DIRECTORY
 !insertmacro MUI_PAGE_INSTFILES
 !insertmacro MUI_PAGE_FINISH
@@ -45,9 +41,6 @@ SetCompressor lzma
 
 Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
 OutFile "${INSTALLER_NAME}"
-[% if ib.py_format != 'bundled' %]
-InstallDir "$PROGRAMFILES${BITNESS}\${PRODUCT_NAME}"
-[% endif %]
 ShowInstDetails show
 
 Section -SETTINGS
@@ -65,13 +58,11 @@ Section "!${PRODUCT_NAME}" sec_app
   File /r "pkgs\*.*"
   SetOutPath "$INSTDIR"
 
-  [% if ib.py_format == 'bundled' %]
   ; Marker file for per-user install
   StrCmp $MultiUser.InstallMode CurrentUser 0 +3
     FileOpen $0 "$INSTDIR\${USER_INSTALL_MARKER}" w
     FileClose $0
     SetFileAttributes "$INSTDIR\${USER_INSTALL_MARKER}" HIDDEN
-  [% endif %]
 
   [% block install_files %]
   ; Install files
@@ -207,7 +198,6 @@ Function .onMouseOverSection
     [% endblock mouseover_messages %]
 FunctionEnd
 
-[% if ib.py_format == 'bundled' %]
 Function .onInit
   !insertmacro MULTIUSER_INIT
 FunctionEnd
@@ -224,9 +214,3 @@ Function correct_prog_files
     StrCpy $INSTDIR "$PROGRAMFILES64\${MULTIUSER_INSTALLMODE_INSTDIR}"
 FunctionEnd
 [% endif %]
-
-[% else %]
-Function .onInit
-  SetShellVarContext all
-FunctionEnd
-[% endif %]

+ 0 - 38
nsist/pyapp_installpy.nsi

@@ -1,38 +0,0 @@
-[% extends "pyapp.nsi" %]
-
-[% block ui_pages %]
-[# We only need to add COMPONENTS, but they have to be in order #]
-!insertmacro MUI_PAGE_WELCOME
-!insertmacro MUI_PAGE_COMPONENTS
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_INSTFILES
-!insertmacro MUI_PAGE_FINISH
-[% endblock ui_pages %]
-
-[% block sections %]
-Section "Python ${PY_VERSION}" sec_py
-
-  DetailPrint "Installing Python ${PY_MAJOR_VERSION}, ${BITNESS} bit"
-  [% if ib.py_version_tuple >= (3, 5) %]
-    [% set filename = 'python-' ~ ib.py_version ~ ('-amd64' if ib.py_bitness==64 else '') ~ '.exe' %]
-    File "[[filename]]"
-    ExecWait '"$INSTDIR\[[filename]]" /passive Include_test=0 InstallAllUsers=1'
-  [% else %]
-    [% set filename = 'python-' ~ ib.py_version ~ ('.amd64' if ib.py_bitness==64 else '') ~ '.msi' %]
-    File "[[filename]]"
-    ExecWait 'msiexec /i "$INSTDIR\[[filename]]" \
-            /qb ALLUSERS=1 TARGETDIR="$COMMONFILES${BITNESS}\Python\${PY_MAJOR_VERSION}"'
-  [% endif %]
-  Delete "$INSTDIR\[[filename]]"
-SectionEnd
-
-[[ super() ]]
-[% endblock sections %]
-
-[% block mouseover_messages %]
-    StrCmp $0 ${sec_py} 0 +2
-      SendMessage $R0 ${WM_SETTEXT} 0 "STR:The Python interpreter. \
-            This is required for ${PRODUCT_NAME} to run."
-
-[[ super() ]]
-[% endblock mouseover_messages %]

+ 0 - 25
nsist/pyapp_w_pylauncher.nsi

@@ -1,25 +0,0 @@
-[% extends "pyapp_installpy.nsi" %]
-[# For Python 2, add the py/pyw Windows launcher. Python 3 includes it already. #]
-
-[% block sections %]
-Section "PyLauncher" sec_pylauncher
-    ; Check for the existence of the pyw command, skip installing if it exists
-    nsExec::Exec 'where pyw'
-    Pop $0
-    IntCmp $0 0 SkipPylauncher
-    ; Extract the py/pyw launcher msi and run it.
-    File "launchwin${ARCH_TAG}.msi"
-    ExecWait 'msiexec /i "$INSTDIR\launchwin${ARCH_TAG}.msi" /qb ALLUSERS=1'
-    Delete "$INSTDIR\launchwin${ARCH_TAG}.msi"
-    SkipPylauncher:
-SectionEnd
-
-[[ super() ]]
-[% endblock %]
-
-[% block mouseover_messages %]
-[[ super() ]]
-    StrCmp $0 ${sec_app} "" +2
-      SendMessage $R0 ${WM_SETTEXT} 0 "STR:The Python launcher. \
-          This is required for ${PRODUCT_NAME} to run."
-[% endblock %]

+ 0 - 1
nsist/tests/test_configuration_validator.py

@@ -43,7 +43,6 @@ def test_valid_config_with_values_starting_on_new_line():
 
     assert args['py_version'] == '3.6.0'
     assert args['py_bitness'] == 64
-    assert args['py_format'] == 'bundled'
     assert args['inc_msvcrt'] == True
 
     assert args['build_dir'] == 'build/'