[Python-checkins] distutils2: merged Pumazi work

tarek.ziade python-checkins at python.org
Mon Apr 5 23:09:20 CEST 2010


tarek.ziade pushed 4c5701baf92f to distutils2:

http://hg.python.org/distutils2/rev/4c5701baf92f
changeset:   109:4c5701baf92f
parent:      85:a59c69e26de6
parent:      108:aade6bc810a5
user:        Tarek Ziade <tarek at ziade.org>
date:        Mon Apr 05 23:06:50 2010 +0200
summary:     merged Pumazi work
files:       

diff --git a/src/distutils2/_backport/pkgutil.py b/src/distutils2/_backport/pkgutil.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/pkgutil.py
@@ -0,0 +1,791 @@
+"""Utilities to support packages."""
+
+# NOTE: This module must remain compatible with Python 2.3, as it is shared
+# by setuptools for distribution with Python 2.3 and up.
+
+import os
+import sys
+import imp
+import os.path
+from csv import reader as csv_reader
+from types import ModuleType
+from distutils2.errors import DistutilsError
+from distutils2.metadata import DistributionMetadata
+from distutils2.version import suggest_normalized_version
+
+__all__ = [
+    'get_importer', 'iter_importers', 'get_loader', 'find_loader',
+    'walk_packages', 'iter_modules',
+    'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
+    'Distribution', 'distinfo_dirname', 'get_distributions',
+    'get_distribution', 'get_file_users', 
+]
+
+def read_code(stream):
+    # This helper is needed in order for the PEP 302 emulation to
+    # correctly handle compiled files
+    import marshal
+
+    magic = stream.read(4)
+    if magic != imp.get_magic():
+        return None
+
+    stream.read(4) # Skip timestamp
+    return marshal.load(stream)
+
+
+def simplegeneric(func):
+    """Make a trivial single-dispatch generic function"""
+    registry = {}
+    def wrapper(*args, **kw):
+        ob = args[0]
+        try:
+            cls = ob.__class__
+        except AttributeError:
+            cls = type(ob)
+        try:
+            mro = cls.__mro__
+        except AttributeError:
+            try:
+                class cls(cls, object):
+                    pass
+                mro = cls.__mro__[1:]
+            except TypeError:
+                mro = object,   # must be an ExtensionClass or some such  :(
+        for t in mro:
+            if t in registry:
+                return registry[t](*args, **kw)
+        else:
+            return func(*args, **kw)
+    try:
+        wrapper.__name__ = func.__name__
+    except (TypeError, AttributeError):
+        pass    # Python 2.3 doesn't allow functions to be renamed
+
+    def register(typ, func=None):
+        if func is None:
+            return lambda f: register(typ, f)
+        registry[typ] = func
+        return func
+
+    wrapper.__dict__ = func.__dict__
+    wrapper.__doc__ = func.__doc__
+    wrapper.register = register
+    return wrapper
+
+
+def walk_packages(path=None, prefix='', onerror=None):
+    """Yields (module_loader, name, ispkg) for all modules recursively
+    on path, or, if path is None, all accessible modules.
+
+    'path' should be either None or a list of paths to look for
+    modules in.
+
+    'prefix' is a string to output on the front of every module name
+    on output.
+
+    Note that this function must import all *packages* (NOT all
+    modules!) on the given path, in order to access the __path__
+    attribute to find submodules.
+
+    'onerror' is a function which gets called with one argument (the
+    name of the package which was being imported) if any exception
+    occurs while trying to import a package.  If no onerror function is
+    supplied, ImportErrors are caught and ignored, while all other
+    exceptions are propagated, terminating the search.
+
+    Examples:
+
+    # list all modules python can access
+    walk_packages()
+
+    # list all submodules of ctypes
+    walk_packages(ctypes.__path__, ctypes.__name__+'.')
+    """
+
+    def seen(p, m={}):
+        if p in m:
+            return True
+        m[p] = True
+
+    for importer, name, ispkg in iter_modules(path, prefix):
+        yield importer, name, ispkg
+
+        if ispkg:
+            try:
+                __import__(name)
+            except ImportError:
+                if onerror is not None:
+                    onerror(name)
+            except Exception:
+                if onerror is not None:
+                    onerror(name)
+                else:
+                    raise
+            else:
+                path = getattr(sys.modules[name], '__path__', None) or []
+
+                # don't traverse path items we've seen before
+                path = [p for p in path if not seen(p)]
+
+                for item in walk_packages(path, name+'.', onerror):
+                    yield item
+
+
+def iter_modules(path=None, prefix=''):
+    """Yields (module_loader, name, ispkg) for all submodules on path,
+    or, if path is None, all top-level modules on sys.path.
+
+    'path' should be either None or a list of paths to look for
+    modules in.
+
+    'prefix' is a string to output on the front of every module name
+    on output.
+    """
+
+    if path is None:
+        importers = iter_importers()
+    else:
+        importers = map(get_importer, path)
+
+    yielded = {}
+    for i in importers:
+        for name, ispkg in iter_importer_modules(i, prefix):
+            if name not in yielded:
+                yielded[name] = 1
+                yield i, name, ispkg
+
+
+#@simplegeneric
+def iter_importer_modules(importer, prefix=''):
+    if not hasattr(importer, 'iter_modules'):
+        return []
+    return importer.iter_modules(prefix)
+
+iter_importer_modules = simplegeneric(iter_importer_modules)
+
+
+class ImpImporter:
+    """PEP 302 Importer that wraps Python's "classic" import algorithm
+
+    ImpImporter(dirname) produces a PEP 302 importer that searches that
+    directory.  ImpImporter(None) produces a PEP 302 importer that searches
+    the current sys.path, plus any modules that are frozen or built-in.
+
+    Note that ImpImporter does not currently support being used by placement
+    on sys.meta_path.
+    """
+
+    def __init__(self, path=None):
+        self.path = path
+
+    def find_module(self, fullname, path=None):
+        # Note: we ignore 'path' argument since it is only used via meta_path
+        subname = fullname.split(".")[-1]
+        if subname != fullname and self.path is None:
+            return None
+        if self.path is None:
+            path = None
+        else:
+            path = [os.path.realpath(self.path)]
+        try:
+            file, filename, etc = imp.find_module(subname, path)
+        except ImportError:
+            return None
+        return ImpLoader(fullname, file, filename, etc)
+
+    def iter_modules(self, prefix=''):
+        if self.path is None or not os.path.isdir(self.path):
+            return
+
+        yielded = {}
+        import inspect
+
+        filenames = os.listdir(self.path)
+        filenames.sort()  # handle packages before same-named modules
+
+        for fn in filenames:
+            modname = inspect.getmodulename(fn)
+            if modname=='__init__' or modname in yielded:
+                continue
+
+            path = os.path.join(self.path, fn)
+            ispkg = False
+
+            if not modname and os.path.isdir(path) and '.' not in fn:
+                modname = fn
+                for fn in os.listdir(path):
+                    subname = inspect.getmodulename(fn)
+                    if subname=='__init__':
+                        ispkg = True
+                        break
+                else:
+                    continue    # not a package
+
+            if modname and '.' not in modname:
+                yielded[modname] = 1
+                yield prefix + modname, ispkg
+
+
+class ImpLoader:
+    """PEP 302 Loader that wraps Python's "classic" import algorithm
+    """
+    code = source = None
+
+    def __init__(self, fullname, file, filename, etc):
+        self.file = file
+        self.filename = filename
+        self.fullname = fullname
+        self.etc = etc
+
+    def load_module(self, fullname):
+        self._reopen()
+        try:
+            mod = imp.load_module(fullname, self.file, self.filename, self.etc)
+        finally:
+            if self.file:
+                self.file.close()
+        # Note: we don't set __loader__ because we want the module to look
+        # normal; i.e. this is just a wrapper for standard import machinery
+        return mod
+
+    def get_data(self, pathname):
+        return open(pathname, "rb").read()
+
+    def _reopen(self):
+        if self.file and self.file.closed:
+            mod_type = self.etc[2]
+            if mod_type==imp.PY_SOURCE:
+                self.file = open(self.filename, 'rU')
+            elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
+                self.file = open(self.filename, 'rb')
+
+    def _fix_name(self, fullname):
+        if fullname is None:
+            fullname = self.fullname
+        elif fullname != self.fullname:
+            raise ImportError("Loader for module %s cannot handle "
+                              "module %s" % (self.fullname, fullname))
+        return fullname
+
+    def is_package(self, fullname):
+        fullname = self._fix_name(fullname)
+        return self.etc[2]==imp.PKG_DIRECTORY
+
+    def get_code(self, fullname=None):
+        fullname = self._fix_name(fullname)
+        if self.code is None:
+            mod_type = self.etc[2]
+            if mod_type==imp.PY_SOURCE:
+                source = self.get_source(fullname)
+                self.code = compile(source, self.filename, 'exec')
+            elif mod_type==imp.PY_COMPILED:
+                self._reopen()
+                try:
+                    self.code = read_code(self.file)
+                finally:
+                    self.file.close()
+            elif mod_type==imp.PKG_DIRECTORY:
+                self.code = self._get_delegate().get_code()
+        return self.code
+
+    def get_source(self, fullname=None):
+        fullname = self._fix_name(fullname)
+        if self.source is None:
+            mod_type = self.etc[2]
+            if mod_type==imp.PY_SOURCE:
+                self._reopen()
+                try:
+                    self.source = self.file.read()
+                finally:
+                    self.file.close()
+            elif mod_type==imp.PY_COMPILED:
+                if os.path.exists(self.filename[:-1]):
+                    f = open(self.filename[:-1], 'rU')
+                    self.source = f.read()
+                    f.close()
+            elif mod_type==imp.PKG_DIRECTORY:
+                self.source = self._get_delegate().get_source()
+        return self.source
+
+
+    def _get_delegate(self):
+        return ImpImporter(self.filename).find_module('__init__')
+
+    def get_filename(self, fullname=None):
+        fullname = self._fix_name(fullname)
+        mod_type = self.etc[2]
+        if self.etc[2]==imp.PKG_DIRECTORY:
+            return self._get_delegate().get_filename()
+        elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
+            return self.filename
+        return None
+
+
+try:
+    import zipimport
+    from zipimport import zipimporter
+
+    def iter_zipimport_modules(importer, prefix=''):
+        dirlist = zipimport._zip_directory_cache[importer.archive].keys()
+        dirlist.sort()
+        _prefix = importer.prefix
+        plen = len(_prefix)
+        yielded = {}
+        import inspect
+        for fn in dirlist:
+            if not fn.startswith(_prefix):
+                continue
+
+            fn = fn[plen:].split(os.sep)
+
+            if len(fn)==2 and fn[1].startswith('__init__.py'):
+                if fn[0] not in yielded:
+                    yielded[fn[0]] = 1
+                    yield fn[0], True
+
+            if len(fn)!=1:
+                continue
+
+            modname = inspect.getmodulename(fn[0])
+            if modname=='__init__':
+                continue
+
+            if modname and '.' not in modname and modname not in yielded:
+                yielded[modname] = 1
+                yield prefix + modname, False
+
+    iter_importer_modules.register(zipimporter, iter_zipimport_modules)
+
+except ImportError:
+    pass
+
+
+def get_importer(path_item):
+    """Retrieve a PEP 302 importer for the given path item
+
+    The returned importer is cached in sys.path_importer_cache
+    if it was newly created by a path hook.
+
+    If there is no importer, a wrapper around the basic import
+    machinery is returned. This wrapper is never inserted into
+    the importer cache (None is inserted instead).
+
+    The cache (or part of it) can be cleared manually if a
+    rescan of sys.path_hooks is necessary.
+    """
+    try:
+        importer = sys.path_importer_cache[path_item]
+    except KeyError:
+        for path_hook in sys.path_hooks:
+            try:
+                importer = path_hook(path_item)
+                break
+            except ImportError:
+                pass
+        else:
+            importer = None
+        sys.path_importer_cache.setdefault(path_item, importer)
+
+    if importer is None:
+        try:
+            importer = ImpImporter(path_item)
+        except ImportError:
+            importer = None
+    return importer
+
+
+def iter_importers(fullname=""):
+    """Yield PEP 302 importers for the given module name
+
+    If fullname contains a '.', the importers will be for the package
+    containing fullname, otherwise they will be importers for sys.meta_path,
+    sys.path, and Python's "classic" import machinery, in that order.  If
+    the named module is in a package, that package is imported as a side
+    effect of invoking this function.
+
+    Non PEP 302 mechanisms (e.g. the Windows registry) used by the
+    standard import machinery to find files in alternative locations
+    are partially supported, but are searched AFTER sys.path. Normally,
+    these locations are searched BEFORE sys.path, preventing sys.path
+    entries from shadowing them.
+
+    For this to cause a visible difference in behaviour, there must
+    be a module or package name that is accessible via both sys.path
+    and one of the non PEP 302 file system mechanisms. In this case,
+    the emulation will find the former version, while the builtin
+    import mechanism will find the latter.
+
+    Items of the following types can be affected by this discrepancy:
+        imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
+    """
+    if fullname.startswith('.'):
+        raise ImportError("Relative module names not supported")
+    if '.' in fullname:
+        # Get the containing package's __path__
+        pkg = '.'.join(fullname.split('.')[:-1])
+        if pkg not in sys.modules:
+            __import__(pkg)
+        path = getattr(sys.modules[pkg], '__path__', None) or []
+    else:
+        for importer in sys.meta_path:
+            yield importer
+        path = sys.path
+    for item in path:
+        yield get_importer(item)
+    if '.' not in fullname:
+        yield ImpImporter()
+
+def get_loader(module_or_name):
+    """Get a PEP 302 "loader" object for module_or_name
+
+    If the module or package is accessible via the normal import
+    mechanism, a wrapper around the relevant part of that machinery
+    is returned.  Returns None if the module cannot be found or imported.
+    If the named module is not already imported, its containing package
+    (if any) is imported, in order to establish the package __path__.
+
+    This function uses iter_importers(), and is thus subject to the same
+    limitations regarding platform-specific special import locations such
+    as the Windows registry.
+    """
+    if module_or_name in sys.modules:
+        module_or_name = sys.modules[module_or_name]
+    if isinstance(module_or_name, ModuleType):
+        module = module_or_name
+        loader = getattr(module, '__loader__', None)
+        if loader is not None:
+            return loader
+        fullname = module.__name__
+    else:
+        fullname = module_or_name
+    return find_loader(fullname)
+
+def find_loader(fullname):
+    """Find a PEP 302 "loader" object for fullname
+
+    If fullname contains dots, path must be the containing package's __path__.
+    Returns None if the module cannot be found or imported. This function uses
+    iter_importers(), and is thus subject to the same limitations regarding
+    platform-specific special import locations such as the Windows registry.
+    """
+    for importer in iter_importers(fullname):
+        loader = importer.find_module(fullname)
+        if loader is not None:
+            return loader
+
+    return None
+
+
+def extend_path(path, name):
+    """Extend a package's path.
+
+    Intended use is to place the following code in a package's __init__.py:
+
+        from pkgutil import extend_path
+        __path__ = extend_path(__path__, __name__)
+
+    This will add to the package's __path__ all subdirectories of
+    directories on sys.path named after the package.  This is useful
+    if one wants to distribute different parts of a single logical
+    package as multiple directories.
+
+    It also looks for *.pkg files beginning where * matches the name
+    argument.  This feature is similar to *.pth files (see site.py),
+    except that it doesn't special-case lines starting with 'import'.
+    A *.pkg file is trusted at face value: apart from checking for
+    duplicates, all entries found in a *.pkg file are added to the
+    path, regardless of whether they are exist the filesystem.  (This
+    is a feature.)
+
+    If the input path is not a list (as is the case for frozen
+    packages) it is returned unchanged.  The input path is not
+    modified; an extended copy is returned.  Items are only appended
+    to the copy at the end.
+
+    It is assumed that sys.path is a sequence.  Items of sys.path that
+    are not (unicode or 8-bit) strings referring to existing
+    directories are ignored.  Unicode items of sys.path that cause
+    errors when used as filenames may cause this function to raise an
+    exception (in line with os.path.isdir() behavior).
+    """
+
+    if not isinstance(path, list):
+        # This could happen e.g. when this is called from inside a
+        # frozen package.  Return the path unchanged in that case.
+        return path
+
+    pname = os.path.join(*name.split('.')) # Reconstitute as relative path
+    # Just in case os.extsep != '.'
+    sname = os.extsep.join(name.split('.'))
+    sname_pkg = sname + os.extsep + "pkg"
+    init_py = "__init__" + os.extsep + "py"
+
+    path = path[:] # Start with a copy of the existing path
+
+    for dir in sys.path:
+        if not isinstance(dir, basestring) or not os.path.isdir(dir):
+            continue
+        subdir = os.path.join(dir, pname)
+        # XXX This may still add duplicate entries to path on
+        # case-insensitive filesystems
+        initfile = os.path.join(subdir, init_py)
+        if subdir not in path and os.path.isfile(initfile):
+            path.append(subdir)
+        # XXX Is this the right thing for subpackages like zope.app?
+        # It looks for a file named "zope.app.pkg"
+        pkgfile = os.path.join(dir, sname_pkg)
+        if os.path.isfile(pkgfile):
+            try:
+                f = open(pkgfile)
+            except IOError, msg:
+                sys.stderr.write("Can't open %s: %s\n" %
+                                 (pkgfile, msg))
+            else:
+                for line in f:
+                    line = line.rstrip('\n')
+                    if not line or line.startswith('#'):
+                        continue
+                    path.append(line) # Don't check for existence!
+                f.close()
+
+    return path
+
+def get_data(package, resource):
+    """Get a resource from a package.
+
+    This is a wrapper round the PEP 302 loader get_data API. The package
+    argument should be the name of a package, in standard module format
+    (foo.bar). The resource argument should be in the form of a relative
+    filename, using '/' as the path separator. The parent directory name '..'
+    is not allowed, and nor is a rooted name (starting with a '/').
+
+    The function returns a binary string, which is the contents of the
+    specified resource.
+
+    For packages located in the filesystem, which have already been imported,
+    this is the rough equivalent of
+
+        d = os.path.dirname(sys.modules[package].__file__)
+        data = open(os.path.join(d, resource), 'rb').read()
+
+    If the package cannot be located or loaded, or it uses a PEP 302 loader
+    which does not support get_data(), then None is returned.
+    """
+
+    loader = get_loader(package)
+    if loader is None or not hasattr(loader, 'get_data'):
+        return None
+    mod = sys.modules.get(package) or loader.load_module(package)
+    if mod is None or not hasattr(mod, '__file__'):
+        return None
+
+    # Modify the resource name to be compatible with the loader.get_data
+    # signature - an os.path format "filename" starting with the dirname of
+    # the package's __file__
+    parts = resource.split('/')
+    parts.insert(0, os.path.dirname(mod.__file__))
+    resource_name = os.path.join(*parts)
+    return loader.get_data(resource_name)
+
+##########################
+# PEP 376 Implementation #
+##########################
+
+DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',)
+
+class Distribution(object):
+    """Created with the *path* of the ``.dist-info`` directory provided to the
+    constructor. It reads the metadata contained in METADATA when it is
+    instantiated."""
+
+    # Attribute documenting for Sphinx style documentation, see for more info:
+    #   http://sphinx.pocoo.org/ext/autodoc.html#dir-autoattribute
+    name = ''
+    """The name of the distribution."""
+    metadata = None
+    """A :class:`distutils2.metadata.DistributionMetadata` instance loaded with 
+    the distribution's METADATA file."""
+    requested = False
+    """A boolean that indicates whether the REQUESTED metadata file is present
+    (in other words, whether the package was installed by user request)."""
+
+    def __init__(self, path):
+        self.path = path
+        metadata_path = os.path.join(path, 'METADATA')
+        self.metadata = DistributionMetadata(path=metadata_path)
+        self.name = self.metadata['name']
+
+    def _get_records(self, local=False):
+        RECORD = os.path.join(self.path, 'RECORD')
+        record_reader = csv_reader(open(RECORD, 'rb'), delimiter=',')
+        for row in record_reader:
+            path, md5, size = row[:] + [ None for i in xrange(len(row), 3) ]
+            if local:
+                path = path.replace('/', os.sep)
+                path = os.path.join(sys.prefix, path)
+            yield path, md5, size
+
+    def get_installed_files(self, local=False):
+        """
+        Iterates over the RECORD entries and returns a tuple (path, md5, size)
+        for each line. If *local* is ``True``, the returned path is transformed
+        into a local absolute path. Otherwise the raw value from RECORD is
+        returned.
+
+        A local absolute path is an absolute path in which occurrences of
+        ``'/'`` have been replaced by the system separator given by ``os.sep``.
+
+        :parameter local: flag to say if the path should be returned a local
+                          absolute path
+        :type local: boolean
+        :returns: iterator of (path, md5, size)
+        """
+        return self._get_records(local)
+
+
+    def uses(self, path):
+        """
+        Returns ``True`` if path is listed in RECORD. *path* can be a local 
+        absolute path or a relative ``'/'``-separated path.
+
+        :rtype: boolean
+        """
+        for p, md5, size in self._get_records():
+            local_absolute = os.path.join(sys.prefix, p)
+            if path == p or path == local_absolute:
+                return True
+        return False
+
+    def get_distinfo_file(self, path, binary=False):
+        """
+        Returns a file located under the ``.dist-info`` directory. Returns a
+        ``file`` instance for the file pointed by *path*.
+
+        :parameter path: a ``'/'``-separated path relative to the ``.dist-info``
+                         directory or an absolute path; If *path* is an absolute 
+                         path and doesn't start with the ``.dist-info``
+                         directory path, a :class:`DistutilsError` is raised
+        :type path: string
+        :parameter binary: If *binary* is ``True``, opens the file in read-only
+                           binary mode (rb), otherwise opens it in read-only
+                           mode (r).
+        :rtype: file object
+        """
+        open_flags = 'r'
+        if binary:
+            open_flags += 'b'
+
+        # Check if it is an absolute path
+        if path.find(os.sep) >= 0:
+            # it's an absolute path?
+            distinfo_dirname, path = path.split(os.sep)[-2:]
+            if distinfo_dirname != self.path.split(os.sep)[-1]:
+                raise DistutilsError("Requested dist-info file does not "
+                    "belong to the %s distribution. '%s' was requested." \
+                    % (self.name, os.sep.join([distinfo_dirname, path])))
+
+        # The file must be relative
+        if path not in DIST_FILES:
+            raise DistutilsError("Requested an invalid dist-info file: "
+                "%s" % path)
+
+        # Convert the relative path back to absolute
+        path = os.path.join(self.path, path)
+        return open(path, open_flags)
+
+    def get_distinfo_files(self, local=False):
+        """
+        Iterates over the RECORD entries and returns paths for each line if the 
+        path is pointing to a file located in the ``.dist-info`` directory or 
+        one of its subdirectories.
+
+        :parameter local: If *local* is ``True``, each returned path is
+                          transformed into a local absolute path. Otherwise the
+                          raw value from RECORD is returned.
+        :type local: boolean
+        :returns: iterator of paths
+        """
+        for path, md5, size in self._get_records(local):
+            yield path
+
+
+def _normalize_dist_name(name):
+    """Returns a normalized name from the given *name*.
+    :rtype: string"""
+    return name.replace('-', '_')
+
+def distinfo_dirname(name, version):
+    """
+    The *name* and *version* parameters are converted into their
+    filename-escaped form, i.e. any ``'-'`` characters are replaced with ``'_'``
+    other than the one in ``'dist-info'`` and the one separating the name from 
+    the version number.
+
+    :parameter name: is converted to a standard distribution name by replacing
+                     any runs of non- alphanumeric characters with a single
+                     ``'-'``.
+    :type name: string
+    :parameter version: is converted to a standard version string. Spaces become
+                        dots, and all other non-alphanumeric characters (except
+                        dots) become dashes, with runs of multiple dashes
+                        condensed to a single dash.
+    :type version: string
+    :returns: directory name
+    :rtype: string"""
+    file_extension = '.dist-info'
+    name = _normalize_dist_name(name)
+    normalized_version = suggest_normalized_version(version)
+    # Because this is a lookup procedure, something will be returned even if
+    #   it is a version that cannot be normalized
+    if normalized_version is None:
+        # Unable to achieve normality?
+        normalized_version = version
+    return '-'.join([name, normalized_version]) + file_extension
+
+def get_distributions():
+    """
+    Provides an iterator that looks for ``.dist-info`` directories in
+    ``sys.path`` and returns :class:`Distribution` instances for each one of
+    them.
+
+    :rtype: iterator of :class:`Distribution` instances"""
+    for path in sys.path:
+        realpath = os.path.realpath(path)
+        if not os.path.isdir(realpath):
+            continue
+        for dir in os.listdir(realpath):
+            if dir.endswith('.dist-info'):
+                dist = Distribution(os.path.join(realpath, dir))
+                yield dist
+
+def get_distribution(name):
+    """
+    Scans all elements in ``sys.path`` and looks for all directories ending with
+    ``.dist-info``. Returns a :class:`Distribution` corresponding to the 
+    ``.dist-info`` directory that contains the METADATA that matches *name* for
+    the *name* metadata.
+
+    This function only returns the first result founded, as no more than one
+    value is expected. If the directory is not found, ``None`` is returned.
+
+    :rtype: :class:`Distribution` or None"""
+    found = None
+    for dist in get_distributions():
+        if dist.name == name:
+            found = dist
+            break
+    return found
+
+def get_file_users(path):
+    """
+    Iterates over all distributions to find out which distributions uses
+    *path*.
+
+    :parameter path: can be a local absolute path or a relative
+                     ``'/'``-separated path.
+    :type path: string
+    :rtype: iterator of :class:`Distribution` instances"""
+    for dist in get_distributions():
+        if dist.uses(path):
+            yield dist
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA
@@ -0,0 +1,6 @@
+Metadata-Version: 1.2
+Name: choxie
+Version: 2.0.0.9
+Summary: Chocolate with a kick!
+Requires-Dist: towel-stuff (0.1)
+Provides-Dist: truffles (1.0)
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+from towel_stuff import Towel
+
+class Chocolate(object):
+    """A piece of chocolate."""
+
+    def wrap_with_towel(self):
+        towel = Towel()
+        towel.wrap(self)
+        return towel
diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from choxie.chocolate import Chocolate
+
+class Truffle(Chocolate):
+    """A truffle."""
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA
@@ -0,0 +1,3 @@
+Metadata-Version: 1.2
+Name: grammar
+Version: 1.0a4
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/RECORD
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+
diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+from random import randint
+
+def is_valid_grammar(sentence):
+    if randint(0, 10) < 2:
+        return False
+    else:
+        return True
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA
@@ -0,0 +1,3 @@
+Metadata-Version: 1.2
+Name: towel-stuff
+Version: 0.1
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED
new file mode 100644
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+class Towel(object):
+    """A towel, that one should never be without."""
+
+    def __init__(self, color='tie-dye'):
+        self.color = color
+        self.wrapped_obj = None
+
+    def wrap(self, obj):
+        """Wrap an object up in our towel."""
+        self.wrapped_obj = obj
+
+    def unwrap(self):
+        """Unwrap whatever is in our towel and return whatever it is."""
+        obj = self.wrapped_obj
+        self.wrapped_obj = None
+        return obj
diff --git a/src/distutils2/_backport/tests/test_pkgutil.py b/src/distutils2/_backport/tests/test_pkgutil.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/_backport/tests/test_pkgutil.py
@@ -0,0 +1,272 @@
+# -*- coding: utf-8 -*-
+"""Tests for PEP 376 pkgutil functionality"""
+import unittest2
+import sys
+import os
+import csv
+import hashlib
+
+from test.test_support import run_unittest, TESTFN
+
+import distutils2._backport.pkgutil
+
+# TODO Add a test for getting a distribution that is provided by another
+#   distribution.
+
+# TODO Add a test for absolute pathed RECORD items (e.g. /etc/myapp/config.ini)
+
+class TestPkgUtilDistribution(unittest2.TestCase):
+    """Tests the pkgutil.Distribution class"""
+
+    def setUp(self):
+        super(TestPkgUtilDistribution, self).setUp()
+
+        self.fake_dists_path = os.path.abspath(
+            os.path.join(os.path.dirname(__file__), 'fake_dists'))
+        self.distinfo_dirs = [ os.path.join(self.fake_dists_path, dir)
+            for dir in os.listdir(self.fake_dists_path)
+            if dir.endswith('.dist-info')
+            ]
+
+        def get_hexdigest(file):
+            md5_hash = hashlib.md5()
+            md5_hash.update(open(file).read())
+            return md5_hash.hexdigest()
+        def record_pieces(file):
+            path = os.path.relpath(file, sys.prefix)
+            digest = get_hexdigest(file)
+            size = os.path.getsize(file)
+            return [path, digest, size]
+
+        self.records = {}
+        for distinfo_dir in self.distinfo_dirs:
+            # Setup the RECORD file for this dist
+            record_file = os.path.join(distinfo_dir, 'RECORD')
+            record_writer = csv.writer(open(record_file, 'w'), delimiter=',',
+                quoting=csv.QUOTE_NONE)
+            dist_location = distinfo_dir.replace('.dist-info', '')
+
+            for path, dirs, files in os.walk(dist_location):
+                for f in files:
+                    record_writer.writerow(record_pieces(os.path.join(path, f)))
+            for file in ['INSTALLER', 'METADATA', 'REQUESTED']:
+                record_writer.writerow(record_pieces(
+                    os.path.join(distinfo_dir, file)))
+            record_writer.writerow([os.path.relpath(record_file, sys.prefix)])
+            del record_writer # causes the RECORD file to close
+            record_reader = csv.reader(open(record_file, 'rb'))
+            record_data = []
+            for row in record_reader:
+                path, md5, size = row[:] + [ None for i in xrange(len(row), 3) ]
+                record_data.append([path, (md5, size,)])
+            self.records[distinfo_dir] = dict(record_data)
+
+    def tearDown(self):
+        self.records = None
+        for distinfo_dir in self.distinfo_dirs:
+            record_file = os.path.join(distinfo_dir, 'RECORD')
+            open(record_file, 'w').close()
+        super(TestPkgUtilDistribution, self).tearDown()
+
+    def test_instantiation(self):
+        """Test the Distribution class's instantiation provides us with usable
+        attributes."""
+        # Import the Distribution class
+        from distutils2._backport.pkgutil import distinfo_dirname, Distribution
+
+        here = os.path.abspath(os.path.dirname(__file__))
+        name = 'choxie'
+        version = '2.0.0.9'
+        dist_path = os.path.join(here, 'fake_dists',
+            distinfo_dirname(name, version))
+        dist = Distribution(dist_path)
+
+        self.assertEqual(dist.name, name)
+        from distutils2.metadata import DistributionMetadata
+        self.assertTrue(isinstance(dist.metadata, DistributionMetadata))
+        self.assertEqual(dist.metadata['version'], version)
+        self.assertTrue(isinstance(dist.requested, type(bool())))
+
+    def test_installed_files(self):
+        """Test the iteration of installed files."""
+        # Test the distribution's installed files
+        from distutils2._backport.pkgutil import Distribution
+        for distinfo_dir in self.distinfo_dirs:
+            dist = Distribution(distinfo_dir)
+            for path, md5, size in dist.get_installed_files():
+                record_data = self.records[dist.path]
+                self.assertTrue(path in record_data.keys())
+                self.assertEqual(md5, record_data[path][0])
+                self.assertEqual(size, record_data[path][1])
+
+    def test_uses(self):
+        """Test to determine if a distribution uses a specified file."""
+        # Criteria to test against
+        distinfo_name = 'grammar-1.0a4'
+        distinfo_dir = os.path.join(self.fake_dists_path,
+            distinfo_name + '.dist-info')
+        true_path = [self.fake_dists_path, distinfo_name, 'grammar', 'utils.py']
+        true_path = os.path.relpath(os.path.join(*true_path), sys.prefix)
+        false_path = [self.fake_dists_path, 'towel_stuff-0.1', 'towel_stuff',
+            '__init__.py']
+        false_path = os.path.relpath(os.path.join(*false_path), sys.prefix)
+
+        # Test if the distribution uses the file in question
+        from distutils2._backport.pkgutil import Distribution
+        dist = Distribution(distinfo_dir)
+        self.assertTrue(dist.uses(true_path))
+        self.assertFalse(dist.uses(false_path))
+
+    def test_get_distinfo_file(self):
+        """Test the retrieval of dist-info file objects."""
+        from distutils2._backport.pkgutil import Distribution
+        distinfo_name = 'choxie-2.0.0.9'
+        other_distinfo_name = 'grammar-1.0a4'
+        distinfo_dir = os.path.join(self.fake_dists_path,
+            distinfo_name + '.dist-info')
+        dist = Distribution(distinfo_dir)
+        # Test for known good file matches
+        distinfo_files = [
+            # Relative paths
+            'INSTALLER', 'METADATA',
+            # Absolute paths
+            os.path.join(distinfo_dir, 'RECORD'),
+            os.path.join(distinfo_dir, 'REQUESTED'),
+            ]
+
+        for distfile in distinfo_files:
+            value = dist.get_distinfo_file(distfile)
+            self.assertTrue(isinstance(value, file))
+            # Is it the correct file?
+            self.assertEqual(value.name, os.path.join(distinfo_dir, distfile))
+
+        from distutils2.errors import DistutilsError
+        # Test an absolute path that is part of another distributions dist-info
+        other_distinfo_file = os.path.join(self.fake_dists_path,
+            other_distinfo_name + '.dist-info', 'REQUESTED')
+        self.assertRaises(DistutilsError, dist.get_distinfo_file,
+            other_distinfo_file)
+        # Test for a file that does not exist and should not exist
+        self.assertRaises(DistutilsError, dist.get_distinfo_file, 'ENTRYPOINTS')
+
+    def test_get_distinfo_files(self):
+        """Test for the iteration of RECORD path entries."""
+        from distutils2._backport.pkgutil import Distribution
+        distinfo_name = 'towel_stuff-0.1'
+        distinfo_dir = os.path.join(self.fake_dists_path,
+            distinfo_name + '.dist-info')
+        dist = Distribution(distinfo_dir)
+        # Test for the iteration of the raw path
+        distinfo_record_paths = self.records[distinfo_dir].keys()
+        found = [ path for path in dist.get_distinfo_files() ]
+        self.assertEqual(sorted(found), sorted(distinfo_record_paths))
+        # Test for the iteration of local absolute paths
+        distinfo_record_paths = [ os.path.join(sys.prefix, path)
+            for path in self.records[distinfo_dir].keys()
+            ]
+        found = [ path for path in dist.get_distinfo_files(local=True) ]
+        self.assertEqual(sorted(found), sorted(distinfo_record_paths))
+
+
+class TestPkgUtilFunctions(unittest2.TestCase):
+    """Tests for the new functionality added in PEP 376."""
+
+    def setUp(self):
+        super(TestPkgUtilFunctions, self).setUp()
+        # Setup the path environment with our fake distributions
+        current_path = os.path.abspath(os.path.dirname(__file__))
+        self.sys_path = sys.path[:]
+        self.fake_dists_path = os.path.join(current_path, 'fake_dists')
+        sys.path[0:0] = [self.fake_dists_path]
+
+    def tearDown(self):
+        super(TestPkgUtilFunctions, self).tearDown()
+        sys.path[:] = self.sys_path
+
+    def test_distinfo_dirname(self):
+        """Given a name and a version, we expect the distinfo_dirname function
+        to return a standard distribution information directory name."""
+
+        items = [ # (name, version, standard_dirname)
+            # Test for a very simple single word name and decimal version number
+            ('docutils', '0.5', 'docutils-0.5.dist-info'),
+            # Test for another except this time with a '-' in the name, which
+            #   needs to be transformed during the name lookup
+            ('python-ldap', '2.5', 'python_ldap-2.5.dist-info'),
+            # Test for both '-' in the name and a funky version number
+            ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'),
+            ]
+
+        # Import the function in question
+        from distutils2._backport.pkgutil import distinfo_dirname
+
+        # Loop through the items to validate the results
+        for name, version, standard_dirname in items:
+            dirname = distinfo_dirname(name, version)
+            self.assertEqual(dirname, standard_dirname)
+
+    def test_get_distributions(self):
+        """Lookup all distributions found in the ``sys.path``."""
+        # This test could potentially pick up other installed distributions
+        fake_dists = [('grammar', '1.0a4'), ('choxie', '2.0.0.9'),
+            ('towel-stuff', '0.1')]
+        found_dists = []
+
+        # Import the function in question
+        from distutils2._backport.pkgutil import get_distributions, Distribution
+
+        # Verify the fake dists have been found.
+        dists = [ dist for dist in get_distributions() ]
+        for dist in dists:
+            if not isinstance(dist, Distribution):
+                self.fail("item received was not a Distribution instance: "
+                    "%s" % type(dist))
+            if dist.name in dict(fake_dists).keys():
+                found_dists.append((dist.name, dist.metadata['version'],))
+            # otherwise we don't care what other distributions are found
+
+        # Finally, test that we found all that we were looking for
+        self.assertListEqual(sorted(found_dists), sorted(fake_dists))
+
+    def test_get_distribution(self):
+        """Test for looking up a distribution by name."""
+        # Test the lookup of the towel-stuff distribution
+        name = 'towel-stuff' # Note: This is different from the directory name
+
+        # Import the function in question
+        from distutils2._backport.pkgutil import get_distribution, Distribution
+
+        # Lookup the distribution
+        dist = get_distribution(name)
+        self.assertTrue(isinstance(dist, Distribution))
+        self.assertEqual(dist.name, name)
+
+        # Verify that an unknown distribution returns None
+        self.assertEqual(None, get_distribution('bogus'))
+
+        # Verify partial name matching doesn't work
+        self.assertEqual(None, get_distribution('towel'))
+
+    def test_get_file_users(self):
+        """Test the iteration of distributions that use a file."""
+        from distutils2._backport.pkgutil import get_file_users, Distribution
+        name = 'towel_stuff-0.1'
+        path = os.path.join(self.fake_dists_path, name,
+            'towel_stuff', '__init__.py')
+        for dist in get_file_users(path):
+            self.assertTrue(isinstance(dist, Distribution))
+            self.assertEqual(dist.name, name)
+
+
+def test_suite():
+    suite = unittest2.TestSuite()
+    testcase_loader = unittest2.loader.defaultTestLoader.loadTestsFromTestCase
+    suite.addTest(testcase_loader(TestPkgUtilFunctions))
+    suite.addTest(testcase_loader(TestPkgUtilDistribution))
+    return suite
+
+def test_main():
+    run_unittest(test_suite())
+
+if __name__ == "__main__":
+    test_main()
diff --git a/src/distutils2/mkpkg.py b/src/distutils2/mkpkg.py
--- a/src/distutils2/mkpkg.py
+++ b/src/distutils2/mkpkg.py
@@ -73,774 +73,776 @@
 }
 
 troveList = [
-      'Development Status :: 1 - Planning',
-		'Development Status :: 2 - Pre-Alpha',
-		'Development Status :: 3 - Alpha',
-		'Development Status :: 4 - Beta',
-		'Development Status :: 5 - Production/Stable',
-		'Development Status :: 6 - Mature',
-		'Development Status :: 7 - Inactive',
-		'Environment :: Console',
-		'Environment :: Console :: Curses',
-		'Environment :: Console :: Framebuffer',
-		'Environment :: Console :: Newt',
-		'Environment :: Console :: svgalib',
-		'Environment :: Handhelds/PDA\'s',
-		'Environment :: MacOS X',
-		'Environment :: MacOS X :: Aqua',
-		'Environment :: MacOS X :: Carbon',
-		'Environment :: MacOS X :: Cocoa',
-		'Environment :: No Input/Output (Daemon)',
-		'Environment :: Other Environment',
-		'Environment :: Plugins',
-		'Environment :: Web Environment',
-		'Environment :: Web Environment :: Buffet',
-		'Environment :: Web Environment :: Mozilla',
-		'Environment :: Web Environment :: ToscaWidgets',
-		'Environment :: Win32 (MS Windows)',
-		'Environment :: X11 Applications',
-		'Environment :: X11 Applications :: Gnome',
-		'Environment :: X11 Applications :: GTK',
-		'Environment :: X11 Applications :: KDE',
-		'Environment :: X11 Applications :: Qt',
-		'Framework :: BFG',
-		'Framework :: Buildout',
-		'Framework :: Chandler',
-		'Framework :: CubicWeb',
-		'Framework :: Django',
-		'Framework :: IDLE',
-		'Framework :: Paste',
-		'Framework :: Plone',
-		'Framework :: Pylons',
-		'Framework :: Setuptools Plugin',
-		'Framework :: Trac',
-		'Framework :: TurboGears',
-		'Framework :: TurboGears :: Applications',
-		'Framework :: TurboGears :: Widgets',
-		'Framework :: Twisted',
-		'Framework :: ZODB',
-		'Framework :: Zope2',
-		'Framework :: Zope3',
-		'Intended Audience :: Customer Service',
-		'Intended Audience :: Developers',
-		'Intended Audience :: Education',
-		'Intended Audience :: End Users/Desktop',
-		'Intended Audience :: Financial and Insurance Industry',
-		'Intended Audience :: Healthcare Industry',
-		'Intended Audience :: Information Technology',
-		'Intended Audience :: Legal Industry',
-		'Intended Audience :: Manufacturing',
-		'Intended Audience :: Other Audience',
-		'Intended Audience :: Religion',
-		'Intended Audience :: Science/Research',
-		'Intended Audience :: System Administrators',
-		'Intended Audience :: Telecommunications Industry',
-		'License :: Aladdin Free Public License (AFPL)',
-		'License :: DFSG approved',
-		'License :: Eiffel Forum License (EFL)',
-		'License :: Free For Educational Use',
-		'License :: Free For Home Use',
-		'License :: Free for non-commercial use',
-		'License :: Freely Distributable',
-		'License :: Free To Use But Restricted',
-		'License :: Freeware',
-		'License :: Netscape Public License (NPL)',
-		'License :: Nokia Open Source License (NOKOS)',
-		'License :: OSI Approved',
-		'License :: OSI Approved :: Academic Free License (AFL)',
-		'License :: OSI Approved :: Apache Software License',
-		'License :: OSI Approved :: Apple Public Source License',
-		'License :: OSI Approved :: Artistic License',
-		'License :: OSI Approved :: Attribution Assurance License',
-		'License :: OSI Approved :: BSD License',
-		'License :: OSI Approved :: Common Public License',
-		'License :: OSI Approved :: Eiffel Forum License',
-		'License :: OSI Approved :: European Union Public Licence 1.0 (EUPL 1.0)',
-		'License :: OSI Approved :: European Union Public Licence 1.1 (EUPL 1.1)',
-		'License :: OSI Approved :: GNU Affero General Public License v3',
-		'License :: OSI Approved :: GNU Free Documentation License (FDL)',
-		'License :: OSI Approved :: GNU General Public License (GPL)',
-		'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
-		'License :: OSI Approved :: IBM Public License',
-		'License :: OSI Approved :: Intel Open Source License',
-		'License :: OSI Approved :: ISC License (ISCL)',
-		'License :: OSI Approved :: Jabber Open Source License',
-		'License :: OSI Approved :: MIT License',
-		'License :: OSI Approved :: MITRE Collaborative Virtual Workspace License (CVW)',
-		'License :: OSI Approved :: Motosoto License',
-		'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)',
-		'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)',
-		'License :: OSI Approved :: Nethack General Public License',
-		'License :: OSI Approved :: Nokia Open Source License',
-		'License :: OSI Approved :: Open Group Test Suite License',
-		'License :: OSI Approved :: Python License (CNRI Python License)',
-		'License :: OSI Approved :: Python Software Foundation License',
-		'License :: OSI Approved :: Qt Public License (QPL)',
-		'License :: OSI Approved :: Ricoh Source Code Public License',
-		'License :: OSI Approved :: Sleepycat License',
-		'License :: OSI Approved :: Sun Industry Standards Source License (SISSL)',
-		'License :: OSI Approved :: Sun Public License',
-		'License :: OSI Approved :: University of Illinois/NCSA Open Source License',
-		'License :: OSI Approved :: Vovida Software License 1.0',
-		'License :: OSI Approved :: W3C License',
-		'License :: OSI Approved :: X.Net License',
-		'License :: OSI Approved :: zlib/libpng License',
-		'License :: OSI Approved :: Zope Public License',
-		'License :: Other/Proprietary License',
-		'License :: Public Domain',
-		'License :: Repoze Public License',
-		'Natural Language :: Afrikaans',
-		'Natural Language :: Arabic',
-		'Natural Language :: Bengali',
-		'Natural Language :: Bosnian',
-		'Natural Language :: Bulgarian',
-		'Natural Language :: Catalan',
-		'Natural Language :: Chinese (Simplified)',
-		'Natural Language :: Chinese (Traditional)',
-		'Natural Language :: Croatian',
-		'Natural Language :: Czech',
-		'Natural Language :: Danish',
-		'Natural Language :: Dutch',
-		'Natural Language :: English',
-		'Natural Language :: Esperanto',
-		'Natural Language :: Finnish',
-		'Natural Language :: French',
-		'Natural Language :: German',
-		'Natural Language :: Greek',
-		'Natural Language :: Hebrew',
-		'Natural Language :: Hindi',
-		'Natural Language :: Hungarian',
-		'Natural Language :: Icelandic',
-		'Natural Language :: Indonesian',
-		'Natural Language :: Italian',
-		'Natural Language :: Japanese',
-		'Natural Language :: Javanese',
-		'Natural Language :: Korean',
-		'Natural Language :: Latin',
-		'Natural Language :: Latvian',
-		'Natural Language :: Macedonian',
-		'Natural Language :: Malay',
-		'Natural Language :: Marathi',
-		'Natural Language :: Norwegian',
-		'Natural Language :: Panjabi',
-		'Natural Language :: Persian',
-		'Natural Language :: Polish',
-		'Natural Language :: Portuguese',
-		'Natural Language :: Portuguese (Brazilian)',
-		'Natural Language :: Romanian',
-		'Natural Language :: Russian',
-		'Natural Language :: Serbian',
-		'Natural Language :: Slovak',
-		'Natural Language :: Slovenian',
-		'Natural Language :: Spanish',
-		'Natural Language :: Swedish',
-		'Natural Language :: Tamil',
-		'Natural Language :: Telugu',
-		'Natural Language :: Thai',
-		'Natural Language :: Turkish',
-		'Natural Language :: Ukranian',
-		'Natural Language :: Urdu',
-		'Natural Language :: Vietnamese',
-		'Operating System :: BeOS',
-		'Operating System :: MacOS',
-		'Operating System :: MacOS :: MacOS 9',
-		'Operating System :: MacOS :: MacOS X',
-		'Operating System :: Microsoft',
-		'Operating System :: Microsoft :: MS-DOS',
-		'Operating System :: Microsoft :: Windows',
-		'Operating System :: Microsoft :: Windows :: Windows 3.1 or Earlier',
-		'Operating System :: Microsoft :: Windows :: Windows 95/98/2000',
-		'Operating System :: Microsoft :: Windows :: Windows CE',
-		'Operating System :: Microsoft :: Windows :: Windows NT/2000',
-		'Operating System :: OS/2',
-		'Operating System :: OS Independent',
-		'Operating System :: Other OS',
-		'Operating System :: PalmOS',
-		'Operating System :: PDA Systems',
-		'Operating System :: POSIX',
-		'Operating System :: POSIX :: AIX',
-		'Operating System :: POSIX :: BSD',
-		'Operating System :: POSIX :: BSD :: BSD/OS',
-		'Operating System :: POSIX :: BSD :: FreeBSD',
-		'Operating System :: POSIX :: BSD :: NetBSD',
-		'Operating System :: POSIX :: BSD :: OpenBSD',
-		'Operating System :: POSIX :: GNU Hurd',
-		'Operating System :: POSIX :: HP-UX',
-		'Operating System :: POSIX :: IRIX',
-		'Operating System :: POSIX :: Linux',
-		'Operating System :: POSIX :: Other',
-		'Operating System :: POSIX :: SCO',
-		'Operating System :: POSIX :: SunOS/Solaris',
-		'Operating System :: Unix',
-		'Programming Language :: Ada',
-		'Programming Language :: APL',
-		'Programming Language :: ASP',
-		'Programming Language :: Assembly',
-		'Programming Language :: Awk',
-		'Programming Language :: Basic',
-		'Programming Language :: C',
-		'Programming Language :: C#',
-		'Programming Language :: C++',
-		'Programming Language :: Cold Fusion',
-		'Programming Language :: Cython',
-		'Programming Language :: Delphi/Kylix',
-		'Programming Language :: Dylan',
-		'Programming Language :: Eiffel',
-		'Programming Language :: Emacs-Lisp',
-		'Programming Language :: Erlang',
-		'Programming Language :: Euler',
-		'Programming Language :: Euphoria',
-		'Programming Language :: Forth',
-		'Programming Language :: Fortran',
-		'Programming Language :: Haskell',
-		'Programming Language :: Java',
-		'Programming Language :: JavaScript',
-		'Programming Language :: Lisp',
-		'Programming Language :: Logo',
-		'Programming Language :: ML',
-		'Programming Language :: Modula',
-		'Programming Language :: Objective C',
-		'Programming Language :: Object Pascal',
-		'Programming Language :: OCaml',
-		'Programming Language :: Other',
-		'Programming Language :: Other Scripting Engines',
-		'Programming Language :: Pascal',
-		'Programming Language :: Perl',
-		'Programming Language :: PHP',
-		'Programming Language :: Pike',
-		'Programming Language :: Pliant',
-		'Programming Language :: PL/SQL',
-		'Programming Language :: PROGRESS',
-		'Programming Language :: Prolog',
-		'Programming Language :: Python',
-		'Programming Language :: Python :: 2',
-		'Programming Language :: Python :: 2.3',
-		'Programming Language :: Python :: 2.4',
-		'Programming Language :: Python :: 2.5',
-		'Programming Language :: Python :: 2.6',
-		'Programming Language :: Python :: 2.7',
-		'Programming Language :: Python :: 3',
-		'Programming Language :: Python :: 3.0',
-		'Programming Language :: Python :: 3.1',
-		'Programming Language :: Python :: 3.2',
-		'Programming Language :: REBOL',
-		'Programming Language :: Rexx',
-		'Programming Language :: Ruby',
-		'Programming Language :: Scheme',
-		'Programming Language :: Simula',
-		'Programming Language :: Smalltalk',
-		'Programming Language :: SQL',
-		'Programming Language :: Tcl',
-		'Programming Language :: Unix Shell',
-		'Programming Language :: Visual Basic',
-		'Programming Language :: XBasic',
-		'Programming Language :: YACC',
-		'Programming Language :: Zope',
-		'Topic :: Adaptive Technologies',
-		'Topic :: Artistic Software',
-		'Topic :: Communications',
-		'Topic :: Communications :: BBS',
-		'Topic :: Communications :: Chat',
-		'Topic :: Communications :: Chat :: AOL Instant Messenger',
-		'Topic :: Communications :: Chat :: ICQ',
-		'Topic :: Communications :: Chat :: Internet Relay Chat',
-		'Topic :: Communications :: Chat :: Unix Talk',
-		'Topic :: Communications :: Conferencing',
-		'Topic :: Communications :: Email',
-		'Topic :: Communications :: Email :: Address Book',
-		'Topic :: Communications :: Email :: Email Clients (MUA)',
-		'Topic :: Communications :: Email :: Filters',
-		'Topic :: Communications :: Email :: Mailing List Servers',
-		'Topic :: Communications :: Email :: Mail Transport Agents',
-		'Topic :: Communications :: Email :: Post-Office',
-		'Topic :: Communications :: Email :: Post-Office :: IMAP',
-		'Topic :: Communications :: Email :: Post-Office :: POP3',
-		'Topic :: Communications :: Fax',
-		'Topic :: Communications :: FIDO',
-		'Topic :: Communications :: File Sharing',
-		'Topic :: Communications :: File Sharing :: Gnutella',
-		'Topic :: Communications :: File Sharing :: Napster',
-		'Topic :: Communications :: Ham Radio',
-		'Topic :: Communications :: Internet Phone',
-		'Topic :: Communications :: Telephony',
-		'Topic :: Communications :: Usenet News',
-		'Topic :: Database',
-		'Topic :: Database :: Database Engines/Servers',
-		'Topic :: Database :: Front-Ends',
-		'Topic :: Desktop Environment',
-		'Topic :: Desktop Environment :: File Managers',
-		'Topic :: Desktop Environment :: Gnome',
-		'Topic :: Desktop Environment :: GNUstep',
-		'Topic :: Desktop Environment :: K Desktop Environment (KDE)',
-		'Topic :: Desktop Environment :: K Desktop Environment (KDE) :: Themes',
-		'Topic :: Desktop Environment :: PicoGUI',
-		'Topic :: Desktop Environment :: PicoGUI :: Applications',
-		'Topic :: Desktop Environment :: PicoGUI :: Themes',
-		'Topic :: Desktop Environment :: Screen Savers',
-		'Topic :: Desktop Environment :: Window Managers',
-		'Topic :: Desktop Environment :: Window Managers :: Afterstep',
-		'Topic :: Desktop Environment :: Window Managers :: Afterstep :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: Applets',
-		'Topic :: Desktop Environment :: Window Managers :: Blackbox',
-		'Topic :: Desktop Environment :: Window Managers :: Blackbox :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: CTWM',
-		'Topic :: Desktop Environment :: Window Managers :: CTWM :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: Enlightenment',
-		'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Epplets',
-		'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR15',
-		'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR16',
-		'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR17',
-		'Topic :: Desktop Environment :: Window Managers :: Fluxbox',
-		'Topic :: Desktop Environment :: Window Managers :: Fluxbox :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: FVWM',
-		'Topic :: Desktop Environment :: Window Managers :: FVWM :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: IceWM',
-		'Topic :: Desktop Environment :: Window Managers :: IceWM :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: MetaCity',
-		'Topic :: Desktop Environment :: Window Managers :: MetaCity :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: Oroborus',
-		'Topic :: Desktop Environment :: Window Managers :: Oroborus :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: Sawfish',
-		'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes 0.30',
-		'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes pre-0.30',
-		'Topic :: Desktop Environment :: Window Managers :: Waimea',
-		'Topic :: Desktop Environment :: Window Managers :: Waimea :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: Window Maker',
-		'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Applets',
-		'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Themes',
-		'Topic :: Desktop Environment :: Window Managers :: XFCE',
-		'Topic :: Desktop Environment :: Window Managers :: XFCE :: Themes',
-		'Topic :: Documentation',
-		'Topic :: Education',
-		'Topic :: Education :: Computer Aided Instruction (CAI)',
-		'Topic :: Education :: Testing',
-		'Topic :: Games/Entertainment',
-		'Topic :: Games/Entertainment :: Arcade',
-		'Topic :: Games/Entertainment :: Board Games',
-		'Topic :: Games/Entertainment :: First Person Shooters',
-		'Topic :: Games/Entertainment :: Fortune Cookies',
-		'Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)',
-		'Topic :: Games/Entertainment :: Puzzle Games',
-		'Topic :: Games/Entertainment :: Real Time Strategy',
-		'Topic :: Games/Entertainment :: Role-Playing',
-		'Topic :: Games/Entertainment :: Side-Scrolling/Arcade Games',
-		'Topic :: Games/Entertainment :: Simulation',
-		'Topic :: Games/Entertainment :: Turn Based Strategy',
-		'Topic :: Home Automation',
-		'Topic :: Internet',
-		'Topic :: Internet :: File Transfer Protocol (FTP)',
-		'Topic :: Internet :: Finger',
-		'Topic :: Internet :: Log Analysis',
-		'Topic :: Internet :: Name Service (DNS)',
-		'Topic :: Internet :: Proxy Servers',
-		'Topic :: Internet :: WAP',
-		'Topic :: Internet :: WWW/HTTP',
-		'Topic :: Internet :: WWW/HTTP :: Browsers',
-		'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
-		'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries',
-		'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards',
-		'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary',
-		'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Page Counters',
-		'Topic :: Internet :: WWW/HTTP :: HTTP Servers',
-		'Topic :: Internet :: WWW/HTTP :: Indexing/Search',
-		'Topic :: Internet :: WWW/HTTP :: Site Management',
-		'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking',
-		'Topic :: Internet :: WWW/HTTP :: WSGI',
-		'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
-		'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware',
-		'Topic :: Internet :: WWW/HTTP :: WSGI :: Server',
-		'Topic :: Internet :: Z39.50',
-		'Topic :: Multimedia',
-		'Topic :: Multimedia :: Graphics',
-		'Topic :: Multimedia :: Graphics :: 3D Modeling',
-		'Topic :: Multimedia :: Graphics :: 3D Rendering',
-		'Topic :: Multimedia :: Graphics :: Capture',
-		'Topic :: Multimedia :: Graphics :: Capture :: Digital Camera',
-		'Topic :: Multimedia :: Graphics :: Capture :: Scanners',
-		'Topic :: Multimedia :: Graphics :: Capture :: Screen Capture',
-		'Topic :: Multimedia :: Graphics :: Editors',
-		'Topic :: Multimedia :: Graphics :: Editors :: Raster-Based',
-		'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based',
-		'Topic :: Multimedia :: Graphics :: Graphics Conversion',
-		'Topic :: Multimedia :: Graphics :: Presentation',
-		'Topic :: Multimedia :: Graphics :: Viewers',
-		'Topic :: Multimedia :: Sound/Audio',
-		'Topic :: Multimedia :: Sound/Audio :: Analysis',
-		'Topic :: Multimedia :: Sound/Audio :: Capture/Recording',
-		'Topic :: Multimedia :: Sound/Audio :: CD Audio',
-		'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Playing',
-		'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Ripping',
-		'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Writing',
-		'Topic :: Multimedia :: Sound/Audio :: Conversion',
-		'Topic :: Multimedia :: Sound/Audio :: Editors',
-		'Topic :: Multimedia :: Sound/Audio :: MIDI',
-		'Topic :: Multimedia :: Sound/Audio :: Mixers',
-		'Topic :: Multimedia :: Sound/Audio :: Players',
-		'Topic :: Multimedia :: Sound/Audio :: Players :: MP3',
-		'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis',
-		'Topic :: Multimedia :: Sound/Audio :: Speech',
-		'Topic :: Multimedia :: Video',
-		'Topic :: Multimedia :: Video :: Capture',
-		'Topic :: Multimedia :: Video :: Conversion',
-		'Topic :: Multimedia :: Video :: Display',
-		'Topic :: Multimedia :: Video :: Non-Linear Editor',
-		'Topic :: Office/Business',
-		'Topic :: Office/Business :: Financial',
-		'Topic :: Office/Business :: Financial :: Accounting',
-		'Topic :: Office/Business :: Financial :: Investment',
-		'Topic :: Office/Business :: Financial :: Point-Of-Sale',
-		'Topic :: Office/Business :: Financial :: Spreadsheet',
-		'Topic :: Office/Business :: Groupware',
-		'Topic :: Office/Business :: News/Diary',
-		'Topic :: Office/Business :: Office Suites',
-		'Topic :: Office/Business :: Scheduling',
-		'Topic :: Other/Nonlisted Topic',
-		'Topic :: Printing',
-		'Topic :: Religion',
-		'Topic :: Scientific/Engineering',
-		'Topic :: Scientific/Engineering :: Artificial Intelligence',
-		'Topic :: Scientific/Engineering :: Astronomy',
-		'Topic :: Scientific/Engineering :: Atmospheric Science',
-		'Topic :: Scientific/Engineering :: Bio-Informatics',
-		'Topic :: Scientific/Engineering :: Chemistry',
-		'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)',
-		'Topic :: Scientific/Engineering :: GIS',
-		'Topic :: Scientific/Engineering :: Human Machine Interfaces',
-		'Topic :: Scientific/Engineering :: Image Recognition',
-		'Topic :: Scientific/Engineering :: Information Analysis',
-		'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator',
-		'Topic :: Scientific/Engineering :: Mathematics',
-		'Topic :: Scientific/Engineering :: Medical Science Apps.',
-		'Topic :: Scientific/Engineering :: Physics',
-		'Topic :: Scientific/Engineering :: Visualization',
-		'Topic :: Security',
-		'Topic :: Security :: Cryptography',
-		'Topic :: Sociology',
-		'Topic :: Sociology :: Genealogy',
-		'Topic :: Sociology :: History',
-		'Topic :: Software Development',
-		'Topic :: Software Development :: Assemblers',
-		'Topic :: Software Development :: Bug Tracking',
-		'Topic :: Software Development :: Build Tools',
-		'Topic :: Software Development :: Code Generators',
-		'Topic :: Software Development :: Compilers',
-		'Topic :: Software Development :: Debuggers',
-		'Topic :: Software Development :: Disassemblers',
-		'Topic :: Software Development :: Documentation',
-		'Topic :: Software Development :: Embedded Systems',
-		'Topic :: Software Development :: Internationalization',
-		'Topic :: Software Development :: Interpreters',
-		'Topic :: Software Development :: Libraries',
-		'Topic :: Software Development :: Libraries :: Application Frameworks',
-		'Topic :: Software Development :: Libraries :: Java Libraries',
-		'Topic :: Software Development :: Libraries :: Perl Modules',
-		'Topic :: Software Development :: Libraries :: PHP Classes',
-		'Topic :: Software Development :: Libraries :: Pike Modules',
-		'Topic :: Software Development :: Libraries :: pygame',
-		'Topic :: Software Development :: Libraries :: Python Modules',
-		'Topic :: Software Development :: Libraries :: Ruby Modules',
-		'Topic :: Software Development :: Libraries :: Tcl Extensions',
-		'Topic :: Software Development :: Localization',
-		'Topic :: Software Development :: Object Brokering',
-		'Topic :: Software Development :: Object Brokering :: CORBA',
-		'Topic :: Software Development :: Pre-processors',
-		'Topic :: Software Development :: Quality Assurance',
-		'Topic :: Software Development :: Testing',
-		'Topic :: Software Development :: Testing :: Traffic Generation',
-		'Topic :: Software Development :: User Interfaces',
-		'Topic :: Software Development :: Version Control',
-		'Topic :: Software Development :: Version Control :: CVS',
-		'Topic :: Software Development :: Version Control :: RCS',
-		'Topic :: Software Development :: Version Control :: SCCS',
-		'Topic :: Software Development :: Widget Sets',
-		'Topic :: System',
-		'Topic :: System :: Archiving',
-		'Topic :: System :: Archiving :: Backup',
-		'Topic :: System :: Archiving :: Compression',
-		'Topic :: System :: Archiving :: Mirroring',
-		'Topic :: System :: Archiving :: Packaging',
-		'Topic :: System :: Benchmark',
-		'Topic :: System :: Boot',
-		'Topic :: System :: Boot :: Init',
-		'Topic :: System :: Clustering',
-		'Topic :: System :: Console Fonts',
-		'Topic :: System :: Distributed Computing',
-		'Topic :: System :: Emulators',
-		'Topic :: System :: Filesystems',
-		'Topic :: System :: Hardware',
-		'Topic :: System :: Hardware :: Hardware Drivers',
-		'Topic :: System :: Hardware :: Mainframes',
-		'Topic :: System :: Hardware :: Symmetric Multi-processing',
-		'Topic :: System :: Installation/Setup',
-		'Topic :: System :: Logging',
-		'Topic :: System :: Monitoring',
-		'Topic :: System :: Networking',
-		'Topic :: System :: Networking :: Firewalls',
-		'Topic :: System :: Networking :: Monitoring',
-		'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog',
-		'Topic :: System :: Networking :: Time Synchronization',
-		'Topic :: System :: Operating System',
-		'Topic :: System :: Operating System Kernels',
-		'Topic :: System :: Operating System Kernels :: BSD',
-		'Topic :: System :: Operating System Kernels :: GNU Hurd',
-		'Topic :: System :: Operating System Kernels :: Linux',
-		'Topic :: System :: Power (UPS)',
-		'Topic :: System :: Recovery Tools',
-		'Topic :: System :: Shells',
-		'Topic :: System :: Software Distribution',
-		'Topic :: System :: Systems Administration',
-		'Topic :: System :: Systems Administration :: Authentication/Directory',
-		'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP',
-		'Topic :: System :: Systems Administration :: Authentication/Directory :: NIS',
-		'Topic :: System :: System Shells',
-		'Topic :: Terminals',
-		'Topic :: Terminals :: Serial',
-		'Topic :: Terminals :: Telnet',
-		'Topic :: Terminals :: Terminal Emulators/X Terminals',
-		'Topic :: Text Editors',
-		'Topic :: Text Editors :: Documentation',
-		'Topic :: Text Editors :: Emacs',
-		'Topic :: Text Editors :: Integrated Development Environments (IDE)',
-		'Topic :: Text Editors :: Text Processing',
-		'Topic :: Text Editors :: Word Processors',
-		'Topic :: Text Processing',
-		'Topic :: Text Processing :: Filters',
-		'Topic :: Text Processing :: Fonts',
-		'Topic :: Text Processing :: General',
-		'Topic :: Text Processing :: Indexing',
-		'Topic :: Text Processing :: Linguistic',
-		'Topic :: Text Processing :: Markup',
-		'Topic :: Text Processing :: Markup :: HTML',
-		'Topic :: Text Processing :: Markup :: LaTeX',
-		'Topic :: Text Processing :: Markup :: SGML',
-		'Topic :: Text Processing :: Markup :: VRML',
-		'Topic :: Text Processing :: Markup :: XML',
-		'Topic :: Utilities',
+        'Development Status :: 1 - Planning',
+        'Development Status :: 2 - Pre-Alpha',
+        'Development Status :: 3 - Alpha',
+        'Development Status :: 4 - Beta',
+        'Development Status :: 5 - Production/Stable',
+        'Development Status :: 6 - Mature',
+        'Development Status :: 7 - Inactive',
+        'Environment :: Console',
+        'Environment :: Console :: Curses',
+        'Environment :: Console :: Framebuffer',
+        'Environment :: Console :: Newt',
+        'Environment :: Console :: svgalib',
+        'Environment :: Handhelds/PDA\'s',
+        'Environment :: MacOS X',
+        'Environment :: MacOS X :: Aqua',
+        'Environment :: MacOS X :: Carbon',
+        'Environment :: MacOS X :: Cocoa',
+        'Environment :: No Input/Output (Daemon)',
+        'Environment :: Other Environment',
+        'Environment :: Plugins',
+        'Environment :: Web Environment',
+        'Environment :: Web Environment :: Buffet',
+        'Environment :: Web Environment :: Mozilla',
+        'Environment :: Web Environment :: ToscaWidgets',
+        'Environment :: Win32 (MS Windows)',
+        'Environment :: X11 Applications',
+        'Environment :: X11 Applications :: Gnome',
+        'Environment :: X11 Applications :: GTK',
+        'Environment :: X11 Applications :: KDE',
+        'Environment :: X11 Applications :: Qt',
+        'Framework :: BFG',
+        'Framework :: Buildout',
+        'Framework :: Chandler',
+        'Framework :: CubicWeb',
+        'Framework :: Django',
+        'Framework :: IDLE',
+        'Framework :: Paste',
+        'Framework :: Plone',
+        'Framework :: Pylons',
+        'Framework :: Setuptools Plugin',
+        'Framework :: Trac',
+        'Framework :: TurboGears',
+        'Framework :: TurboGears :: Applications',
+        'Framework :: TurboGears :: Widgets',
+        'Framework :: Twisted',
+        'Framework :: ZODB',
+        'Framework :: Zope2',
+        'Framework :: Zope3',
+        'Intended Audience :: Customer Service',
+        'Intended Audience :: Developers',
+        'Intended Audience :: Education',
+        'Intended Audience :: End Users/Desktop',
+        'Intended Audience :: Financial and Insurance Industry',
+        'Intended Audience :: Healthcare Industry',
+        'Intended Audience :: Information Technology',
+        'Intended Audience :: Legal Industry',
+        'Intended Audience :: Manufacturing',
+        'Intended Audience :: Other Audience',
+        'Intended Audience :: Religion',
+        'Intended Audience :: Science/Research',
+        'Intended Audience :: System Administrators',
+        'Intended Audience :: Telecommunications Industry',
+        'License :: Aladdin Free Public License (AFPL)',
+        'License :: DFSG approved',
+        'License :: Eiffel Forum License (EFL)',
+        'License :: Free For Educational Use',
+        'License :: Free For Home Use',
+        'License :: Free for non-commercial use',
+        'License :: Freely Distributable',
+        'License :: Free To Use But Restricted',
+        'License :: Freeware',
+        'License :: Netscape Public License (NPL)',
+        'License :: Nokia Open Source License (NOKOS)',
+        'License :: OSI Approved',
+        'License :: OSI Approved :: Academic Free License (AFL)',
+        'License :: OSI Approved :: Apache Software License',
+        'License :: OSI Approved :: Apple Public Source License',
+        'License :: OSI Approved :: Artistic License',
+        'License :: OSI Approved :: Attribution Assurance License',
+        'License :: OSI Approved :: BSD License',
+        'License :: OSI Approved :: Common Public License',
+        'License :: OSI Approved :: Eiffel Forum License',
+        'License :: OSI Approved :: European Union Public Licence 1.0 (EUPL 1.0)',
+        'License :: OSI Approved :: European Union Public Licence 1.1 (EUPL 1.1)',
+        'License :: OSI Approved :: GNU Affero General Public License v3',
+        'License :: OSI Approved :: GNU Free Documentation License (FDL)',
+        'License :: OSI Approved :: GNU General Public License (GPL)',
+        'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+        'License :: OSI Approved :: IBM Public License',
+        'License :: OSI Approved :: Intel Open Source License',
+        'License :: OSI Approved :: ISC License (ISCL)',
+        'License :: OSI Approved :: Jabber Open Source License',
+        'License :: OSI Approved :: MIT License',
+        'License :: OSI Approved :: MITRE Collaborative Virtual Workspace License (CVW)',
+        'License :: OSI Approved :: Motosoto License',
+        'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)',
+        'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)',
+        'License :: OSI Approved :: Nethack General Public License',
+        'License :: OSI Approved :: Nokia Open Source License',
+        'License :: OSI Approved :: Open Group Test Suite License',
+        'License :: OSI Approved :: Python License (CNRI Python License)',
+        'License :: OSI Approved :: Python Software Foundation License',
+        'License :: OSI Approved :: Qt Public License (QPL)',
+        'License :: OSI Approved :: Ricoh Source Code Public License',
+        'License :: OSI Approved :: Sleepycat License',
+        'License :: OSI Approved :: Sun Industry Standards Source License (SISSL)',
+        'License :: OSI Approved :: Sun Public License',
+        'License :: OSI Approved :: University of Illinois/NCSA Open Source License',
+        'License :: OSI Approved :: Vovida Software License 1.0',
+        'License :: OSI Approved :: W3C License',
+        'License :: OSI Approved :: X.Net License',
+        'License :: OSI Approved :: zlib/libpng License',
+        'License :: OSI Approved :: Zope Public License',
+        'License :: Other/Proprietary License',
+        'License :: Public Domain',
+        'License :: Repoze Public License',
+        'Natural Language :: Afrikaans',
+        'Natural Language :: Arabic',
+        'Natural Language :: Bengali',
+        'Natural Language :: Bosnian',
+        'Natural Language :: Bulgarian',
+        'Natural Language :: Catalan',
+        'Natural Language :: Chinese (Simplified)',
+        'Natural Language :: Chinese (Traditional)',
+        'Natural Language :: Croatian',
+        'Natural Language :: Czech',
+        'Natural Language :: Danish',
+        'Natural Language :: Dutch',
+        'Natural Language :: English',
+        'Natural Language :: Esperanto',
+        'Natural Language :: Finnish',
+        'Natural Language :: French',
+        'Natural Language :: German',
+        'Natural Language :: Greek',
+        'Natural Language :: Hebrew',
+        'Natural Language :: Hindi',
+        'Natural Language :: Hungarian',
+        'Natural Language :: Icelandic',
+        'Natural Language :: Indonesian',
+        'Natural Language :: Italian',
+        'Natural Language :: Japanese',
+        'Natural Language :: Javanese',
+        'Natural Language :: Korean',
+        'Natural Language :: Latin',
+        'Natural Language :: Latvian',
+        'Natural Language :: Macedonian',
+        'Natural Language :: Malay',
+        'Natural Language :: Marathi',
+        'Natural Language :: Norwegian',
+        'Natural Language :: Panjabi',
+        'Natural Language :: Persian',
+        'Natural Language :: Polish',
+        'Natural Language :: Portuguese',
+        'Natural Language :: Portuguese (Brazilian)',
+        'Natural Language :: Romanian',
+        'Natural Language :: Russian',
+        'Natural Language :: Serbian',
+        'Natural Language :: Slovak',
+        'Natural Language :: Slovenian',
+        'Natural Language :: Spanish',
+        'Natural Language :: Swedish',
+        'Natural Language :: Tamil',
+        'Natural Language :: Telugu',
+        'Natural Language :: Thai',
+        'Natural Language :: Turkish',
+        'Natural Language :: Ukranian',
+        'Natural Language :: Urdu',
+        'Natural Language :: Vietnamese',
+        'Operating System :: BeOS',
+        'Operating System :: MacOS',
+        'Operating System :: MacOS :: MacOS 9',
+        'Operating System :: MacOS :: MacOS X',
+        'Operating System :: Microsoft',
+        'Operating System :: Microsoft :: MS-DOS',
+        'Operating System :: Microsoft :: Windows',
+        'Operating System :: Microsoft :: Windows :: Windows 3.1 or Earlier',
+        'Operating System :: Microsoft :: Windows :: Windows 95/98/2000',
+        'Operating System :: Microsoft :: Windows :: Windows CE',
+        'Operating System :: Microsoft :: Windows :: Windows NT/2000',
+        'Operating System :: OS/2',
+        'Operating System :: OS Independent',
+        'Operating System :: Other OS',
+        'Operating System :: PalmOS',
+        'Operating System :: PDA Systems',
+        'Operating System :: POSIX',
+        'Operating System :: POSIX :: AIX',
+        'Operating System :: POSIX :: BSD',
+        'Operating System :: POSIX :: BSD :: BSD/OS',
+        'Operating System :: POSIX :: BSD :: FreeBSD',
+        'Operating System :: POSIX :: BSD :: NetBSD',
+        'Operating System :: POSIX :: BSD :: OpenBSD',
+        'Operating System :: POSIX :: GNU Hurd',
+        'Operating System :: POSIX :: HP-UX',
+        'Operating System :: POSIX :: IRIX',
+        'Operating System :: POSIX :: Linux',
+        'Operating System :: POSIX :: Other',
+        'Operating System :: POSIX :: SCO',
+        'Operating System :: POSIX :: SunOS/Solaris',
+        'Operating System :: Unix',
+        'Programming Language :: Ada',
+        'Programming Language :: APL',
+        'Programming Language :: ASP',
+        'Programming Language :: Assembly',
+        'Programming Language :: Awk',
+        'Programming Language :: Basic',
+        'Programming Language :: C',
+        'Programming Language :: C#',
+        'Programming Language :: C++',
+        'Programming Language :: Cold Fusion',
+        'Programming Language :: Cython',
+        'Programming Language :: Delphi/Kylix',
+        'Programming Language :: Dylan',
+        'Programming Language :: Eiffel',
+        'Programming Language :: Emacs-Lisp',
+        'Programming Language :: Erlang',
+        'Programming Language :: Euler',
+        'Programming Language :: Euphoria',
+        'Programming Language :: Forth',
+        'Programming Language :: Fortran',
+        'Programming Language :: Haskell',
+        'Programming Language :: Java',
+        'Programming Language :: JavaScript',
+        'Programming Language :: Lisp',
+        'Programming Language :: Logo',
+        'Programming Language :: ML',
+        'Programming Language :: Modula',
+        'Programming Language :: Objective C',
+        'Programming Language :: Object Pascal',
+        'Programming Language :: OCaml',
+        'Programming Language :: Other',
+        'Programming Language :: Other Scripting Engines',
+        'Programming Language :: Pascal',
+        'Programming Language :: Perl',
+        'Programming Language :: PHP',
+        'Programming Language :: Pike',
+        'Programming Language :: Pliant',
+        'Programming Language :: PL/SQL',
+        'Programming Language :: PROGRESS',
+        'Programming Language :: Prolog',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.3',
+        'Programming Language :: Python :: 2.4',
+        'Programming Language :: Python :: 2.5',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.0',
+        'Programming Language :: Python :: 3.1',
+        'Programming Language :: Python :: 3.2',
+        'Programming Language :: REBOL',
+        'Programming Language :: Rexx',
+        'Programming Language :: Ruby',
+        'Programming Language :: Scheme',
+        'Programming Language :: Simula',
+        'Programming Language :: Smalltalk',
+        'Programming Language :: SQL',
+        'Programming Language :: Tcl',
+        'Programming Language :: Unix Shell',
+        'Programming Language :: Visual Basic',
+        'Programming Language :: XBasic',
+        'Programming Language :: YACC',
+        'Programming Language :: Zope',
+        'Topic :: Adaptive Technologies',
+        'Topic :: Artistic Software',
+        'Topic :: Communications',
+        'Topic :: Communications :: BBS',
+        'Topic :: Communications :: Chat',
+        'Topic :: Communications :: Chat :: AOL Instant Messenger',
+        'Topic :: Communications :: Chat :: ICQ',
+        'Topic :: Communications :: Chat :: Internet Relay Chat',
+        'Topic :: Communications :: Chat :: Unix Talk',
+        'Topic :: Communications :: Conferencing',
+        'Topic :: Communications :: Email',
+        'Topic :: Communications :: Email :: Address Book',
+        'Topic :: Communications :: Email :: Email Clients (MUA)',
+        'Topic :: Communications :: Email :: Filters',
+        'Topic :: Communications :: Email :: Mailing List Servers',
+        'Topic :: Communications :: Email :: Mail Transport Agents',
+        'Topic :: Communications :: Email :: Post-Office',
+        'Topic :: Communications :: Email :: Post-Office :: IMAP',
+        'Topic :: Communications :: Email :: Post-Office :: POP3',
+        'Topic :: Communications :: Fax',
+        'Topic :: Communications :: FIDO',
+        'Topic :: Communications :: File Sharing',
+        'Topic :: Communications :: File Sharing :: Gnutella',
+        'Topic :: Communications :: File Sharing :: Napster',
+        'Topic :: Communications :: Ham Radio',
+        'Topic :: Communications :: Internet Phone',
+        'Topic :: Communications :: Telephony',
+        'Topic :: Communications :: Usenet News',
+        'Topic :: Database',
+        'Topic :: Database :: Database Engines/Servers',
+        'Topic :: Database :: Front-Ends',
+        'Topic :: Desktop Environment',
+        'Topic :: Desktop Environment :: File Managers',
+        'Topic :: Desktop Environment :: Gnome',
+        'Topic :: Desktop Environment :: GNUstep',
+        'Topic :: Desktop Environment :: K Desktop Environment (KDE)',
+        'Topic :: Desktop Environment :: K Desktop Environment (KDE) :: Themes',
+        'Topic :: Desktop Environment :: PicoGUI',
+        'Topic :: Desktop Environment :: PicoGUI :: Applications',
+        'Topic :: Desktop Environment :: PicoGUI :: Themes',
+        'Topic :: Desktop Environment :: Screen Savers',
+        'Topic :: Desktop Environment :: Window Managers',
+        'Topic :: Desktop Environment :: Window Managers :: Afterstep',
+        'Topic :: Desktop Environment :: Window Managers :: Afterstep :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: Applets',
+        'Topic :: Desktop Environment :: Window Managers :: Blackbox',
+        'Topic :: Desktop Environment :: Window Managers :: Blackbox :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: CTWM',
+        'Topic :: Desktop Environment :: Window Managers :: CTWM :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: Enlightenment',
+        'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Epplets',
+        'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR15',
+        'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR16',
+        'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR17',
+        'Topic :: Desktop Environment :: Window Managers :: Fluxbox',
+        'Topic :: Desktop Environment :: Window Managers :: Fluxbox :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: FVWM',
+        'Topic :: Desktop Environment :: Window Managers :: FVWM :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: IceWM',
+        'Topic :: Desktop Environment :: Window Managers :: IceWM :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: MetaCity',
+        'Topic :: Desktop Environment :: Window Managers :: MetaCity :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: Oroborus',
+        'Topic :: Desktop Environment :: Window Managers :: Oroborus :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: Sawfish',
+        'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes 0.30',
+        'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes pre-0.30',
+        'Topic :: Desktop Environment :: Window Managers :: Waimea',
+        'Topic :: Desktop Environment :: Window Managers :: Waimea :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: Window Maker',
+        'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Applets',
+        'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Themes',
+        'Topic :: Desktop Environment :: Window Managers :: XFCE',
+        'Topic :: Desktop Environment :: Window Managers :: XFCE :: Themes',
+        'Topic :: Documentation',
+        'Topic :: Education',
+        'Topic :: Education :: Computer Aided Instruction (CAI)',
+        'Topic :: Education :: Testing',
+        'Topic :: Games/Entertainment',
+        'Topic :: Games/Entertainment :: Arcade',
+        'Topic :: Games/Entertainment :: Board Games',
+        'Topic :: Games/Entertainment :: First Person Shooters',
+        'Topic :: Games/Entertainment :: Fortune Cookies',
+        'Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)',
+        'Topic :: Games/Entertainment :: Puzzle Games',
+        'Topic :: Games/Entertainment :: Real Time Strategy',
+        'Topic :: Games/Entertainment :: Role-Playing',
+        'Topic :: Games/Entertainment :: Side-Scrolling/Arcade Games',
+        'Topic :: Games/Entertainment :: Simulation',
+        'Topic :: Games/Entertainment :: Turn Based Strategy',
+        'Topic :: Home Automation',
+        'Topic :: Internet',
+        'Topic :: Internet :: File Transfer Protocol (FTP)',
+        'Topic :: Internet :: Finger',
+        'Topic :: Internet :: Log Analysis',
+        'Topic :: Internet :: Name Service (DNS)',
+        'Topic :: Internet :: Proxy Servers',
+        'Topic :: Internet :: WAP',
+        'Topic :: Internet :: WWW/HTTP',
+        'Topic :: Internet :: WWW/HTTP :: Browsers',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary',
+        'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Page Counters',
+        'Topic :: Internet :: WWW/HTTP :: HTTP Servers',
+        'Topic :: Internet :: WWW/HTTP :: Indexing/Search',
+        'Topic :: Internet :: WWW/HTTP :: Site Management',
+        'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking',
+        'Topic :: Internet :: WWW/HTTP :: WSGI',
+        'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+        'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware',
+        'Topic :: Internet :: WWW/HTTP :: WSGI :: Server',
+        'Topic :: Internet :: Z39.50',
+        'Topic :: Multimedia',
+        'Topic :: Multimedia :: Graphics',
+        'Topic :: Multimedia :: Graphics :: 3D Modeling',
+        'Topic :: Multimedia :: Graphics :: 3D Rendering',
+        'Topic :: Multimedia :: Graphics :: Capture',
+        'Topic :: Multimedia :: Graphics :: Capture :: Digital Camera',
+        'Topic :: Multimedia :: Graphics :: Capture :: Scanners',
+        'Topic :: Multimedia :: Graphics :: Capture :: Screen Capture',
+        'Topic :: Multimedia :: Graphics :: Editors',
+        'Topic :: Multimedia :: Graphics :: Editors :: Raster-Based',
+        'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based',
+        'Topic :: Multimedia :: Graphics :: Graphics Conversion',
+        'Topic :: Multimedia :: Graphics :: Presentation',
+        'Topic :: Multimedia :: Graphics :: Viewers',
+        'Topic :: Multimedia :: Sound/Audio',
+        'Topic :: Multimedia :: Sound/Audio :: Analysis',
+        'Topic :: Multimedia :: Sound/Audio :: Capture/Recording',
+        'Topic :: Multimedia :: Sound/Audio :: CD Audio',
+        'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Playing',
+        'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Ripping',
+        'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Writing',
+        'Topic :: Multimedia :: Sound/Audio :: Conversion',
+        'Topic :: Multimedia :: Sound/Audio :: Editors',
+        'Topic :: Multimedia :: Sound/Audio :: MIDI',
+        'Topic :: Multimedia :: Sound/Audio :: Mixers',
+        'Topic :: Multimedia :: Sound/Audio :: Players',
+        'Topic :: Multimedia :: Sound/Audio :: Players :: MP3',
+        'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis',
+        'Topic :: Multimedia :: Sound/Audio :: Speech',
+        'Topic :: Multimedia :: Video',
+        'Topic :: Multimedia :: Video :: Capture',
+        'Topic :: Multimedia :: Video :: Conversion',
+        'Topic :: Multimedia :: Video :: Display',
+        'Topic :: Multimedia :: Video :: Non-Linear Editor',
+        'Topic :: Office/Business',
+        'Topic :: Office/Business :: Financial',
+        'Topic :: Office/Business :: Financial :: Accounting',
+        'Topic :: Office/Business :: Financial :: Investment',
+        'Topic :: Office/Business :: Financial :: Point-Of-Sale',
+        'Topic :: Office/Business :: Financial :: Spreadsheet',
+        'Topic :: Office/Business :: Groupware',
+        'Topic :: Office/Business :: News/Diary',
+        'Topic :: Office/Business :: Office Suites',
+        'Topic :: Office/Business :: Scheduling',
+        'Topic :: Other/Nonlisted Topic',
+        'Topic :: Printing',
+        'Topic :: Religion',
+        'Topic :: Scientific/Engineering',
+        'Topic :: Scientific/Engineering :: Artificial Intelligence',
+        'Topic :: Scientific/Engineering :: Astronomy',
+        'Topic :: Scientific/Engineering :: Atmospheric Science',
+        'Topic :: Scientific/Engineering :: Bio-Informatics',
+        'Topic :: Scientific/Engineering :: Chemistry',
+        'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)',
+        'Topic :: Scientific/Engineering :: GIS',
+        'Topic :: Scientific/Engineering :: Human Machine Interfaces',
+        'Topic :: Scientific/Engineering :: Image Recognition',
+        'Topic :: Scientific/Engineering :: Information Analysis',
+        'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator',
+        'Topic :: Scientific/Engineering :: Mathematics',
+        'Topic :: Scientific/Engineering :: Medical Science Apps.',
+        'Topic :: Scientific/Engineering :: Physics',
+        'Topic :: Scientific/Engineering :: Visualization',
+        'Topic :: Security',
+        'Topic :: Security :: Cryptography',
+        'Topic :: Sociology',
+        'Topic :: Sociology :: Genealogy',
+        'Topic :: Sociology :: History',
+        'Topic :: Software Development',
+        'Topic :: Software Development :: Assemblers',
+        'Topic :: Software Development :: Bug Tracking',
+        'Topic :: Software Development :: Build Tools',
+        'Topic :: Software Development :: Code Generators',
+        'Topic :: Software Development :: Compilers',
+        'Topic :: Software Development :: Debuggers',
+        'Topic :: Software Development :: Disassemblers',
+        'Topic :: Software Development :: Documentation',
+        'Topic :: Software Development :: Embedded Systems',
+        'Topic :: Software Development :: Internationalization',
+        'Topic :: Software Development :: Interpreters',
+        'Topic :: Software Development :: Libraries',
+        'Topic :: Software Development :: Libraries :: Application Frameworks',
+        'Topic :: Software Development :: Libraries :: Java Libraries',
+        'Topic :: Software Development :: Libraries :: Perl Modules',
+        'Topic :: Software Development :: Libraries :: PHP Classes',
+        'Topic :: Software Development :: Libraries :: Pike Modules',
+        'Topic :: Software Development :: Libraries :: pygame',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Topic :: Software Development :: Libraries :: Ruby Modules',
+        'Topic :: Software Development :: Libraries :: Tcl Extensions',
+        'Topic :: Software Development :: Localization',
+        'Topic :: Software Development :: Object Brokering',
+        'Topic :: Software Development :: Object Brokering :: CORBA',
+        'Topic :: Software Development :: Pre-processors',
+        'Topic :: Software Development :: Quality Assurance',
+        'Topic :: Software Development :: Testing',
+        'Topic :: Software Development :: Testing :: Traffic Generation',
+        'Topic :: Software Development :: User Interfaces',
+        'Topic :: Software Development :: Version Control',
+        'Topic :: Software Development :: Version Control :: CVS',
+        'Topic :: Software Development :: Version Control :: RCS',
+        'Topic :: Software Development :: Version Control :: SCCS',
+        'Topic :: Software Development :: Widget Sets',
+        'Topic :: System',
+        'Topic :: System :: Archiving',
+        'Topic :: System :: Archiving :: Backup',
+        'Topic :: System :: Archiving :: Compression',
+        'Topic :: System :: Archiving :: Mirroring',
+        'Topic :: System :: Archiving :: Packaging',
+        'Topic :: System :: Benchmark',
+        'Topic :: System :: Boot',
+        'Topic :: System :: Boot :: Init',
+        'Topic :: System :: Clustering',
+        'Topic :: System :: Console Fonts',
+        'Topic :: System :: Distributed Computing',
+        'Topic :: System :: Emulators',
+        'Topic :: System :: Filesystems',
+        'Topic :: System :: Hardware',
+        'Topic :: System :: Hardware :: Hardware Drivers',
+        'Topic :: System :: Hardware :: Mainframes',
+        'Topic :: System :: Hardware :: Symmetric Multi-processing',
+        'Topic :: System :: Installation/Setup',
+        'Topic :: System :: Logging',
+        'Topic :: System :: Monitoring',
+        'Topic :: System :: Networking',
+        'Topic :: System :: Networking :: Firewalls',
+        'Topic :: System :: Networking :: Monitoring',
+        'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog',
+        'Topic :: System :: Networking :: Time Synchronization',
+        'Topic :: System :: Operating System',
+        'Topic :: System :: Operating System Kernels',
+        'Topic :: System :: Operating System Kernels :: BSD',
+        'Topic :: System :: Operating System Kernels :: GNU Hurd',
+        'Topic :: System :: Operating System Kernels :: Linux',
+        'Topic :: System :: Power (UPS)',
+        'Topic :: System :: Recovery Tools',
+        'Topic :: System :: Shells',
+        'Topic :: System :: Software Distribution',
+        'Topic :: System :: Systems Administration',
+        'Topic :: System :: Systems Administration :: Authentication/Directory',
+        'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP',
+        'Topic :: System :: Systems Administration :: Authentication/Directory :: NIS',
+        'Topic :: System :: System Shells',
+        'Topic :: Terminals',
+        'Topic :: Terminals :: Serial',
+        'Topic :: Terminals :: Telnet',
+        'Topic :: Terminals :: Terminal Emulators/X Terminals',
+        'Topic :: Text Editors',
+        'Topic :: Text Editors :: Documentation',
+        'Topic :: Text Editors :: Emacs',
+        'Topic :: Text Editors :: Integrated Development Environments (IDE)',
+        'Topic :: Text Editors :: Text Processing',
+        'Topic :: Text Editors :: Word Processors',
+        'Topic :: Text Processing',
+        'Topic :: Text Processing :: Filters',
+        'Topic :: Text Processing :: Fonts',
+        'Topic :: Text Processing :: General',
+        'Topic :: Text Processing :: Indexing',
+        'Topic :: Text Processing :: Linguistic',
+        'Topic :: Text Processing :: Markup',
+        'Topic :: Text Processing :: Markup :: HTML',
+        'Topic :: Text Processing :: Markup :: LaTeX',
+        'Topic :: Text Processing :: Markup :: SGML',
+        'Topic :: Text Processing :: Markup :: VRML',
+        'Topic :: Text Processing :: Markup :: XML',
+        'Topic :: Utilities',
    ]
 
 def askYn(question, default = None, helptext = None):
