Autoloader (was Re: [Python-Dev] Adding Optik to 2.3 standard library)

Barry A. Warsaw barry@zope.com
Mon, 15 Apr 2002 10:12:42 -0400


I've now uploaded a patch (really a tarball) to

http://sourceforge.net/tracker/index.php?func=detail&aid=544175&group_id=38019&atid=421099

Below is the __init__.py.  I found that _copysyms() was necessary
because if you just pulled in the exported symbols from say, getopt,
getopt.getopt() wouldn't find the helper functions which are global to
its namespace.  Oh well.  It does mean you have to watch out for name
collisions when stitching stuff together like this.

You also have to play funny games with imports to get them to work
right (you can't do intra-package imports through fully-qualified
getopt.* imports).

-Barry

P.S. I think that ImportError probably ought to be an AttributeError

-------------------- snip snip --------------------
# Copyright (c) 2002 Python Software Foundation

# As of Python 2.3, we now have two command line option parsing systems, the
# legacy getopt interface and Greg Ward's Optik.  The code below provides a
# lazy loading system so that only the option parsers requested are actually
# loaded from this submodule.

# Autoloader class, see
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65207

import sys

class _Autoloader:
    # legacy getopt module exports these symbols
    getopt_exports = ['getopt', 'GetoptError', 'error']

    # Optik exports these symbols
    optik_exports = ['OptionParser', 'SUPPRESS_HELP', 'SUPPRESS_USAGE',
                      'STD_HELP_OPTION', 'OptionValueError']

    def __getattr__(self, name):
        if name in self.getopt_exports:
            import _getopt._getopt
            self._copysyms(_getopt._getopt)
        elif name in self.optik_exports:
            # Import the whole Optik world
            import _getopt.option
            self._copysyms(_getopt.option)
            import _getopt.option_parser
            self._copysyms(_getopt.option_parser)
            import _getopt.errors
            self._copysyms(_getopt.errors)
        else:
            raise ImportError, name
        return self.__dict__[name]

    # If we don't copy all the globals from the module, we'll get exceptions
    # when publically exported names try to access other globals in the same
    # module.
    def _copysyms(self, module):
        for name in dir(module):
            self.__dict__[name] = getattr(module, name)

# So we can do sub-imports later
sys.modules['_getopt'] = sys.modules[__name__]
sys.modules[__name__] = _Autoloader()