Guides

Specifiying data files

Most packages have some files besides pure code: configuration, data files, documentation, etc... When those files need to be installed, you should use DataFiles sections. Each such section has two mandatory fields, to specify the target directory (where files are installed) and which files are specific to this section:

DataFiles: manage
    TargetDir: /usr/man/man1
    Files: fubar/fubar1

This will install the file top_dir/fubar/fubar1 into /usr/man/man1/fubar/fubar1.

Flexible install scheme

Hardcoding the target directory as above is not flexibe. The user may want to install manpages somewhere else. Bento defines a set of variable paths which are customizable from bentomaker, with platform-specific defaults. For manpages, the variable is mandir:

DataFiles: manpage
    TargetDir: $mandir/man1
    Files: fubar/fubar.1

Now, the installation path is customizable, e.g.:

bentomaker configure --mandir=/opt/man

will cause the target directory to translate to /opt/man/man1. Moreover, as mandir default value is defined relatively to $prefix ($prefix/man on unix), modifying the prefix will also change how mandir is expanded at install time:

# $mandir is automatically expanded to /opt/man
bentomaker configure --prefix=/opt

If you do not want to install files with their directory component, you need to use the SourceDir option:

DataFiles: manpage
    TargetDir: $mandir
    SourceDir: fubar
    Files: fubar.1

will install fubar/fubar.1 as $mandir/fubar.1 instead of $mandir/fubar/fubar.1.

Custom data paths

While the default list should cover most package needs, it is sometimes useful to define custom path variable:

Path: foo
    Description: foo directory
    Default: $datadir/foo

Bentomaker will automatically add the –foodir option, and $foo will be expanded to the customized value (or $datadir/foo by default). The description will be used as a description in the help message.

Conditional customization

It is sometimes necessary to define platform-specific default for custom paths. This can be done as follows:

Path: foo
    Description: foo directory
    if os(darwin):
        Default: /Library/foo
    else:
        Default: $bin/foo

FIXME: refer to conditional

Retrieving data files at runtime

It is often necessary to retrieve data files from your python code. For example, you may have a configuration file which needs to be read at startup. The simplest way to do so is to use __file__ and refer to data files relatively to python code location. This is not very flexible, because it requires dealing with platform idiosyncraties w.r.t. file location. Setuptools and its descendents have an alternative mechanism to retrieve resources at runtime, implemented in the pkg_resource module.

Bento uses a much simpler system, based on a simple python module generated at install time, containing all the relevant information. This file is not generated by default, and you need to define which file will contain all those variables with the ConfigPy field:

ConfigPy: foo/__bento_config.py

This tells bento to generate a module, and install it into foo/__bento_config.py. The path is always relative to site-packages (e.g. /usr/local/lib/python2.6/site-packages/foo/__bento_config.py by default on unix). The file looks as follows:

DOCDIR = "/usr/local/share/doc/config_py"
SHAREDSTATEDIR = "/usr/local/com"
...

to that you can import every path variable with its expanded value in your package:

from foo.__bento_config import DOCDIR, SHAREDSTATEDIR

As the generated python module is a simple python file with pair values, it is easy to modify it if desired (for debugging, etc...), and understandable by any python programmer.

If you need to support the case where the package has not been built yet, you can do as follows:

try:
    from foo.__bento_config import DOCDIR, SHAREDSTATEDIR
except ImportError:
    # Default values (so that the package may be imported/used without
    # being built)
    DOCDIR = ...

This is not done by default as it is not possible to know the right default value.

Example

Assuming the following bento file:

...

DataFiles: test_data
    SourceDir: data
    TargetDir: $pkgdatadir
    Files:
        foo.dat

ConfigPy: foo/__bento_config.py

you can access “foo.dat” as follows in your package:

try:
    from foo.__bento_config import PKGDATADIR
except ImportError:
    PKGDATADIR = "data" # default value

data = os.path.join(PKGDATADIR, "foo.dat")

This will point to the right location independently on $pkgdatadir value.

Recursive package description

If you have a package with a lot of python subpackages which require custom configurations, doing everything in one bento.info file is restrictive. Bento has a simple recursive feature so that one bento.info can refer to another bento.info:

...
Recurse: foo, bar

The Recurse field indicates to bento that it should look for bento.info in both foo/ and bar/ directories. At this time, those bento.info files support a strict subset of the top bento.info. For example, no metadata may be defined in sub-bento.info.

Simple example

Let’s assume that you have a software with the packages foo, foo.bar and foo.foo. The simplest way to define this software would be:

...
Library:
    Packages: foo, foo.bar, foo.fubar

Alternatively, an equivalent description, using the recursive feature:

...
Recurse: foo

Library:
    Package: foo

and the foo/bento.info:

...
Library:
    Packages: bar, fubar

The packages are defined relatively to the directory where the subento file is located. Obviously, in this case, it is overkill, but for complex, deeply nested packages (like scipy or twisted), this makes the bento.info more readable. It is especially useful when you use this with the hook file mechanism, where each subento file can drive a part of the configure/build through command hooks and overrides. In that case, the hook file defined in a subdirectory only sees the libraries, modules, etc... defined in the corresponding bento.info by default (see hook section).