-	while True:
-		answer = ask(question, default, helptext, required = True)
-		if answer and answer[0].lower() in 'yn':
-			return(answer[0].lower())
+    while True:
+        answer = ask(question, default, helptext, required = True)
+        if answer and answer[0].lower() in 'yn':
+            return(answer[0].lower())
 
-		print '\nERROR: You must select "Y" or "N".\n'
+        print '\nERROR: You must select "Y" or "N".\n'
 
 
 def ask(question, default = None, helptext = None, required = True,
         lengthy = False, multiline = False):
-	prompt = '%s: ' % ( question, )
-	if default:
-		prompt = '%s [%s]: ' % ( question, default )
-		if default and len(question) + len(default) > 70:
-			prompt = '%s\n    [%s]: ' % ( question, default )
-	if lengthy or multiline:
-		prompt += '\n   >'
+    prompt = '%s: ' % ( question, )
+    if default:
+        prompt = '%s [%s]: ' % ( question, default )
+        if default and len(question) + len(default) > 70:
+            prompt = '%s\n    [%s]: ' % ( question, default )
+    if lengthy or multiline:
+        prompt += '\n   >'
 
-	if not helptext: helptext = 'No additional help available.'
-	if helptext[0] == '\n': helptext = helptext[1:]
-	if helptext[-1] == '\n': helptext = helptext[:-1]
+    if not helptext: helptext = 'No additional help available.'
+    if helptext[0] == '\n': helptext = helptext[1:]
+    if helptext[-1] == '\n': helptext = helptext[:-1]
 
