setup.py - Package and install CodeChat

Builds and installs CodeChat.

Packaging notes

Reading to get up to speed:

  • Python Packaging User Guide - the most up-to-date reference I’ve found so far. Tells which tools to actually use.

  • setuptools - A distutils replacement which can install dependencies, so I use it.

To package

Create a source distribution, a built distribution, then upload both to CodeChat at PyPI:

1python -m pip install -U pip setuptools wheel twine build
2python -m build
3python -m twine upload dist/*

For development:

1pip install -e .[test]

Packaging script

Otherwise known as the evils of setup.py.

PyPA copied code

From PyPA’s sample setup.py, read long_description from a file. This code was last updated on 26-May-2015 based on this commit.

Always prefer setuptools over distutils

from setuptools import setup
 

To use a consistent encoding

from os import path
 

Imports for version parse code.

import sys
import os
import re

here = path.abspath(path.dirname(__file__))
 

Get the long description from the relevant file.

with open(path.join(here, "README.rst"), encoding="utf-8") as f:
    long_description = f.read()

The inclusion of a raw tag causes PyPI to not render the reST. Ouch. Remove it before uploading.

    long_description = re.sub(
        r"\.\. raw.*</iframe>", "", long_description, flags=re.DOTALL
    )
 
 

This code was copied from version parse code. See version in the call to setup below.

def read(*names, **kwargs):
    with open(
        os.path.join(os.path.dirname(__file__), *names),
        encoding=kwargs.get("encoding", "utf8"),
    ) as fp:
        return fp.read()


def find_version(*file_paths):
    version_file = read(*file_paths)
    version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
    if version_match:
        return version_match.group(1)
    raise RuntimeError("Unable to find version string.")
 
 

My code

We support Python 3.4 and higher. I could instead use python_requires, but it seems like this is a new feature, so avoid it for now so that installs on older Python versions still work.

assert sys.version_info >= (3, 4)

setup(

This must comply with PEP 0426’s name requirements.

    name="CodeChat",

Projects should comply with the version scheme specified in PEP440. I use this so that my Sphinx docs will have the same version number. There are a lot of alternatives in Single-sourcing the Project Version. While I like something simple, such as import CodeChat then version=CodeChat.__version__ here, this means any dependencies of __init__.py will be required to run setup, a bad thing. So, instead I read the file in setup.py and parse the version with a regex (see version parse code).

    version=find_version("CodeChat", "__init__.py"),
    description="The CodeChat System for software documentation",
    long_description=long_description,

The project’s main homepage.

    url="http://codechat.readthedocs.io/en/latest/",
    author="Bryan A. Jones",
    author_email="bjones@ece.msstate.edu",
    license="GPLv3+",

These are taken from the full list.

    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
        "Operating System :: OS Independent",
        "Natural Language :: English",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.3",
        "Programming Language :: Python :: 3.4",
        "Programming Language :: Python :: 3.5",
        "Topic :: Software Development :: Documentation",
        "Topic :: Text Processing :: Markup",
    ],
    keywords="literate programming",
    packages=["CodeChat", "CodeChat.css"],

List run-time dependencies here. These will be installed by pip when your project is installed. For an analysis of “install_requires” vs pip’s requirements files see: https://packaging.python.org/en/latest/requirements.html

    install_requires=(
        [

Note: I don’t include Sphinx in this list: while CodeToRest.py can be executed from the command line if the packages below are installed, CodeToRestSphinx.py can only be executed by Sphinx.

            "docutils>=0.13.1",
            "pygments>=2.1",
            "lxml",
        ]
    ),

List additional groups of dependencies here (e.g. development dependencies). You can install these using the following syntax, for example:

$ pip install -e .[test]

    extras_require={
        "test": ["pytest", "sphinx>=3", "myst-parser", "black", "flake8"],
        "sphinx": ["sphinx>=3", "myst-parser"],
    },

To package data files, I’m using include_package_data=True. See including data files.

    include_package_data=True,

Make it easy to run the mdbooks CodeChat preprocessor.

    entry_points={
        "console_scripts": ["mdbook-CodeChat = CodeChat.mdbook_CodeChat:main"]
    },
)