[GIS] Creating executables from Python using OSGeo4W shell

osgeo4wpy2exepythonqgis

I've been trying to create an executable from my Python script and using the OSGeo4W.bat shell. I tried py2exe but it returns an access denied error.

Previously I've written executables using py2exe and it worked beautifully but that was using the Python27 application located c:/Python27 (v 2.7.10). Using the CMD shell, after writing:

cd C:\Python27
python

The following version is presented: "Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32"

I had trouble using this Python version when I tried to import gdal. See enter link description here. So, in this script I'm writing, I was required to use OSGeo4W shell, located C:\Program Files\QGIS Lyon.

I've been trying to install PyInstaller but I keep running into issues with importing setuptools when I run the following commands in the OSGeo4W shell:

cd C:\Program Files\QGIS Lyon\pyinstaller-3.1.1
python setup.py

I even downloaded "setuptools-20.3.1.zip (md5)" from this website and tried running the script in the C:\Program Files\QGIS Lyon and C:\Program Files\QGIS Lyon\pyinstaller-3.1.1 directories.

Could someone please walk me through installing and using an executable creating application using the OSGeo4W.bat shell and python scripts?

The modules I'm trying to import in my Python script are the following:

import sys
import os
import math
try:
    from osgeo import osr
    from osgeo import gdal
except ImportError:
    import osr
    import gdal

When I run python in OSGeo4W.bat the version number is "Python 2.7.5 (Default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win32"


An update:

In OsGeo4w.bat shell ran as admin, I ran the following commands:

SET "PATH="C:\Program Files\QGIS Lyon\share\gdal";%PATH%"
SET "GDAL_DATA=C:\Program Files\QGIS Lyon\share\gdal\gdal-data"
SET "GDAL_DRIVER_PATH=C:\Program Files\QGIS Lyon\share\gdal\gdalplugins"
SET "PROJ_LIB=C:\Program Files\QGIS Lyon\share\gdal\projlib"

I changed the start of my python script to look like this:

import sys
import os
import math
path = os.environ['PATH']
pgdal= 'C:\\Program Files\\QGIS Lyon\\share\\gdal;'
os.environ['GDAL_DATA']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\gdal-data'
os.environ['GDAL_DRIVER_PATH']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\gdalplugins'
os.environ['PROJ_LIB']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\projlib'
os.environ['PATH'] = "%s;%s" % (pgdal, path)
try:
    from osgeo import osr
    from osgeo import gdal
except ImportError:
    import osr
    import gdal

I installed pip using The OsGeo4w External Python Packages installer (pip) instructions using the OsGeo4w.bat shell (ran as admin).

Then I used the shell to run:

pip install pyinstaller

command, which successfully installed PyInstaller.

Then in the shell I ran:

cd C:\Python27\PyPack

then to attempt to create my executable:

pyinstaller b.py

The output was an addition of 3 items in C:\Python27\PyPack:

> 1) C:\Python27\PyPack\build\b\b.exe.manifest - (this is the only file)
> 2) C:\Python27\PyPack\dist - (empty) 
> 3) C:\Python27\PyPack\b.spec

The output in the shell is:

C:\Python27\PyPack>pyinstaller b.py
922 INFO: PyInstaller: 3.1.1
922 INFO: Python: 2.7.5
922 INFO: Platform: Windows-8-6.2.9200
922 INFO: wrote C:\Python27\PyPack\b.spec
922 INFO: UPX is not available.
937 INFO: Extending PYTHONPATH with paths
['C:\\Python27\\PyPack', 'C:\\Python27\\PyPack']
937 INFO: checking Analysis
937 INFO: Building Analysis because out00-Analysis.toc is non existent
937 INFO: Initializing module dependency graph...
953 INFO: Initializing module graph hooks...
1031 INFO: running Analysis out00-Analysis.toc
1094 INFO: Adding Microsoft.VC90.CRT to dependent assemblies of final executable
  required by c:\progra~1\qgisly~1\bin\python.exe
