Passing arguments in python setup.py install_requires list - python

I have used pip to install PIL. It requires two additional arguments while installation. So the command for installation looks something like this.
pip install PIL --allow-external PIL --allow-unverified PIL
I need to add the PIL package in setup.py file. Adding PIL in the install_requires list do install PIL but it doesn't work, as I need to install PIL with the additional arguments.
So how can I add the PIL to the install_requires list with additional arguments ?

Currently, there is no way to specify extra arguments in install_requires in setup.py. But, I solved my problem of installing dependencies with global-options by sub-classing setuptools.command.install class and overriding its run() method, like following code -
from setuptools import setup
from setuptools.command.install import install
from subprocess import call
class CustomInstall(install):
def run(self):
install.run(self)
call(['pip', 'install', 'PIL', '--allow-external', 'PIL', '--allow-unverified', 'PIL'])
setup( ...
cmdclass={
'install': CustomInstall,
},
)

Just replace PIL with Pillow (in your install_requires). It's a fork of PIL with bugfixes, py3k support and proper hosting. You don't need to change your code.

Related

Install by default, "optional" dependencies in Python (setuptools)

Is there a way to specify optional dependencies for a Python package that should be installed by default from pip but for which an install should not be considered a failure if they cannot be installed?
I know that I can specify install_requires so that the packages will be installed for the 90% of users using OSes that can easily install certain optional dependencies, and I also know I can specify extra_require to specify that users can declare they want a full install to get these features, but I haven't found a way to make a default pip install try to install the packages but not complain if they cannot be installed.
(The particular package I'd like to update the setuptools and setup.py for is called music21 for which 95% of the tools can be run without matplotlib, IPython, scipy, pygame, some obscure audio tools etc. but the package gains extra abilities and speed if these packages are installed, and I'd prefer to let people have these abilities by default but not report errors if they cannot be installed)
Not a perfect solution by any means, but you could setup a post-install script to try to install the packages, something like this:
from distutils.core import setup
from distutils import debug
from setuptools.command.install import install
class PostInstallExtrasInstaller(install):
extras_install_by_default = ['matplotlib', 'nothing']
#classmethod
def pip_main(cls, *args, **kwargs):
def pip_main(*args, **kwargs):
raise Exception('No pip module found')
try:
from pip import main as pip_main
except ImportError:
from pip._internal import main as pip_main
ret = pip_main(*args, **kwargs)
if ret:
raise Exception(f'Exitcode {ret}')
return ret
def run(self):
for extra in self.extras_install_by_default:
try:
self.pip_main(['install', extra])
except Exception as E:
print(f'Optional package {extra} not installed: {E}')
else:
print(f"Optional package {extra} installed")
return install.run(self)
setup(
name='python-package-ignore-extra-dep-failures',
version='0.1dev',
packages=['somewhat',],
license='Creative Commons Attribution-Noncommercial-Share Alike license',
install_requires=['requests',],
extras_require={
'extras': PostInstallExtrasInstaller.extras_install_by_default,
},
cmdclass={
'install': PostInstallExtrasInstaller,
},
)
The simplest way to do this is by adding a custom install command that simply shells out to pip to install the "optional" packages. In your setup.py:
import sys
import subprocess
from setuptools import setup
from setuptools.command.install import install
class MyInstall(install):
def run(self):
subprocess.call([sys.executable, "-m", "pip", "install", "whatever"])
install.run(self)
setup(
...
cmdclass={
'install': MyInstall,
},
)
Like hoefling said above, this will only work if you publish a source distribution (.tar.gz or .zip). It will not work if you publish your package as a built distribution (.whl).
This might be what you are looking for. It's appears to be a built in feature of setup tools that allows you to declare "optional dependencies".
https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies
Ex
setup(
name="Project-A",
...
extras_require={
'PDF': ["ReportLab>=1.2", "RXP"],
'reST': ["docutils>=0.3"],
}
)

setup.py with cv2 dependency installed via conda (conda-forge opencv)

