68

I wonder if as well as .deb packages for example, it is possible in my setup.py I configure the dependencies for my package, and run:

$ sudo python setup.py install

They are installed automatically. Already researched the internet but all I found out just leaving me confused, things like "requires", "install_requires" and "requirements.txt"

1

4 Answers 4

44

Just create requirements.txt in your lib folder and add all dependencies like this:

gunicorn
docutils>=0.3
lxml==0.5a7

Then create a setup.py script and read requirements.txt:

import os
lib_folder = os.path.dirname(os.path.realpath(__file__))
requirement_path = f"{lib_folder}/requirements.txt"
install_requires = [] # Here we'll add: ["gunicorn", "docutils>=0.3", "lxml==0.5a7"]
if os.path.isfile(requirement_path):
    with open(requirement_path) as f:
        install_requires = f.read().splitlines()
setup(name="mypackage", install_requires=install_requires, [...])

The execution of python setup.py install will install your package and all dependencies. Like @jwodder said it is not mandatory to create a requirements.txt file, you can just set install_requires directly in the setup.py script. But writing a requirements.txt file is a best practice.

In the setup function call, you also have to set version, packages, author, etc, read the doc for a complete example: https://docs.python.org/3/distutils/setupscript.html

Your package directory should look like this:

├── mypackage
│   ├── mypackage
│   │   ├── __init__.py
│   │   └── mymodule.py
│   ├── requirements.txt
│   └── setup.py
Sign up to request clarification or add additional context in comments.

6 Comments

install_requires = list(f.read().splitlines()) is much more straightforward than appending one line at a time in a loop. (The list call may or may not be necessary; test and see.)
Or maybe something like [line for line in f.read().splitlines() if len(line) > 0] to prevent blank lines
Or you could just forego the requirements.txt file entirely and write setup(install_requires=['gunicorn', 'docutils>=0.3', 'lxml==0.5a7'], ...) directly in your setup.py.
I'd add, one should ignore comments and whitespaces prefix install_requires = [line for line in map(str.lstrip, f.read().splitlines()) if len(line) > 0 and not line.startswith('#')]
While all proposed solutions so far somehow parse the requirements.txt file and use these dependencies as install_requires in the setup.py, there is an argument whether this is a good practice or not: caremad.io/posts/2013/07/setup-vs-requirement
|
11

You generate egg information from your setup.py, then you use the requirements.txt from these egg information:

$ python setup.py egg_info
$ pip install -r <your_package_name>.egg-info/requires.txt 

1 Comment

This looks really good
10

Another possible solution

try:
    # for pip >= 10
    from pip._internal.req import parse_requirements
except ImportError:
    # for pip <= 9.0.3
    from pip.req import parse_requirements

def load_requirements(fname):
    reqs = parse_requirements(fname, session="test")
    return [str(ir.req) for ir in reqs]

setup(name="yourpackage", install_requires=load_requirements("requirements.txt"))

2 Comments

This worked for me. No idea how this would fail in the future though (if it ever fails).
@muammar it could fail because pip is explicitly not supposed to be used programmatically. See that _ in pip._internal.req? That means it's part of a package's internals, which shouldn't be used externally and may change without warning. There is absolutely no guarantee that it won't suddenly change, and in fact it has.
3

In Python 3.4+, it is possible to use the Path class from pathlib, to do effectively the same thing as @hayj answer.

from pathlib import Path
import setuptools

...

def get_install_requires() -> List[str]:
    """Returns requirements.txt parsed to a list"""
    fname = Path(__file__).parent / 'requirements.txt'
    targets = []
    if fname.exists():
        with open(fname, 'r') as f:
            targets = f.read().splitlines()
    return targets

...

setuptools.setup(
    ...
    install_requires=get_install_requires(),
    ...
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.