[Distutils] installing .py plugins to an alternate directory
David Cournapeau
david at ar.media.kyoto-u.ac.jp
Thu Dec 3 04:46:53 CET 2009
Andrew Dalke wrote:
> Hi all,
>
> I'm working with the Akara project. It contains a web server. The server loads extensions from a special directory (let's say "$AKARA" for now). An extension can register handlers for URLs. An example extension might look like:
>
> installs to $AKARA/spam_extension.py
> (note: only .py files are supported; not even .pyc files)
> =========================
> from akara.services import simple_service
>
> import my_spam # This is part of the distribution, and gets put in site-packages
>
> @simple_service("GET", "http://vikings.protocol.id/")
> def vikings(say=my_spam.DEFAULT_TEXT):
> return my_spam.vikings(say)
> =========================
>
>
> We want people to be able to distribute Akara plugins and install via setup.py. Ideally I would like to say:
>
> from distutils.core import setup
> from akara.distutils ... I'm not sure what here ...
>
> setup(name="Spam services",
> package="my_spam",
> akara_extensions=["spam_extension.py"]
> )
>
>
> To clarify, the development/distribution package looks like:
> $PACKAGE/setup.py
> $PACKAGE/README
> $PACKAGE/spam_extensions.py
> $PACKAGE/my_spam/__init__.py
> $PACKAGE/my_spam/dramatis_personae.py
> $PACKAGE/my_spam/cafe.py
>
> and $PACKAGE/spam_extensions.py goes to $AKARA/spam_extensions.py while $PACKAGE/my_spam is copied to site-packages.
>
> The installation does not need to byte-compile spam_extension.py.
>
> It should also include spam_extension.py in any distribution that it makes.
>
>
> I looked through the documentation and searched for existing examples, but found nothing which does this. The plugins I found used entry_points, and that's an architecture change which I don't think is appropriate for us.
I won't comment on entry_points, as I have never used them. The way I
would do it is by having akara distutils extensions, which define in
particular a setup function and associated classes.
Here is the code:
import shutil
from distutils.core import setup as _setup
from distutils.core import Command
from distutils import log
# XXX: you will need to handle setuptools (and distribute, and....)
# monkey-patching for the below commands
from distutils.command.install import install as old_install
from distutils.dist import Distribution as _Distribution
# Where to install akara extensions
AKARA_SITE = '/tmp'
def setup(**kw):
new_kw = kw.copy()
# Handle commands overriding
cmdclass = new_kw.get('cmdclass', {})
if 'install' in cmdclass:
install = cmdclass['install']
else:
install = old_install
class my_install(install):
sub_commands = install.sub_commands + [
('install_akara_extensions', lambda x: True)
]
class install_akara_extensions(Command):
description = "Command to install akara extensions"
user_options = [
('akara-site=', None, 'Akara plugin directory install'),
]
def initialize_options(self):
self.install_dir = None
self.akara_site = None
self.outfiles = []
def finalize_options(self):
if self.akara_site is None:
self.akara_site = AKARA_SITE
def run (self):
dist = self.distribution
for a in dist.akara_extensions:
log.info("Installing akara extension %s in %s" % (a,
self.akara_site))
shutil.copy(a, self.akara_site)
new_cmdclass = {}
new_cmdclass.update(cmdclass)
new_cmdclass['install'] = my_install
new_cmdclass['install_akara_extensions'] = install_akara_extensions
new_kw['cmdclass'] = new_cmdclass
# Handle overriden distclass
if not 'distclass' in new_kw:
Distribution = new_kw['distclass']
else:
Distribution = _Distribution
class MyDistribution(Distribution):
def __init__(self, attrs=None):
assert not hasattr(self, 'akara_extensions')
if 'akara_extensions' in attrs:
self.akara_extensions = attrs['akara_extensions']
else:
self.akara_extensions = []
Distribution.__init__(self, attrs)
new_kw['distclass'] = MyDistribution
return _setup(**new_kw)
setup(name="Spam services",
packages=["my_spam"],
akara_extensions=["spam_extension.py"]
)
This is the minimal code to support this semi correctly. Note that many
things are not handled correctly:
- get_output for install_akara_extensions should be handled
- most likely it will break for semi-random distutils extensions,
including setuptools and distribute: you will need to detect
monkey-patching to decide which Distribution and install commands to
override. I have not done it because it requires the extensions to be in
a separate package (to conditionally import things depending on detected
monkey patching).
If you think this is insane, you are not alone :)
David
More information about the Distutils-SIG
mailing list