The setup.py file

The setup.py file is what governs everything when you want to interact with a Python project. When the setup() method is executed, it generates a static metadata file, which follows the PEP 314 format. The metadata file holds all the metadata for the project, but you need to regenerate it via a setup() call to get it ;to the Python environment you are using.

The reason why you cannot use a static version is that the author of a project might have platform-specific code in ;setup.py, which generates a different metadata file depending on the platform and Python versions.

To rely on running a Python module to extract static information about a project has always been a problem. You need to make sure that the code in the module can run in the target Python interpreter. If you are going to make your microservices available to the community, you need to keep that in mind, as the installation happens in many different Python environments.

PEP 390 (2009) was the first attempt to get rid of the setup.py file for metadata. PEP 426, PEP 508, and PEP 518 are new attempts at fixing this issue with smaller chunks, but in 2017, we still don't have tools that support static metadata, and it is probably going to take a while before everyone uses them. So setup.py is going to stick around for years.

A very common mistake when creating the setup.py file is to import your package in it when you have third-party dependencies. If a tool like PIP tries to read the metadata by running setup.py, it might raise an import error before it has a chance to list all the dependencies to install.

The only dependency you can afford to import directly in your setup.py file is Setuptools, because you can make the assumption that anyone trying to install your project is likely to have it in their environment.

Another important consideration is the metadata you want to include to describe your project. Your project can work with just a name, a version, a URL, and an author, but this is obviously not enough information to describe your project.

Metadata fields are set through setup() arguments. Some of them match directly with the name of the metadata, some don't.

The following is the minimal set of arguments you should use for your microservices projects:

  • name: The name of the package, should be a short lowercase name
  • version: The version of the project, as defined in PEP 440
  • url: A URL for the project; can be its repository or home page
  • description: One sentence to describe the project
  • long_description: A reStructuredText document
  • author, and author_email: The name and email of the author--can be an organization
  • license: The license used for the project (MIT, Apache2, GPL, and so on)
  • classifiers: A list of classifiers picked from a fixed list, as defined in PEP 301
  • keywords: Tags to describe your project--this is useful if you publish the project to the Python Package Index (PyPI)
  • packages: A list of packages that your project includes--Setuptools can populate that option automatically with the find_packages() method
  • install_requires: A list of dependencies (this is a Setuptools option)
  • entry_points: A list of Setuptools hooks, like console scripts (this is a Setuptools option)
  • include_package_data: A flag that simplifies the inclusion of non-Python files
  • zip_safe: This is a flag that prevents Setuptools to install the project as a ZIP file, which is a standard from the past (executable eggs)

The following is an example of a setup.py file that includes those options:

    from setuptools import setup, find_packages 

with open('README.rst') as f:
LONG_DESC = f.read()

setup(name='MyProject',
version='1.0.0',
url='http://example.com',
description='This is a cool microservice based on strava.',
long_description=LONG_DESC,
author='Tarek', author_email='[email protected]',
license='MIT',
classifiers=[
'Development Status :: 3 - Alpha',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3'],
keywords=['flask', 'microservice', 'strava'],
packages=find_packages(),
include_package_data=True,
zip_safe=False,
entry_points="""
[console_scripts]
mycli = mypackage.mymodule:myfunc
""",
install_requires=['stravalib'])
)

The long_description option is usually pulled from a README.rst file, so you do not have to deal with including a large piece of reStructuredText string in your function.

The restructured text-lint project (https://github.com/twolfson/restructuredtext-lint) is a linter that you can use to verify a reST file syntax.

The other benefit of separating the description is that it's automatically recognized, parsed, and displayed by most editors. For instance, GitHub uses it as your project landing page in your repository, and also offers an inline reStructuredText editor to change it directly from the browser. PyPI does the same to display the front page of the project.

The license field is free-form, as long as people can recognize the license being used. If you use the Apache Public Licence Version 2 (APL v2),it works. In any case, you should add, alongside your setup.py file, a LICENCE file with the official text of that license.

The classifiers option is probably the most painful one to write. You need to use strings from https://pypi.python.org/pypi?%3Aaction=list_classifiers, which classify your project. The three most common classifiers that developers use are the list of supported Python versions, the license (which duplicates and should match the license option), and the development status, which is a hint about the maturity of the project.

Keywords are a good way to make your project visible if you publish it to the Python Package Index. For instance, if you are creating a Flask microservice, you should use flask and microservice as keywords.

The Trove classifier is a machine-parseable metadata that can be used, for instance, by tools interacting with PyPI. For example, the zc.buildout tool looks for packages with the Framework :: Buildout :: Recipe classifier.

The entry_points section is an INI-like string that defines Setuptools entry points, which are callables that can be used as plugins once the project is installed in Python. The most common entry point type is the console script. When you add functions in that section, a command-line script will be installed alongside the Python interpreter, and the function hooked to it via the entry point. This is a good way to create a Command-Line Interface (CLI) for your project. In the example, mycli should be directly reachable in the shell when the project is installed. Python's Distutils has a similar feature, but the one in Setuptools does a better job, because it allows you to point to a specific function.

Lastly, install_requires lists all the dependencies. This list of Python projects the project uses, and can be used by projects like PIP when the installation occurs. The tool will grab them if they are published in the PyPI, and install them.

Once this setup.py file is created, a good way to try it is by creating a local virtual environment.

Assuming you have virtualenv installed, if you run these commands in the directory containing the setup.py file, it will create a few directories including a bin directory containing a local Python interpreter, and drop you into a local shell.

$ virtualenv . 
$ source bin/activate
(thedir) $

From there, running the pip install -e ; command will install the project in editable mode. This command installs the project by reading its setup file, but unlike install, the installation occurs in-place. Installing in-place means that you will be able to work directly on the Python modules in the project, and they will be linked to the local Python installation via its site-packages directory.

Using a vanilla install call would have created copies of the files into the local site-packages directory, and changing the source code would have had no impact on the installed version.

The PIP call also generates a ;MyProject.egg-info directory, which contains the metadata. PIP generates version 1.1 of the metadata spec, under the PKG-INFO name.

$ more MyProject.egg-info/PKG-INFO 
Metadata-Version: 1.1
Name: MyProject
Version: 1.0.0
Summary: This is a cool project.
Home-page: http://example.com
Author: Tarek
Author-email: [email protected]
License: MIT
Description: MyProject
---------

I am the **long** description.

Keywords: flask,microservice,strava
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3

This metadata file is what describes your project and is what is used to register it to the PyPI via other commands, as we will see later in the chapter.

The PIP call also pulls all the project dependencies by looking from them in the PyPI on https://pypi.python.org/pypi and installs them in the local site-packages. Running this command is a good way to make sure everything works as expected.

One thing that we need to discuss further is the install_requires option. It competes with another way of listing the project dependencies, the requirements.txt file, which is explained in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset