Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #13 (closed defect: fixed)

Opened 12 years ago

Last modified 10 years ago

Make sure all files that need to be distributed with an app appear in the egg

Reported by: kevin Owned by: anonymous
Priority: normal Milestone: 0.8
Component: TurboGears Version:
Severity: normal Keywords:
Cc:

Description

Some people may build an egg without committing to svn or cvs. If that's the case, the quickstart-generated setup file should make sure that all of the needed files appear in the egg.

Change History

comment:1 Changed 12 years ago by kevin

  • Status changed from new to assigned

Ian Bicking has a find_package_data function that can help with this: # Note: you may want to copy this into your setup.py file verbatim, as # you can't import this from another package, when you don't know if # that package is installed yet.

import os import sys from fnmatch import fnmatchcase from distutils.util import convert_path

# Provided as an attribute, so you can append to these instead # of replicating them: standard_exclude = ('*.py', '*.pyc', '*~', '.*', '*.bak') standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',

'./dist', 'EGG-INFO', '*.egg-info')

def find_package_data(

where='.', package=, exclude=standard_exclude, exclude_directories=standard_exclude_directories, only_in_packages=True, show_ignored=False): """ Return a dictionary suitable for use in package_data in a distutils setup.py file.

The dictionary looks like

{'package': [files]}

Where files is a list of all the files in that package that don't match anything in exclude.

If only_in_packages is true, then top-level directories that are not packages won't be included (but directories under packages will).

Directories matching any pattern in exclude_directories will be ignored; by default directories with leading ., CVS, and _darcs will be ignored.

If show_ignored is true, then all the files that aren't included in package data are shown on stderr (for debugging purposes).

Note patterns use wildcards, or can be exact paths (including leading ./), and all searching is case-insensitive. """

out = {} stack = [(convert_path(where), , package, only_in_packages)] while stack:

where, prefix, package, only_in_packages = stack.pop(0) for name in os.listdir(where):

fn = os.path.join(where, name) if os.path.isdir(fn):

bad_name = False for pattern in exclude_directories:

if (fnmatchcase(name, pattern)

or fn.lower() == pattern.lower()): bad_name = True if show_ignored:

print >> sys.stderr, (

"Directory %s ignored by pattern %s" % (fn, pattern))

break

if bad_name:

continue

if os.path.isfile(os.path.join(fn, 'init.py')):

if not package:

new_package = name

else:

new_package = package + '.' + name

stack.append((fn, , new_package, False))

else:

stack.append((fn, prefix + name + '/', package, only_in_packages))

elif package or not only_in_packages:

# is a file bad_name = False for pattern in exclude:

if (fnmatchcase(name, pattern)

or fn.lower() == pattern.lower()): bad_name = True if show_ignored:

print >> sys.stderr, (

"File %s ignored by pattern %s" % (fn, pattern))

break

if bad_name:

continue

out.setdefault(package, []).append(prefix+name)

return out

if name == 'main':

import sys, pprint pprint.pprint(

find_package_data(show_ignored=True))

comment:2 Changed 12 years ago by kevin

Grr... here's a better version of that:

# Note: you may want to copy this into your setup.py file verbatim, as
# you can't import this from another package, when you don't know if
# that package is installed yet.

import os
import sys
from fnmatch import fnmatchcase
from distutils.util import convert_path

# Provided as an attribute, so you can append to these instead
# of replicating them:
standard_exclude = ('*.py', '*.pyc', '*~', '.*', '*.bak')
standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
                                './dist', 'EGG-INFO', '*.egg-info')

def find_package_data(
    where='.', package='',
    exclude=standard_exclude,
    exclude_directories=standard_exclude_directories,
    only_in_packages=True,
    show_ignored=False):
    """
    Return a dictionary suitable for use in ``package_data``
    in a distutils ``setup.py`` file.

    The dictionary looks like::

        {'package': [files]}

    Where ``files`` is a list of all the files in that package that
    don't match anything in ``exclude``.

    If ``only_in_packages`` is true, then top-level directories that
    are not packages won't be included (but directories under packages
    will).

    Directories matching any pattern in ``exclude_directories`` will
    be ignored; by default directories with leading ``.``, ``CVS``,
    and ``_darcs`` will be ignored.

    If ``show_ignored`` is true, then all the files that aren't
    included in package data are shown on stderr (for debugging
    purposes).

    Note patterns use wildcards, or can be exact paths (including
    leading ``./``), and all searching is case-insensitive.
    """
    
    out = {}
    stack = [(convert_path(where), '', package, only_in_packages)]
    while stack:
        where, prefix, package, only_in_packages = stack.pop(0)
        for name in os.listdir(where):
            fn = os.path.join(where, name)
            if os.path.isdir(fn):
                bad_name = False
                for pattern in exclude_directories:
                    if (fnmatchcase(name, pattern)
                        or fn.lower() == pattern.lower()):
                        bad_name = True
                        if show_ignored:
                            print >> sys.stderr, (
                                "Directory %s ignored by pattern %s"
                                % (fn, pattern))
                        break
                if bad_name:
                    continue
                if os.path.isfile(os.path.join(fn, '__init__.py')):
                    if not package:
                        new_package = name
                    else:
                        new_package = package + '.' + name
                    stack.append((fn, '', new_package, False))
                else:
                    stack.append((fn, prefix + name + '/', package, only_in_packages))
            elif package or not only_in_packages:
                # is a file
                bad_name = False
                for pattern in exclude:
                    if (fnmatchcase(name, pattern)
                        or fn.lower() == pattern.lower()):
                        bad_name = True
                        if show_ignored:
                            print >> sys.stderr, (
                                "File %s ignored by pattern %s"
                                % (fn, pattern))
                        break
                if bad_name:
                    continue
                out.setdefault(package, []).append(prefix+name)
    return out

if __name__ == '__main__':
    import sys, pprint
    pprint.pprint(
        find_package_data(show_ignored=True))

comment:3 Changed 12 years ago by kevin

  • Status changed from assigned to closed
  • Resolution set to fixed

Fixed in [47].

Note: See TracTickets for help on using tickets.