.. doctest docs/dev/setup.rst
.. _dev.setup_info:
====================================
How Lino applications use `setup.py`
====================================
This document describes our trick for keeping the metadata about a Python
package in a single place. It does not depend on Lino and we recommend it for
any Python project which contains a package.
The classical layout is to store the setup information directly in the
:xfile:`setup.py` file of your project. The problem with this layout is that
this :xfile:`setup.py` file is not available at runtime.
For example the **version number**. You need it of course in the
:xfile:`setup.py`, but there are quite some projects which want to show somehow
their version. So they need it at runtime as well. And that number can change
quickly and can be critical. You don't want to store it in two different
places.
Is there a way to have setup information both in a central place *and**
accessible at runtime?
It is an old problem, and e.g. `Single-sourcing the package version
`__
describes a series of answers.
Our solution
============
To solve this problem, we store the setup information in a separate file which
we usually name :xfile:`setup_info.py` and which we load ("execute") from both
our :xfile:`setup.py` and our packages's main :xfile:`__init__.py` file.
That's why the :xfile:`setup.py` of a package "xxyyzz" contains just this::
from setuptools import setup
fn = 'xxyyzz/setup_info.py')
exec(compile(open(fn, "rb").read(), fn, 'exec'))
if __name__ == '__main__':
setup(**SETUP_INFO)
And the :file:`__init__.py` file of the main module contains this::
from os.path import join, dirname
fn = join(dirname(__file__), 'setup_info.py')
exec(compile(open(fn, "rb").read(), fn, 'exec'))
__version__ = SETUP_INFO.get('version')
Note that ``exec(compile(open(fn, "rb").read(), fn, 'exec'))`` is
equivalent to ``execfile(fn)``, except that it works in both Python 2
and 3.
Usage example:
>>> from lino import SETUP_INFO
>>> print(SETUP_INFO['description'])
A framework for writing desktop-like web applications using Django and ExtJS or React
>>> from lino_xl import SETUP_INFO
>>> print(SETUP_INFO['description'])
Lino Extensions Library
Related files
=============
These are the files we are talking about here.
.. xfile:: setup.py
A file named :xfile:`setup.py` is part of the `minimal structure
`__
of every Python project. It is in the root directory of a project
and contains information about the project, e.g. the **version
number** or the **dependencies** (i.e. which other Python packages
must be installed when using your package). The information in
this file is used for running test suites, installing the project
in different environments, etc...
.. xfile:: setup_info.py
The file which *actually* contains the information for Python's
:xfile:`setup.py` script. It is imported from both the :xfile:`setup.py`
and the packages's main :xfile:`__init__.py` file and usually defines a
global variable `SETUP_INFO`, a dict of keyword arguments to be passed to
the :func:`setup` function. It is located in the directory that contains
the main package of your project. E.g. for the :ref:`xl` project it is in
:file:`lino_xl/setup_info.py`. the main package of a project is specified
in the :xfile:`tasks.py`.
.. xfile:: README.rst
A file named ``README`` (or some variant thereof) should be in the
root directory of every public code repository and should contain
a description of your project, links to more detailed
documentation, ...
In Atelier projects this file is automatically generated from the
:ref:`long_description` by the :cmd:`inv bd`.
.. xfile:: MANIFEST.in
TODO
.. xfile:: test_packages.py
A file in the test suite of a repository that runs :meth:`run_packages_test
`.
Setup information
=================
The :func:`setup` function has a lot of keyword parameters which are
documented elsewhere.
.. _install_requires:
install_requires
----------------
See http://python-packaging.readthedocs.io/en/latest/dependencies.html
.. _tests_require:
tests_require
-------------
See http://python-packaging.readthedocs.io/en/latest/dependencies.html
.. _long_description:
long_description
----------------
This contains the description to be published on PyPI.
Some projects insert this in the :xfile:`api/index.rst` file of their docs
tree.
This is also used by :cmd:`inv bd` as the source text for generating the
project's :xfile:`README.rst`.
How to suggest changes to a README file
=======================================
We assume that you have installed a development environment as explained in
:ref:`dev.install`.
Open the :xfile:`setup_info.py` file of your project and find the
`long_description`.
Edit its content.
Run :cmd:`inv bd` in the root of the project you want to make changes. This
will ask you::
Overwrite /path/to/my/project/README.rst [Y,n]?
Hit ENTER.
Open the :xfile:`README.rst` file and check that it contains your changes.
Submit a pull request with the two modified files
:xfile:`setup_info.py` and :xfile:`README.rst`.