I'm trying to collect python code in a package gnn_pylib and install it in my conda environment. My package will require opencv, which has been installed in my conda environment via:
conda install -c conda-forge opencv
I can run cv2 functions correctly, and I can call functions in the packages using cv2 functions successfully:
import gnn_pylib
gnn_pylib.show()
But when i try to install the package running pip install -e .
from the gnn_pylib directory I get the following error:
Collecting cv2 (from gnn-pylib==0.1)
Could not find a version that satisfies the requirement cv2 (from gnn-pylib==0.1) (from versions: )
No matching distribution found for cv2 (from gnn-pylib==0.1)
Is there something i am missing? should I some way inform pip but my conda opencv?
The package has the following structure:
gnn_pylib/
gnn_pylib/
__init__.py
show.py
setup.py
__init__.py is as follows:
from .show import foo
show.py is as follows:
import cv2
import numpy as np
def foo():
cv2.imshow("random", np.random.rand(10,10))
cv2.waitKey()
return
setup.py is as follows:
from setuptools import setup
setup(name='gnn_pylib',
version='0.1',
description='General purpose python library',
url='http://github.com/whatever/gnn_pylib',
author='whatever',
author_email='whatever#gmail.com',
license='MIT',
packages=['gnn_pylib'],
install_requires=[
'numpy',
'cv2',
],
zip_safe=False)
Rather than using cv2 as the required package name instead use opencv-python since that's the name of the OpenCV bindings package available from PyPI. So your setup.py file will instead look like this (same as above with different entry for the OpenCV bindings package requirement):
from setuptools import setup
setup(name='gnn_pylib',
version='0.1',
description='General purpose python library',
url='http://github.com/whatever/gnn_pylib',
author='whatever',
author_email='whatever#gmail.com',
license='MIT',
packages=['gnn_pylib'],
install_requires=[
'numpy',
'opencv-python',
],
zip_safe=False)
#James Adams answer the specific case for cv2, replacing with more compatible opencv-python.
However, if you still want to have dependencies install from conda, consider make a conda package.
See similar question with answer:
setup.py with dependecies installed by conda (not pip)
Use 'conda install' instead of 'pip install' for setup.py packages
I cannot find answer with detail step-by-step and example yet. But hope it help.

Installing a single file package in conda/pip requires redundant import statement

I've created a python package that is posted to pypi.org. The package consists of a single .py file, which is the same name as the package.
After installing the package via pip (pip install package_name) in a conda or standard python environment I must use the following statement to import a function from this module:
from package_name.package_name import function_x
How can I reorganise my package or adjust my installation command so that I may use import statement
from package_name import function_x
which I have successfully used when I install via python setup.py install.
My setup.py is below
setup(
name = "package_name",
version = "...",
packages=find_packages(exclude=['examples', 'docs', 'build', 'dist']),
)
Change your setup arguments from using packages to using py_modules e.g.
setup(
name = "package_name",
version = "..",
py_modules=['package_name'],
)
This is documented here https://docs.python.org/2/distutils/introduction.html#a-simple-example

Speed up a pip install process that contains a build step

# setup.py
from setuptools import setup
from setuptools.command.install import install
from subprocess import check_call
class CustomInstall(install):
def run(self):
check_call("./build.sh")
install.run(self)
setup(
name='customlib',
packages=['customlib'],
version='0.0.1',
...
cmdclass={'install': CustomInstall}
)
build.sh contains a make & make install step which takes more than 10 minutes to finish.
Is there a PyPi way to "package" the output of build.sh to speed up the pip install process?
Use wheel. A wheel is a great standard format for passing around Python packages, and it can contain C code compiled for various architectures. PyPI supports uploading wheels for your project, and pip will download them when available.
Very useful docs can be found here: https://packaging.python.org/tutorials/distributing-packages/#packaging-your-project

setup.py install_require with options

I need to add rjsmin to my dependencies via install_require in a setup.py.
rjsmin offers a way to disable the c-extension by using the --without-c-extensions switch like following
python setup.py install --without-c-extensions
I wonder, how to add this switch to the install_require string.
I solved my problem of installing dependencies with global-options by sub-classing setuptools.command.install class and overriding its run() method, like following code -
from setuptools import setup
from setuptools.command.install import install
from subprocess import call
class CustomInstall(install):
def run(self):
install.run(self)
call(['pip', 'install', 'pycurl', '--global-option=--with-nss'])
setup( ...
cmdclass={
'install': CustomInstall,
},
)
Here, I am installing pycurl with global option --with-nss
You need to provide an --install-option or --global-option along with the requirement text.
You can refer the doc here

Categories