-	while True:
-		sys.stdout.write(prompt)
-		sys.stdout.flush()
+    while True:
+        sys.stdout.write(prompt)
+        sys.stdout.flush()
 
-		line = sys.stdin.readline().strip()
-		if line == '?':
-			print '=' * 70
-			print helptext
-			print '=' * 70
-			continue
-		if default and not line: return(default)
-		if not line and required:
-			print '*' * 70
-			print 'This value cannot be empty.'
-			print '==========================='
-			if helptext: print helptext
-			print '*' * 70
-			continue
-		return(line)
+        line = sys.stdin.readline().strip()
+        if line == '?':
+            print '=' * 70
+            print helptext
+            print '=' * 70
+            continue
+        if default and not line: return(default)
+        if not line and required:
+            print '*' * 70
+            print 'This value cannot be empty.'
+            print '==========================='
+            if helptext: print helptext
+            print '*' * 70
+            continue
+        return(line)
 
 
 def buildTroveDict(troveList):
-	dict = {}
-	for key in troveList:
-		subDict = dict
-		for subkey in key.split(' :: '):
-			if not subkey in subDict: subDict[subkey] = {}
-			subDict = subDict[subkey]
-	return(dict)
+    dict = {}
+    for key in troveList:
+        subDict = dict
+        for subkey in key.split(' :: '):
+            if not subkey in subDict: subDict[subkey] = {}
+            subDict = subDict[subkey]
+    return(dict)
 troveDict = buildTroveDict(troveList)
 
 
 class SetupClass:
-	def __init__(self):
-		self.config = None
-		self.classifierDict = {}
-		self.setupData = {}
-		self.setupData['classifier'] = self.classifierDict
-		self.setupData['packages'] = {}
+    def __init__(self):
+        self.config = None
+        self.classifierDict = {}
+        self.setupData = {}
+        self.setupData['classifier'] = self.classifierDict
+        self.setupData['packages'] = {}
 
-		self.loadConfigFile()
+        self.loadConfigFile()
 
 
-	def lookupOption(self, key):
-		if not self.config.has_option('DEFAULT', key): return(None)
-		return(self.config.get('DEFAULT', key))
+    def lookupOption(self, key):
+        if not self.config.has_option('DEFAULT', key): return(None)
+        return(self.config.get('DEFAULT', key))
 
 
-	def loadConfigFile(self):
-		self.config = ConfigParser.RawConfigParser()
-		self.config.read(os.path.expanduser('~/.mkpkgpy'))
-		self.setupData['author'] = self.lookupOption('author')
-		self.setupData['author_email'] = self.lookupOption('author_email')
+    def loadConfigFile(self):
+        self.config = ConfigParser.RawConfigParser()
+        self.config.read(os.path.expanduser('~/.mkpkgpy'))
+        self.setupData['author'] = self.lookupOption('author')
+        self.setupData['author_email'] = self.lookupOption('author_email')
 
 
-	def updateConfigFile(self):
-		valuesDifferent = False
-		for compareKey in ('author', 'author_email'):
-			if self.lookupOption(compareKey) != self.setupData[compareKey]:
-				valuesDifferent = True
-				self.config.set('DEFAULT', compareKey, self.setupData[compareKey])
+    def updateConfigFile(self):
+        valuesDifferent = False
+        for compareKey in ('author', 'author_email'):
+            if self.lookupOption(compareKey) != self.setupData[compareKey]:
+                valuesDifferent = True
+                self.config.set('DEFAULT', compareKey,
+                    self.setupData[compareKey])
 
