The netsa.dist module is intended primarily for NetSA development team, to provide a common set of practices for generating documentation, running tests, and distributing and installing our software. If you are not a member of the NetSA dev team, you’re likely to be better served by using the standard distutils module or the more powerful setuptools package.
netsa.dist provides a set of extensions to distutils, along with an alternative API for specifying the contents of the distribution. The extensions provide for automatic generation of documentation using Sphinx (including PDF, HTML, and man pages), automatic generation of Python-readable version information from configuration metadata, and targets for running automated tests. The alternative API allows for specification of project metadata in a similar style to the metadata of netsa.script.
When running setup.py for a project that uses netsa.dist, all of the normal commands (build, install, sdist, etc.) are available, along with the following:
The files of the project are expected to be arranged mostly as follows:
Directory | Purpose |
---|---|
bin | Contains Python scripts to be installed as executables. |
doc | Contains Sphinx documentation sources, including conf.py. See disable_documentation, and Documentation Configuration. |
src | Contains Python source code and data files to be installed in Python packages. See add_package, add_package_data, and add_module_py. |
The following directories are used to contain outputs, and any extra files in them may be automatically destroyed by the clean command:
Directory | Purpose |
---|---|
build | A variety of intermediate products are stored here while building the project. |
dist | Final products (tarballs) are stored here. |
doc/html | HTML documentation generated with gen_doc_html will do here. |
doc/man | manpage documentation generated with gen_doc_man will go here. |
To support simpler common configuration for documentation output, a convenience module is create during documentation generation. Under most circumstances, you should be able to use the following conf.py without changes:
from netsa_sphinx_config import *
add_static_path("static_html")
Importing all symbols from netsa_sphinx_config sets all of the settings to their normal values for a NetSA project, including producing output appropriate for use on the NetSA Tools website automatically.
If you need to make modifications, just replace or modify the values of standard Sphinx build options.
The following function is provided to allow automatic generation of man pages. Any man page generated from the documentation will be automatically generated and included in source distributions, and automatically installed in the appropriate location.
Add a new man page to be generated from the given source_file (without extension). The name of the resulting file is man_page.*section*. Note that when Sphinx generates man pages, the top-level heading from the input file is ignored, and the title used is “man_page - description” instead. This way, you can use the same input file to produce installed man pages and to produce man pages for display in the HTML output.
The following functions are used to set metadata for the project:
Sets the name of the project. This name is used as part of the name of produced tarballs and documentation files.
Sets the title for this project. This should be the human-readable name of the project. It is displayed in most places as the project name.
Sets the long-form description for this project. This should be a detailed explanation of the project’s purpose.
Sets the version number for this project. The version number is used as part of the filename of distribution files, is included in the documentation, and may be written out as version files (see add_version_file and netsa.find_version).
Sets the copyright date for this project. This is used in documentation generation, and in the project metadata. For example:
dist.set_copyright("2008-2011, Carnegie Mellon University")
Sets the license type for this project, which defaults to 'GPL'. This is used for project distribution metadata.
Given a name and email address (i.e. 'Harry Q. Bovik <bovik@sample.samp>') sets the maintainer name and email address metadata for the project.
Given a name and email address (i.e. 'Harry Q. Bovik <bovik@sample.samp>') sets the author name and email address metadata for the project.
Sets the home page URL metadata for this project.
Sets the download page URL metadata for this project.
Choosing which files should be installed where is accomplished with the following functions:
Adds a Python package to be installed, by package name. For example:
dist.add_package("netsa.data")
The files for this Python package would be found under src/netsa/dist. Remember that the package directory (and every directory leading up to it) must include an __init__.py file to be accepted as a Python package.
Adds one or more data files to be installed within a package. Each file or directory that data_file_glob expands to is included. The files and directories should be stored under src/<package_name>, just like the Python source files for the package. For a method of installing files in different places, see add_install_data.
Adds a single module by module name. For example:
dist.add_module_py("netsa.util.shell")
Thie file for this module would be found at src/netsa/util/shell.py. Remember that the package directory (and every directory leading up to it) must include an __init__.py file, which will also be installed.
Adds a single C extension module, given a module name, a list of sources, and optional keyword arguments as accepted by distutils.core.Extension. For example:
dist.add_module_ext('foo', ['foo.c', 'bar.c'])
Adds a single script by script name. For example:
dist.add_script("helloworld")
The file for this script would be found at bin/helloworld. When installed, if the script has a #! line and contains python, it will automatically be modified to point to the version of Python being used to install this project.
Adds an extra data file that should be installed when the project is installed. The data_file_name should be the path to the file from the top level of the project. install_path should be the path to the installation directory from the install prefix. For example:
dist.add_install_data("share/doc/helloworld", "samples/helloworld.ini")
This would install the file found at samples/helloworld.ini as .../share/doc/helloworld/helloworld.ini under the installation prefix.
Given a glob string, adds files which match that glob to the distribution. This is used to add any extra files (README, etc.) that should be included in a source distribution but are not to be installed. If you do include in this list a file that’s already to be installed, it will still be installed, and it will still be included in the distribution.
In order to avoid recording the version number in both the setup.py file and the source code, you can use the following functions to automatically generate a file with the version number in it, and read it back at run time:
Adds a “version file” to the project, with the given path and template. By default the template is "%s\n", which simply includes the version number and a newline. The path should be given relative to the base of the project. The version file will be generated automatically before any other processing is done.
See netsa.find_version for a convenient method for retrieving the version number from this file for your package.
Example:
# in setup.py
dist.add_version_file("src/netsa/VERSION")
# in netsa/__init__.py
__version__ = netsa.find_version(__file__)
Given the path to a Python source file, read in a version number from a file VERSION in the same directory, or look for a setup.py file in up to num_levels directories above the file and attempt to find the version there.
The following functions allow automated tests to be added and run from setup.py:
Adds a unit test module to be run, by module name. For example:
dist.add_unit_test_module("netsa.data.test")
The provided module is expected to be a unittest test module, and the tests will be run in a separate process from the process running setup.py. Running tests automatically builds the project, and places the build area in the PYTHONPATH for the test process.
Adds a module to be run for testing, by module name. For example:
dist.add_other_test_module("crunchy.test")
The provided module is called in a subprocess like this:
python -m crunchy.test ${source_dir}
Where ${source_dir} is the top level source directory of the project. Running tests automatically builds the project, and places the build area in the PYTHONPATH for the test process.
Finally, once the project is fully configured, use this function to handle command-line options and actually running the tasks:
Using the project as so far specified, parse command line options and does what is required to build, install, test, or make a distribution for the project. This should be called as the last thing in setup.py.