5

I am trying to write my first python module that can be easily distributed and installed on different machines (hopefully by just cloning the repository and running setup.py). The problem is that my module has a dependency on a small binary file; I am using the Selenium module as one of my dependencies and it needs a webdriver for chrome (http://chromedriver.storage.googleapis.com/index.html?path=2.22/).

What I would like to do is to include the different binaries in my repo, have python determine the system platform, choose the correct binary, add it to the system path, and then install the module as normal.

Is this easy to do? And more importantly, is this actually good practice or is there a better alternative? It seems like a very annoying thing to have to separately download the binary file and add it to the system path for each machine I want to run my module on but I would rather not go against convention.

Mark C.
  • 96
  • 1
  • 7
  • 3
    Your binaries are interpreter-specific and it's not a good idea to include any binaries in your module - rather your egg and setup.py should do the work of versions, dependencies and copying files. http://stackoverflow.com/questions/2026395/how-to-create-python-egg-file – dmitryro Jul 02 '16 at 06:15
  • Thanks for your response dmitryro! So if I'm understanding you right, my setup.py file should determine which file is needed and download it directly rather than including all the binaries in the source to begin with? I'm not really sure how to go about doing that... – Mark C. Jul 02 '16 at 06:29
  • 1
    Yes. You'll provide the list of them and their versions and they will be copied - please see https://pythonhosted.org/an_example_pypi_project/setuptools.html – dmitryro Jul 02 '16 at 06:31
  • 1
    "Downloading" files at install time is a questionable solution (a package should not rely on something to be available at the same URL in N years). If they are from a dependency then the dependency's installer should worry about them. If not, include all the files in _source_ (if you can't build them) but only leave those for a specific architecture in _binary package_ made with `bdist`. – ivan_pozdeev Jul 02 '16 at 15:18

1 Answers1

2

Based on ivan_pozdeev and dmitryro's comments, this is the solution I have come up with at the moment:

Within my project directory is a folder bin/ with the subfolders linux32/, linux64/, mac32/, win32/. Inside each of those subfolders is the appropriate executable (chromedriver / cromedriver.exe).

I have added the following lines to my setup.py script:

import platform

# Determine the correct platform for the webdriver
system = platform.system()
arch, _ = platform.architecture()
if system == 'Linux':
    if arch == '64bit':
        webdriver = 'bin/linux64/chromedriver'
    else:
        webdriver = 'bin/linux32/chromedriver'
if system == 'Windows':
    webdriver = 'bin/win32/chromedriver.exe'
if system == 'Darwin':
    webdriver = 'bin/mac32/chromedriver'

Then, with the call to the setup() function, I simply add the keyword argument

scripts=[webdriver],

After some brief testing, this seems to copy the correct executable to the system's path and installs the python module as normal.

Mark C.
  • 96
  • 1
  • 7