-		if not valuesDifferent: return
+        if not valuesDifferent: return
 
-		self.config.write(open(os.path.expanduser('~/.pygiver'), 'w'))
+        self.config.write(open(os.path.expanduser('~/.pygiver'), 'w'))
 
 
-	def loadExistingSetup(self):
-		raise NotImplementedError
+    def loadExistingSetup(self):
+        raise NotImplementedError
 
 
-	def inspectFile(self, path):
-		fp = open(path, 'r')
-		for line in [ fp.readline() for x in range(10) ]:
-			m = re.match(r'^#!.*python((?P<major>\d)(\.\d+)?)?$', line)
-			if m:
-				if m.group('major') == '3':
-					self.classifierDict['Programming Language :: Python :: 3'] = 1
-				else:
-					self.classifierDict['Programming Language :: Python :: 2'] = 1
-		fp.close()
+    def inspectFile(self, path):
+        fp = open(path, 'r')
+        for line in [ fp.readline() for x in range(10) ]:
+            m = re.match(r'^#!.*python((?P<major>\d)(\.\d+)?)?$', line)
+            if m:
+                if m.group('major') == '3':
+                    self.classifierDict['Programming Language :: Python :: 3'] = 1
+                else:
+                    self.classifierDict['Programming Language :: Python :: 2'] = 1
+        fp.close()
 
 
-	def inspectDirectory(self):
-		dirName = os.path.basename(os.getcwd())
-		self.setupData['name'] = dirName
-		m = re.match(r'(.*)-(\d.+)', dirName)
-		if m:
-			self.setupData['name'] = m.group(1)
-			self.setupData['version'] = m.group(2)
+    def inspectDirectory(self):
+        dirName = os.path.basename(os.getcwd())
+        self.setupData['name'] = dirName
+        m = re.match(r'(.*)-(\d.+)', dirName)
+        if m:
+            self.setupData['name'] = m.group(1)
+            self.setupData['version'] = m.group(2)
 