1219 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.21022.8_none_18f8a87fd1919cd9.manifest
1250 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.1_none_3da38fdebd0e6822.manifest
1266 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_acd0e4ffe1daef0a.manifest
1281 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_acd388d7e1d8689f.manifest
1297 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_acd40623e1d81331.manifest
1406 INFO: Searching for assembly amd64_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.30729.9177_none ...
1406 INFO: Found manifest C:\WINDOWS\WinSxS\Manifests\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_08e695a3a83b6ce3.manifest
1422 INFO: Searching for file msvcr90.dll
1422 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_08e695a3a83b6ce3\msvcr90.dll
1422 INFO: Searching for file msvcp90.dll
1422 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_08e695a3a83b6ce3\msvcp90.dll
1422 INFO: Searching for file msvcm90.dll
1437 INFO: Found file C:\WINDOWS\WinSxS\amd64_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_08e695a3a83b6ce3\msvcm90.dll
1531 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.21022.8_none_18f8a87fd1919cd9.manifest
1531 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.1_none_3da38fdebd0e6822.manifest
1531 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_acd0e4ffe1daef0a.manifest
1531 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_acd388d7e1d8689f.manifest
1547 INFO: Found C:\WINDOWS\WinSxS\Manifests\amd64_policy.9.0.microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.9177_none_acd40623e1d81331.manifest
1547 INFO: Adding redirect Microsoft.VC90.CRT version (9, 0, 21022, 8) -> (9, 0, 30729, 9177)
1706 INFO: Analyzing C:\Python27\PyPack\b.py
5581 INFO: Processing pre-find module path hook   distutils
6066 INFO: Processing pre-safe import module hook   _xmlplus
12082 INFO: Processing pre-find module path hook   site
12098 INFO: site: retargeting to fake-dir 'C:\\PROGRA~1\\QGISLY~1\\apps\\Python27\\lib\\site-packages\\PyInstaller\\fake-modules'
12176 INFO: Processing pre-safe import module hook   win32com
15004 INFO: Looking for import hooks ...
15004 INFO: Processing hook   hook-distutils.py
Traceback (most recent call last):
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\Scripts\pyinstaller.exe\__main__.py", line 9, in <module>
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\__main__.py", line 90, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\__main__.py", line 46, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\build_main.py", line 755, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\build_main.py", line 701, in build
    exec(text, spec_namespace)
  File "<string>", line 16, in <module>
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\build_main.py", line 212, in __init__
    self.__postinit__()
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\datastruct.py", line 183, in __postinit__
    self.assemble()
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\build_main.py", line 434, in assemble
    imphook_object.update_dependencies(self.graph)
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\imphook.py", line 309, in update_dependencies
    self._process_datas(mod_graph)
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\imphook.py", line 285, in _process_datas
    self.datas.update(set(format_binaries_and_datas(self._module.datas)))
  File "C:\PROGRA~1\QGISLY~1\apps\Python27\lib\site-packages\PyInstaller\building\utils.py", line 426, in format_binaries_and_datas
    src_root_path_or_glob))
PyInstaller.compat.FileNotFoundError: Path or glob "C:\PROGRA~1\QGISLY~1\apps\Python27\Include\pyconfig.h" not found or matches no files.

C:\Python27\PyPack>

I noticed that there is no "pyconfig" item searchable anywhere in C:\Program Files\QGIS Lyon. There is a "C:\Program Files\QGIS Lyon\include" with a stack of .h files but none titled pyconfig.h.

Here is the contents of b.spec:

# -*- mode: python -*-
block_cipher = None


a = Analysis(['b.py'],
             pathex=['C:\\Python27\\PyPack'],
             binaries=None,
             datas=None,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='b',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='b')

So, after looking at the PyInstaller guidance outlined on the Using PyInstaller site, which states that:

PyInstaller analyzes myscript.py and:

  • Writes myscript.spec in the same folder as the script.

  • Creates a folder build in the same folder as the script if it does not exist.

  • Writes some log files and working files in the build folder.

  • Creates a folder dist in the same folder as the script if it does not exist.

  • Writes the myscript executable folder in the dist folder.

it appears that the last step:

  • Writes the myscript executable folder in the dist folder.

is not working.

Would anyone know why?

I found this: Potential solution, which refers to this code for changing hook-six.moves.py but I didn't want to jump to do this as I am not sure about it.

Best Answer

I have created a portable python environnement base on ms4w where I can run gdal tools and use osgeo module in python. The main problem to solve is only to set environnement variables.

I use 2 solutions

  1. for the CLI when you run OSGeo4W.bat you can

SET "PATH="C:\Program Files\QGIS Lyon\share\gdal";%PATH%" SET "GDAL_DATA=C:\Program Files\QGIS Lyon\share\gdal\gdal-data" SET "GDAL_DRIVER_PATH=C:\Program Files\QGIS Lyon\share\gdal\gdalplugins" SET "PROJ_LIB=C:\Program Files\QGIS Lyon\share\gdal\projlib"

  1. for python before importing osr and gdal

path = os.environ['PATH'] pgdal= 'C:\\Program Files\\QGIS Lyon\\share\\gdal;' os.environ['GDAL_DATA']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\gdal-data' os.environ['GDAL_DRIVER_PATH']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\gdalplugins' os.environ['PROJ_LIB']='C:\\Program Files\\QGIS Lyon\\share\\gdal\\projlib' os.environ['PATH'] = "%s;%s" % (pgdal, path)

Related Question