Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a Python module single file be installed using pip and PyPI?

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     = "[email protected]",
        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     = "[email protected]",
        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     = "[email protected]",
        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.

like image 606
d3pd Avatar asked Oct 30 '15 08:10

d3pd


1 Answers

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.

like image 90
Xk0nSid Avatar answered Nov 09 '22 03:11

Xk0nSid