14

I am trying to learn how to make a Python module available via pip on PyPI. In order to do this, I am testing using the PyPI test site (https://testpypi.python.org/pypi) and have attempted to create a setup.py for the module. My module is a file at the root directory and I cannot get it to be installed successfully. I want to find out how to do this.

Below, I detail the steps I am taking. I suspect that the problem lies in how I have written setup.py.

The anatomy of the repository is as follows:

.
├── examples_1.py
├── LICENSE
├── MANIFEST.in
├── README.rst
├── setup.py
└── supermodule.py

Note that the module is simply the file supermodule.py at the root of the directory. Note also that the file examples_1.py is not to be included in an installation of the module package.

The contents of setup.py are as follows:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import setuptools

def read(*paths):

    with open(os.path.join(*paths), "r") as filename:
        return filename.read()

def main():

    setuptools.setup(
        name             = "supermodule",
        version          = "2015.10.30.0820",
        description      = "super utilities",
        long_description = (read("README.rst")),
        url              = "https://github.com/johndrake1/junk",
        author           = "John Drake",
        author_email     = "j.drake@sern.ch",
        license          = "GPLv3",
        package_data     = {
            "": [
                "*.txt",
                "*.md",
                "*.rst",
                "*.py"
            ]
        }
    )

if __name__ == "__main__":
    main()

I go through the following procedures to register, upload and install the package:

python setup.py register -r https://testpypi.python.org/pypi
python setup.py sdist upload -r https://testpypi.python.org/pypi
sudo pip install -i https://testpypi.python.org/pypi supermodule

In the source distribution, supermodule-2015.10.30.0820.tar.gz, I can see the following directory structure:

.
└── supermodule-2015.10.30.0820
    ├── LICENSE
    ├── MANIFEST.in
    ├── PKG-INFO
    ├── README.rst
    ├── setup.cfg
    ├── setup.py
    ├── supermodule.egg-info
    │   ├── dependency_links.txt
    │   ├── PKG-INFO
    │   ├── SOURCES.txt
    │   └── top_level.txt
    └── supermodule.py

So, it appears that the packaging and uploading works fine and contains the module file supermodule.py that is at the root directory. However, when I install the package, I get the following files installed locally:

/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/DESCRIPTION.rst
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/METADATA
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/RECORD
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/WHEEL
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/metadata.json
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0820.dist-info/top_level.txt

You can see that the file supermodule.py is not there and it cannot be imported in a Python instance. What should I do to include this file in the installation such that it is importable in Python?


EDIT: Following a suggestion by @DeanFenster, I moved the file supermodule.py to supermodule/__init__.py and changed setup.py to the following:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import setuptools

def read(*paths):
    with open(os.path.join(*paths), "r") as filename:
        return filename.read()

def main():

    setuptools.setup(
        name             = "supermodule",
        version          = "2015.10.30.0902",
        description      = "super utilities",
        long_description = (read("README.rst")),
        url              = "https://github.com/johndrake1/junk",
        author           = "John Drake",
        author_email     = "j.drake@sern.ch",
        license          = "GPLv3",
        packages         = ["supermodule"]
    )

if __name__ == "__main__":
    main()

Following registration, upload and installation, this resulted in an installation that made the module importable, with the following files installed locally:

/usr/local/lib/python2.7/dist-packages/supermodule
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info
/usr/local/lib/python2.7/dist-packages/supermodule/__init__.py
/usr/local/lib/python2.7/dist-packages/supermodule/__init__.pyc
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/DESCRIPTION.rst
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/METADATA
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/RECORD
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/WHEEL
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/metadata.json
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.0902.dist-info/top_level.txt

It's good that this approach works, but I would still like to know how to install the module when it is in the form of a single file.


EDIT: Following a suggestion by @Xk0nSid, I changed setup.py to the following:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import setuptools

def read(*paths):
    with open(os.path.join(*paths), "r") as filename:
        return filename.read()

def main():

    setuptools.setup(
        name             = "supermodule",
        version          = "2015.10.30.1001",
        description      = "super utilities",
        long_description = (read("README.rst")),
        url              = "https://github.com/johndrake1/junk",
        author           = "John Drake",
        author_email     = "j.drake@sern.ch",
        license          = "GPLv3",
        py_modules       = ["supermodule"],
        entry_points     = """
            [console_scripts]
            supermodule = supermodule:supermodule
        """
    )

if __name__ == "__main__":
    main()

Following registration, upload and installation, this resulted in an installation that made the module importable, with the following files installed locally:

/usr/local/bin/supermodule
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info
/usr/local/lib/python2.7/dist-packages/supermodule.py
/usr/local/lib/python2.7/dist-packages/supermodule.pyc
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/DESCRIPTION.rst
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/METADATA
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/RECORD
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/WHEEL
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/entry_points.txt
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/metadata.json
/usr/local/lib/python2.7/dist-packages/supermodule-2015.10.30.1001.dist-info/top_level.txt

This approach was successful at handling the single file form of the module.

d3pd
  • 7,935
  • 24
  • 76
  • 127
  • 1
    Does the module exist in the `site_packages` directory? – Dean Fenster Oct 30 '15 at 08:49
  • @DeanFenster Hey, thanks for your comment. No, the module doesn't exist at the directory `/usr/local/lib/python2.7/dist-packages` following installation. The directories listed in my question are the sole directories at which `supermodule` appears to exist. – d3pd Oct 30 '15 at 08:54
  • 1
    How about trying to put your script in a package? (a folder with the project's name and the code in the `__init__` file) – Dean Fenster Oct 30 '15 at 09:00
  • @DeanFenster Thanks for your suggestion. I have just tried your approach and added details of the approach to an edit of the question. With this approach, the package gets installed successfully and is importable in Python. So, it's good to know that that works. I'd still like to know how to install the module when it is in the form of a single file. – d3pd Oct 30 '15 at 09:13

1 Answers1

25

Try using something like this for a single file. Following is the directory structure:

.
├── example.py
├── LICENSE
├── README.md
└── setup.py

0 directories, 4 files

setup.py

from setuptools import setup

setup(
    name='example',
    version='0.1.0',
    py_modules=['example'],
    install_requires=[
        'exampledep',
    ],
    entry_points='''
        [console_scripts]
        example=example:example
    ''',
)

The above worked for me. This is how example file would look like.

def example():
    # Note: You can use sys.argv here
    print "Hi! I'm a command written in python."

This can also be imported like so:

import example
example.example()
# or
from example import example
example()

Hope this helps.

Install Requires

The install_requires is used to define the dependencies for your module/application. For e.g in this case example module in dependent on exampledep. So when someone does pip install example, then pip will also install exampledep as it is listed in the dependencies.

Entry Points

This is usually a callable which the end user of package might want to use. This usually a callable and is used for command line. You can look at this question or this doc for more details.

Community
  • 1
  • 1
Xk0nSid
  • 961
  • 2
  • 11
  • 19
  • Great, thanks for your help on that. That appears to work successfully. Do you suppose you could add some small details on the options `install_requires` and `entry_points`? I'm quite new to this. – d3pd Oct 30 '15 at 10:18
  • Sure. I've updated the answer with some explanation a couple of links for reference. – Xk0nSid Nov 01 '15 at 16:00
  • 2
    Thanks, this line help me a lot py_modules=['example'] – Anderson Contreira Apr 17 '20 at 19:27