-		for root, dirs, files in os.walk('.'):
-			for file in files:
-				if root == '.' and file == 'setup.py': continue
-				fileName = os.path.join(root, file)
-				self.inspectFile(fileName)
+        for root, dirs, files in os.walk('.'):
+            for file in files:
+                if root == '.' and file == 'setup.py': continue
+                fileName = os.path.join(root, file)
+                self.inspectFile(fileName)
 
-				if file == '__init__.py':
-					trySrc = os.path.join('.', 'src')
-					tmpRoot = root
-					if tmpRoot.startswith(trySrc):
-						tmpRoot = tmpRoot[len(trySrc):]
-					if tmpRoot.startswith(os.path.sep):
-						tmpRoot = tmpRoot[len(os.path.sep):]
+                if file == '__init__.py':
+                    trySrc = os.path.join('.', 'src')
+                    tmpRoot = root
+                    if tmpRoot.startswith(trySrc):
+                        tmpRoot = tmpRoot[len(trySrc):]
+                    if tmpRoot.startswith(os.path.sep):
+                        tmpRoot = tmpRoot[len(os.path.sep):]
 
-					self.setupData['packages'][tmpRoot] = root[1 + len(os.path.sep):]
+                    self.setupData['packages'][tmpRoot] = root[1 + len(os.path.sep):]
 
 
-	def queryUser(self):
-		self.setupData['name'] = ask('Package name', self.setupData['name'],
-		      helpText['name'])
-		self.setupData['version'] = ask('Current version number',
-		      self.setupData.get('version'), helpText['version'])
-		self.setupData['description'] = ask('Package description',
-		      self.setupData.get('description'), helpText['description'],
-		      lengthy = True)
-		self.setupData['author'] = ask('Author name',
-		      self.setupData.get('author'), helpText['author'])
-		self.setupData['author_email'] = ask('Author e-mail address',
-		      self.setupData.get('author_email'), helpText['author_email'])
-		self.setupData['url'] = ask('Project URL',
-		      self.setupData.get('url'), helpText['url'], required = False)
+    def queryUser(self):
+        self.setupData['name'] = ask('Package name', self.setupData['name'],
+              helpText['name'])
+        self.setupData['version'] = ask('Current version number',
+              self.setupData.get('version'), helpText['version'])
+        self.setupData['description'] = ask('Package description',
+              self.setupData.get('description'), helpText['description'],
+              lengthy = True)
+        self.setupData['author'] = ask('Author name',
+              self.setupData.get('author'), helpText['author'])
+        self.setupData['author_email'] = ask('Author e-mail address',
+              self.setupData.get('author_email'), helpText['author_email'])
+        self.setupData['url'] = ask('Project URL',
+              self.setupData.get('url'), helpText['url'], required = False)
 
