Finding application data after install - a solution?

Wolodja Wentland wentland at cl.uni-heidelberg.de
Sat Sep 19 17:03:52 CEST 2009


Hi all,

reliably finding distribution data from your program seems to be an
unsolved issue for programs packaged with distutils. 

I have seen a lot of code that manipulates mod.__file__ to solve this
problem, but this *will* break for some installation schemes and has the
following problems:

* it breaks if the user specified '--install-data' to have a different
  value than '--install-{pure,plat}lib'
* it makes the life of linux distribution package maintainers
  unneccessarily hard, because they have to patch your code so it works
  with their file system hierarchy.
* it does not work inside eggs
* it is ugly ;-)

Good news everyone! I spend some time to solve this problems and would
like to share my snippet and ask for comments.

The idea is to fill a python module 'build_info.py' with installation
prefix information *at build time* and access the data within that
module.

--- snip ---
from distutils.command.build_py import build_py as _build_py
from types import StringType, ListType, TupleType

import distutils.core as core
import sys
import os.path
import string

class build_py(_build_py):
    """build_py command
    
    This specific build_py command will modify module 'build_config' so that it
    contains information on installation prefixes afterwards.
    """
    def build_module (self, module, module_file, package):
        if type(package) is StringType:
            package = string.split(package, '.')
        elif type(package) not in (ListType, TupleType):
            raise TypeError, \
                  "'package' must be a string (dot-separated), list, or tuple"

        if ( module == 'build_info' and len(package) == 1 and package[0] == 'mwdb'):
            iobj = self.distribution.command_obj['install']

            with open(module_file, 'w') as module_fp:
                module_fp.write('# -*- coding: UTF-8 -*-\n\n')
                module_fp.write("DATA_DIR = '%s'\n"%(
                    os.path.join(iobj.install_data, 'share')))
                module_fp.write("LIB_DIR = '%s'\n"%(iobj.install_lib))
                module_fp.write("SCRIPT_DIR = '%s'\n"%(iobj.install_scripts))

        _build_py.build_module(self, module, module_file, package)

core.setup(name='foo',
           cmdclass={'build_py': build_py},
           ...
           )
--- snip ---

This works for installers based on distutils and those based on
setuptools and is IMHO a much cleaner and nicer solution than having to
use a complicated API that relies on externally managed information or
__file__ hacks.

Before you copy this i should note that i plan to use string templates
within 'build_info' and just substitute the wanted information and not
generate the whole file from scratch. 

The module detection logic and exception handling might need some work
as well. ;-)

I have the following questions:

1. Is the distutils 'API' i use here likely to break?
2. Can you think of a better way to do this?

with kind regards

    Wolodja Wentland
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 852 bytes
Desc: Digital signature
URL: <http://mail.python.org/pipermail/python-list/attachments/20090919/0daa00a2/attachment.pgp>


More information about the Python-list mailing list