-		if (askYn('Do you want to set Trove classifiers?',
-				helptext = helpText['do_classifier']) == 'y'):
-			self.setTroveClassifier()
+        if (askYn('Do you want to set Trove classifiers?',
+                helptext = helpText['do_classifier']) == 'y'):
+            self.setTroveClassifier()
 
 
-	def setTroveClassifier(self):
-		self.setTroveDevStatus(self.classifierDict)
-		self.setTroveLicense(self.classifierDict)
-		self.setTroveOther(self.classifierDict)
+    def setTroveClassifier(self):
+        self.setTroveDevStatus(self.classifierDict)
+        self.setTroveLicense(self.classifierDict)
+        self.setTroveOther(self.classifierDict)
 
 
-	def setTroveOther(self, classifierDict):
-		if askYn('Do you want to set other trove identifiers', 'n',
-				helpText['trove_generic']) != 'y': return
+    def setTroveOther(self, classifierDict):
+        if askYn('Do you want to set other trove identifiers', 'n',
+                helpText['trove_generic']) != 'y': return
 
-		self.walkTrove(classifierDict, [troveDict], '')
-	
-	def walkTrove(self, classifierDict, trovePath, desc):
-		trove = trovePath[-1]
+        self.walkTrove(classifierDict, [troveDict], '')
 
-		if not trove:
-			return
+    def walkTrove(self, classifierDict, trovePath, desc):
+        trove = trovePath[-1]
 
-		for key in sorted(trove.keys()):
-			if len(trove[key]) == 0:
-				if askYn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y':
-					classifierDict[desc[4:] + ' :: ' + key] = 1
-				continue
+        if not trove:
+            return
 
-			if askYn('Do you want to set items under\n   "%s" (%d sub-items)'
-					% ( key, len(trove[key]) ), 'n',
-					helpText['trove_generic']) == 'y':
-				self.walkTrove(classifierDict, trovePath + [trove[key]],
-						desc + ' :: ' + key)
+        for key in sorted(trove.keys()):
+            if len(trove[key]) == 0:
+                if askYn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y':
+                    classifierDict[desc[4:] + ' :: ' + key] = 1
+                continue
 
+            if askYn('Do you want to set items under\n   "%s" (%d sub-items)'
+                    % ( key, len(trove[key]) ), 'n',
+                    helpText['trove_generic']) == 'y':
+                self.walkTrove(classifierDict, trovePath + [trove[key]],
+                        desc + ' :: ' + key)
 
-	def setTroveLicense(self, classifierDict):
-		while True:
-			license = ask('What license do you use',
-			      helptext = helpText['trove_license'], required = False)
-			if not license: return
 
-			licenseWords = license.lower().split(' ')
+    def setTroveLicense(self, classifierDict):
+        while True:
+            license = ask('What license do you use',
+                  helptext = helpText['trove_license'], required = False)
+            if not license: return
 
-			foundList = []
-			for index in range(len(troveList)):
-				troveItem = troveList[index]
-				if not troveItem.startswith('License :: '): continue
-				troveItem = troveItem[11:].lower()
+            licenseWords = license.lower().split(' ')
 
-				allMatch = True
-				for word in licenseWords:
-					if not word in troveItem:
-						allMatch = False
-						break
-				if allMatch: foundList.append(index)
+            foundList = []
+            for index in range(len(troveList)):
+                troveItem = troveList[index]
+                if not troveItem.startswith('License :: '): continue
+                troveItem = troveItem[11:].lower()
 
-			question = 'Matching licenses:\n\n'
-			for i in xrange(1, len(foundList) + 1):
-				question += '   %s) %s\n' % ( i, troveList[foundList[i - 1]] )
-			question += ('\nType the number of the license you wish to use or '
-			         '? to try again:')
-			troveLicense = ask(question, required = False)
+                allMatch = True
+                for word in licenseWords:
+                    if not word in troveItem:
+                        allMatch = False
+                        break
+                if allMatch: foundList.append(index)
 
-			if troveLicense == '?': continue
-			if troveLicense == '': return
-			foundIndex = foundList[int(troveLicense) - 1]
-			classifierDict[troveList[foundIndex]] = 1
-			try:
-				return
-			except IndexError:
-				print 'ERROR: Invalid selection, type a number from the list above.'
+            question = 'Matching licenses:\n\n'
+            for i in xrange(1, len(foundList) + 1):
+                question += '   %s) %s\n' % ( i, troveList[foundList[i - 1]] )
+            question += ('\nType the number of the license you wish to use or '
+                     '? to try again:')
+            troveLicense = ask(question, required = False)
 
+            if troveLicense == '?': continue
+            if troveLicense == '': return
+            foundIndex = foundList[int(troveLicense) - 1]
+            classifierDict[troveList[foundIndex]] = 1
+            try:
+                return
+            except IndexError:
+                print("ERROR: Invalid selection, type a number from the list "
+                    "above.")
 
-	def setTroveDevStatus(self, classifierDict):
-		while True:
-			devStatus = ask('''Please select the project status:
+
+    def setTroveDevStatus(self, classifierDict):
+        while True:
+            devStatus = ask('''Please select the project status:
 
 1 - Planning
 2 - Pre-Alpha
@@ -851,71 +853,80 @@
 7 - Inactive
 
 Status''', required = False)
-			if devStatus:
-				try:
-					key = {
-						   '1' : 'Development Status :: 1 - Planning',
-						   '2' : 'Development Status :: 2 - Pre-Alpha',
-						   '3' : 'Development Status :: 3 - Alpha',
-						   '4' : 'Development Status :: 4 - Beta',
-						   '5' : 'Development Status :: 5 - Production/Stable',
-						   '6' : 'Development Status :: 6 - Mature',
-						   '7' : 'Development Status :: 7 - Inactive',
-						   }[devStatus]
-					classifierDict[key] = 1
-					return
-				except KeyError:
-					print 'ERROR: Invalid selection, type a single digit number.'
+            if devStatus:
+                try:
+                    key = {
+                           '1' : 'Development Status :: 1 - Planning',
+                           '2' : 'Development Status :: 2 - Pre-Alpha',
+                           '3' : 'Development Status :: 3 - Alpha',
+                           '4' : 'Development Status :: 4 - Beta',
+                           '5' : 'Development Status :: 5 - Production/Stable',
+                           '6' : 'Development Status :: 6 - Mature',
+                           '7' : 'Development Status :: 7 - Inactive',
+                           }[devStatus]
+                    classifierDict[key] = 1
+                    return
+                except KeyError:
+                    print("ERROR: Invalid selection, type a single digit "
+                        "number.")
 
+    def _dotted_packages(self, data):
+        packages = sorted(data.keys())
+        modified_pkgs = []
+        for pkg in packages:
+            pkg = pkg.lstrip('./')
+            pkg = pkg.replace('/', '.')
+            modified_pkgs.append(pkg)
+        return modified_pkgs
 
-	def writeSetup(self):
-		if os.path.exists('setup.py'): shutil.move('setup.py', 'setup.py.old')
+    def writeSetup(self):
+        if os.path.exists('setup.py'): shutil.move('setup.py', 'setup.py.old')
 
-		fp = open('setup.py', 'w')
-		fp.write('#!/usr/bin/env python\n\n')
-		fp.write('from distutils2.core import setup\n\n')
+        fp = open('setup.py', 'w')
+        fp.write('#!/usr/bin/env python\n\n')
+        fp.write('from distutils2.core import setup\n\n')
 
-		fp.write('from sys import version\n')
-		fp.write('if version < \'2.2.3\':\n')
-		fp.write('    from distutils2.dist import DistributionMetadata\n')
-		fp.write('    DistributionMetadata.classifier = None\n')
-		fp.write('    DistributionMetadata.download_url = None\n')
+        fp.write('from sys import version\n')
+        fp.write('if version < \'2.2.3\':\n')
+        fp.write('    from distutils2.dist import DistributionMetadata\n')
+        fp.write('    DistributionMetadata.classifier = None\n')
+        fp.write('    DistributionMetadata.download_url = None\n')
 
-		fp.write('setup(name = %s,\n' % repr(self.setupData['name']))
-		fp.write('        version = %s,\n' % repr(self.setupData['version']))
-		fp.write('        description = %s,\n'
-				% repr(self.setupData['description']))
-		fp.write('        author = %s,\n' % repr(self.setupData['author']))
-		fp.write('        author_email = %s,\n'
-				% repr(self.setupData['author_email']))
-		if self.setupData['url']:
-			fp.write('        url = %s,\n' % repr(self.setupData['url']))
-		if self.setupData['classifier']:
-			fp.write('        classifier = [\n')
-			for classifier in sorted(self.setupData['classifier'].keys()):
-				fp.write('              %s,\n' % repr(classifier))
-			fp.write('           ],\n')
-		if self.setupData['packages']:
-			fp.write('        packages = %s,\n'
-					% repr(sorted(self.setupData['packages'].keys())))
-			fp.write('        package_dir = %s,\n'
-					% repr(self.setupData['packages']))
-		fp.write('        #scripts = [\'path/to/script\']\n')
+        fp.write('setup(name = %s,\n' % repr(self.setupData['name']))
+        fp.write('        version = %s,\n' % repr(self.setupData['version']))
+        fp.write('        description = %s,\n'
+                % repr(self.setupData['description']))
+        fp.write('        author = %s,\n' % repr(self.setupData['author']))
+        fp.write('        author_email = %s,\n'
+                % repr(self.setupData['author_email']))
+        if self.setupData['url']:
+            fp.write('        url = %s,\n' % repr(self.setupData['url']))
+        if self.setupData['classifier']:
+            fp.write('        classifier = [\n')
+            for classifier in sorted(self.setupData['classifier'].keys()):
+                fp.write('              %s,\n' % repr(classifier))
+            fp.write('           ],\n')
+        if self.setupData['packages']:
+            fp.write('        packages = %s,\n'
+                    % repr(self._dotted_packages(self.setupData['packages'])))
+            fp.write('        package_dir = %s,\n'
+                    % repr(self.setupData['packages']))
+        fp.write('        #scripts = [\'path/to/script\']\n')
 
-		fp.write('        )\n')
-		fp.close()
-		os.chmod('setup.py', 0755)
+        fp.write('        )\n')
+        fp.close()
+        os.chmod('setup.py', 0755)
 
-		print 'Wrote "setup.py".'
+        print 'Wrote "setup.py".'
 
 
 def main():
-	setup = SetupClass()
-	setup.inspectDirectory()
-	setup.queryUser()
-	setup.updateConfigFile()
-	setup.writeSetup()
+    setup = SetupClass()
+    setup.inspectDirectory()
+    setup.queryUser()
+    setup.updateConfigFile()
+    setup.writeSetup()
 
 
 if __name__ == '__main__':
-	main()
+    main()

--
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list