[Zope-CVS] SVN: zpkgtools/trunk/ Split the zpkgtools Python package
into two packages:
Fred L. Drake, Jr.
fred at zope.com
Thu Jun 17 12:12:11 EDT 2004
Log message for revision 25887:
Split the zpkgtools Python package into two packages:
a build/install runtime component (zpkgsetup) and a distribution builder
component (zpkgtools).
This helps keep the size of the code added to a distribution small.
-=-
Modified: zpkgtools/trunk/bin/zpkg
===================================================================
--- zpkgtools/trunk/bin/zpkg 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/bin/zpkg 2004-06-17 16:12:11 UTC (rev 25887)
@@ -25,8 +25,9 @@
sys.path.append(basedir)
import zpkgtools
+from zpkgsetup import loggingapi as logging
+
from zpkgtools import app
-from zpkgtools import loggingapi as logging
if __name__ == "__main__":
Modified: zpkgtools/trunk/doc/zpkg.txt
===================================================================
--- zpkgtools/trunk/doc/zpkg.txt 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/doc/zpkg.txt 2004-06-17 16:12:11 UTC (rev 25887)
@@ -60,7 +60,7 @@
-S
Don't include the required support packages in the distribution.
This can be used to generate smaller distributions when the
- ``setuptools`` and ``zpkgtools`` packages are known to be available
+ ``setuptools`` and ``zpkgsetup`` packages are known to be available
on target systems.
-v VERSION
@@ -97,7 +97,7 @@
bundles the support code along with the resulting distribution. The
value is a boolean, where the strings ``true`` and ``false`` can be
used in the configuration file. If true (the default), copies of the
-``zpkgtools`` and ``setuptools`` packages will be included in the
+``zpkgsetup`` and ``setuptools`` packages will be included in the
distribution (less their test code). If false, the packages will be
assumed to be available for import on target systems.
@@ -217,8 +217,8 @@
using a ``file:`` URL::
setuptools file:///home/myuser/stuff/setuptools/setuptools
- zpkgtools file:///home/myuser/stuff/zpkgtools/zpkgtools
+ zpkgsetup file:///home/myuser/stuff/zpkgtools/zpkgsetup
(The path should identify the directory that contains the
-``setuptools`` or ``zpkgtools`` package itself, not the directory that
+``setuptools`` or ``zpkgsetup`` package itself, not the directory that
would be on ``sys.path`` to allow it to be importable.)
Modified: zpkgtools/trunk/test.py
===================================================================
--- zpkgtools/trunk/test.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/test.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -27,8 +27,16 @@
print >>sys.stderr, \
"arguments only supported when zope.app.tests is available"
sys.exit(2)
- from zpkgtools.tests import runtests
- runtests.MyTestProgram(defaultTest="runtests.test_suite")
+
+ def test_suite():
+ from zpkgsetup.tests import runtests
+ suite = runtests.test_suite()
+ from zpkgtools.tests import runtests
+ suite.addTest(runtests.test_suite())
+ return suite
+
+ from zpkgsetup.tests import runtests
+ runtests.MyTestProgram(defaultTest="test_suite")
else:
# 1. search for tests in starting in this directory
# 2. there are only unit tests, not functional tests
Added: zpkgtools/trunk/zpkgsetup/__init__.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/__init__.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgsetup/__init__.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Zope packaging utilities runtime support.
+
+:organization: Zope Corporation
+:license: `Zope Public License, Version 2.0 (ZPL)`__
+:status: Prototype implementation
+
+This package contains the build/install support for distributions
+built using the **zpkg** tool.
+
+.. __: http://www.zope.org/Resources/ZPL/ZPL-2.0
+
+"""
+
+
+class Error(Exception):
+ """Base class for exceptions raised by zpkgsetup."""
Property changes on: zpkgtools/trunk/zpkgsetup/__init__.py
___________________________________________________________________
Name: svn:mime-type
+ text/x-python
Name: svn:eol-style
+ native
Copied: zpkgtools/trunk/zpkgsetup/cfgparser.py (from rev 25884, zpkgtools/trunk/zpkgtools/cfgparser.py)
Copied: zpkgtools/trunk/zpkgsetup/loggingapi.py (from rev 25884, zpkgtools/trunk/zpkgtools/loggingapi.py)
Copied: zpkgtools/trunk/zpkgsetup/package.py (from rev 25884, zpkgtools/trunk/zpkgtools/package.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/package.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/package.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,518 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Support for handling package configuration files.
+
+The package configuration files handled by this module provide
+information about the software and documentation contents of a
+distribution component. The same kinds of information can be
+described for any component, with the exception that extensions only
+make sense for package components.
+
+Package configuration files use a syntax very like the `ZConfig`_
+package, but fewer features are available. The specific syntax is
+implemented by the `cfgparser` module.
+
+.. _ZConfig: http://www.zope.org/Members/fdrake/zconfig/
+
+There are only a few types of information which can appear in a
+package configuration file; the file is intended to describe what a
+package provides that is not a module or data file. The three types
+of things which can be listed in the file are:
+
+- scripts
+- documentation
+- extensions
+
+The scripts and documentation files are listed very simply::
+
+ documentation *.txt
+ documentation apiref.pdf
+
+ script scritps/*
+
+The value to the right of the identifying keyword is a portable glob
+pattern, where *portable* here means the pattern uses the POSIX
+notation. Path components should be separated by forward slashes
+(like all paths used with distutils), ``?`` can be replaced by any
+single character, and ``*`` can be replaced by zero or more
+characters.
+
+
+:Variables:
+ - `PACKAGE_CONF`: Name of the package information file.
+
+:Groups:
+ - `Public interface`: loadCollectionInfo loadPackageInfo
+ - `Helper functions`: create_extension expand_globs read_package_info
+ - `Datatype functions`: cpp_definition cpp_names path_ref extension
+
+"""
+
+import glob
+import os
+import posixpath
+import re
+import urllib
+
+from distutils.core import Extension
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+
+
+PACKAGE_CONF = "SETUP.cfg"
+
+
+def loadPackageInfo(pkgname, directory, reldir):
+ """Load package information for a Python package.
+
+ :return: Package information object.
+
+ :Parameters:
+ - `pkgname`: Full name of the Python package to which the
+ information being read applies. This is needed to construct
+ Extension objects properly.
+ - `directory`: Directory containing the package's __init__.py file.
+ - `reldir`: Relative directory path with which file names from
+ the information file will be joined. This should be in POSIX
+ notation. It will not be used to locate files.
+
+ """
+ pkginfo = read_package_info(directory, reldir)
+ pkginfo.extensions = [create_extension(ext, pkgname, reldir)
+ for ext in pkginfo.extension]
+ return pkginfo
+
+
+def loadCollectionInfo(directory, reldir):
+ """Load package information for a collection.
+
+ :return: Package information object.
+
+ :Parameters:
+ - `directory`: Directory containing the collection's files.
+ - `reldir`: Relative directory path with which file names from
+ the information file will be joined. This should be in POSIX
+ notation. It will not be used to locate files.
+
+ """
+ pkginfo = read_package_info(directory, reldir)
+ if pkginfo.extension:
+ raise ValueError("extensions cannot be defined in collections")
+ pkginfo.extensions = []
+ return pkginfo
+
+
+def read_package_info(directory, reldir=None):
+ """Read the package information file from a specified directory.
+
+ :return: Package information object.
+
+ :Parameters:
+ - `directory`: Directory containing the collection's files.
+ - `reldir`: Relative directory path with which file names from
+ the information file will be joined. This should be in POSIX
+ notation. It will not be used to locate files. It may be
+ omitted or None; if so, filenames are not 'relocated' relative
+ to where they are found.
+
+ """
+ path = os.path.join(directory, PACKAGE_CONF)
+ if os.path.exists(path):
+ path = os.path.realpath(path)
+ url = "file://" + urllib.pathname2url(path)
+ f = open(path)
+ else:
+ # Initialize using the cfgparser so we still get a package
+ # data object with the right attributes:
+ url = "<no file>"
+ f = StringIO("")
+ try:
+ p = cfgparser.Parser(f, url, PackageSchema(directory, reldir))
+ pkginfo = p.load()
+ finally:
+ f.close()
+ pkginfo.documentation = expand_globs(directory, reldir,
+ pkginfo.documentation)
+ pkginfo.header = expand_globs(directory, reldir, pkginfo.header)
+ pkginfo.script = expand_globs(directory, reldir, pkginfo.script)
+
+ # need to post-process the data_files so included directories are
+ # handled properly; distutils expects everything to be a file!
+ #
+ # XXX need tests!
+ #
+ datamap = {}
+ for dir, paths in pkginfo.data_files:
+ expand_data(directory, reldir, dir, paths, datamap)
+ if "." in datamap and datamap["."] == []:
+ del datamap["."]
+ pkginfo.data_files = datamap.items()
+
+ return pkginfo
+
+
+def expand_data(directory, reldir, targetdir, paths, datamap):
+ #
+ # `directory` is where we find things
+ #
+ # `reldir` is the relative location of directory in the source; we
+ # need it so we can rip it off of the values in `paths`
+ #
+ # `targetdir` is where we want the things in `paths` copied in
+ # POSIX notation
+ #
+ # `paths` is a list of paths to things we want copied, in POSIX
+ # notation, with `reldir` prepended
+ #
+ # `datamap` is a mapping from target directory -> [files], where
+ # files are really paths to actual files (not directories!) that
+ # are to be copied to the target directory; the file paths are
+ # given in POSIX notation and are prefixed by `reldir`
+ #
+ # All directories must be represented in the data map, even if
+ # they're empty.
+ #
+ targetdir = posixpath.normpath(targetdir)
+
+ # Make sure there's an entry for every directory we look at; that
+ # ensures distutils will create empty directories for us.
+ L = datamap.setdefault(targetdir, [])
+
+ if reldir:
+ prefix = posixpath.join(reldir, "")
+ else:
+ prefix = ""
+
+ # for files, add to the list, otherwise recursively scan
+ for src in paths:
+ # strip `reldir`, convert to local path notation
+ localpath = src[len(prefix):].replace("/", os.sep)
+ # find the referenced path
+ fullpath = os.path.join(directory, localpath)
+ if os.path.isfile(fullpath):
+ L.append(src)
+ else:
+ # directory; recurse
+ basename = os.path.basename(fullpath)
+ expand_data(
+ directory, reldir, posixpath.join(targetdir, basename),
+ [posixpath.join(src, name) for name in os.listdir(fullpath)],
+ datamap)
+
+
+def create_extension(section, pkgname, reldir):
+ """Create an `Extension` instance from a configuration section.
+
+ :Parameters:
+ - `section`: Section object from the configuration file.
+ - `pkgname`: Full name of the containing package. This should
+ be an empty string or ``None`` if the extension is not in a
+ package.
+ - `reldir`: Directory in which the extension lives, relative to
+ the top of the distribution, given in POSIX notation.
+
+ """
+ kwargs = {}
+ if pkgname:
+ kwargs["name"] = "%s.%s" % (pkgname, section.name)
+ else:
+ kwargs["name"] = section.name
+ kwargs["sources"] = [posixpath.join(reldir, fn)
+ for fn in section.source]
+ if section.define:
+ kwargs["define_macros"] = section.define
+ if section.undefine:
+ kwargs["undef_macros"] = undefs = []
+ for L in section.undefine:
+ undefs.extend(L)
+ if section.depends_on:
+ kwargs["depends"] = [posixpath.join(reldir, fn)
+ for fn in section.depends_on]
+ if section.language:
+ kwargs["language"] = section.language[0]
+ if reldir and reldir != ".":
+ kwargs["include_dirs"] = [reldir]
+ return Extension(**kwargs)
+
+
+def expand_globs(directory, reldir, globlist):
+ """Expand glob patterns for directory.
+
+ :Parameters:
+ - `directory`: The path to the directory to which the glob
+ patterns are relative to.
+ - `reldir`: Base directory to use for returning glob expansions.
+ This should be a relative path in POSIX notation. This is not
+ used for locating files.
+ - `globlist`: List of glob patterns in POSIX notation. The
+ patterns may refer to child directories of `directory`.
+
+ :return: List of expansions in POSIX notation, using `reldir` as
+ the base directory.
+
+ Note that `directory` and `reldir` are two different names for the
+ same directory.
+
+ :warning: This function is not thread safe, as it changes the
+ current working directory while it is running.
+
+ """
+ results = []
+ pwd = os.getcwd()
+ os.chdir(directory)
+ try:
+ for g in globlist:
+ gs = g.replace("/", os.sep)
+ filenames = glob.glob(gs)
+ if not filenames:
+ raise ValueError(
+ "filename pattern %r doesn't match any files" % g)
+ filenames = [fn.replace(os.sep, "/") for fn in filenames]
+ if reldir:
+ filenames = [posixpath.join(reldir, fn) for fn in filenames]
+ results += filenames
+ finally:
+ os.chdir(pwd)
+ return results
+
+
+# datatype functions referenced by the schema:
+
+def cpp_definition(s):
+ r"""Return a 2-tuple representing a CPP #define.
+
+ :rtype: (str, str or None)
+
+ The first element of the tuple is the name to define, and the
+ second is the value to use as the replacement text. In the input,
+ the two parts should be separated by an equal sign.
+
+ >>> cpp_definition('NAME=VALUE')
+ ('NAME', 'VALUE')
+ >>> cpp_definition('NAME=')
+ ('NAME', '')
+
+ Whitespace around the equal sign are ignored:
+
+ >>> cpp_definition('NAME =\tVALUE')
+ ('NAME', 'VALUE')
+
+ If there is no equal sign, and defininition with no replacement
+ text is used (equivalent to '#define NAME'):
+
+ >>> cpp_definition('NAME')
+ ('NAME', None)
+
+ ValueError is raised if there is an error in the input:
+
+ >>> cpp_definition('not-a-cpp-symbol')
+ Traceback (most recent call last):
+ ...
+ ValueError: not a valid C identifier: 'not-a-cpp-symbol'
+
+ """
+ if "=" in s:
+ name, value = s.split("=", 1)
+ name = name.rstrip()
+ value = value.lstrip()
+ else:
+ name = s
+ value = None
+ if _cpp_ident_match(name) is None:
+ raise ValueError("not a valid C identifier: %r" % name)
+ return name, value
+
+
+def cpp_names(s):
+ r"""Return a list of CPP symbols from a string.
+
+ :rtype: [str, ...]
+
+ >>> cpp_names('NAME')
+ ['NAME']
+ >>> cpp_names('NAME1 NAME_2 A_B_C A123')
+ ['NAME1', 'NAME_2', 'A_B_C', 'A123']
+
+ If something is included which is not a valid identifier for CPP,
+ ValueError is raised:
+
+ >>> cpp_names('not-really!')
+ Traceback (most recent call last):
+ ...
+ ValueError: not a valid C identifier: 'not-really!'
+
+ >>> cpp_names('NAME ANOTHER not-really!')
+ Traceback (most recent call last):
+ ...
+ ValueError: not a valid C identifier: 'not-really!'
+
+ """
+ names = s.split()
+ for name in names:
+ if _cpp_ident_match(name) is None:
+ raise ValueError("not a valid C identifier: %r" % name)
+ return names
+
+_cpp_ident_match = re.compile("[A-Za-z_][A-Za-z_0-9]*$").match
+
+
+def extension(section):
+ """Transform `section`, checking several fields for valid values.
+
+ :param section: Configuration section.
+ :return: Modified section.
+ """
+ section.name = section.getSectionName()
+ if not section.name:
+ raise ValueError("extensions must be named")
+ if not section.source:
+ raise ValueError("at least one extension source file must be listed")
+ if len(section.language) > 1:
+ raise ValueError("language can only be specified once")
+ return section
+
+
+def path_ref(s):
+ """Datatype for a local path reference.
+
+ :rtype: str
+
+ >>> path_ref('README.txt')
+ 'README.txt'
+ >>> path_ref('./README.txt')
+ 'README.txt'
+ >>> path_ref('foo/bar/file.txt')
+ 'foo/bar/file.txt'
+
+ If a reference is not a relative path, ValueError is raised:
+
+ >>> path_ref('/absolute/path')
+ Traceback (most recent call last):
+ ...
+ ValueError: absolute paths are not allowed: '/absolute/path'
+
+ >>> path_ref('/')
+ Traceback (most recent call last):
+ ...
+ ValueError: absolute paths are not allowed: '/'
+
+ References which contain Windows drive letters are not allowed:
+
+ >>> path_ref('c:README.txt')
+ Traceback (most recent call last):
+ ...
+ ValueError: Windows drive letters are not allowed: 'c:README.txt'
+
+ If a reference is relative but points outside the local directory
+ hierarchy, ValueError is raised:
+
+ >>> path_ref('../somefile')
+ Traceback (most recent call last):
+ ...
+ ValueError: relative paths may not point outside the containing tree: '../somefile'
+
+ """
+ if not s:
+ raise ValueError("path references may not be empty")
+ if s.find(":") == 1:
+ # looks like a windows drive letter:
+ raise ValueError("Windows drive letters are not allowed: %r" % s)
+ p = posixpath.normpath(s)
+ if p[:1] == "/":
+ raise ValueError("absolute paths are not allowed: %r" % s)
+ parts = p.split("/")
+ if parts[0] == "..":
+ raise ValueError("relative paths may not point outside"
+ " the containing tree: %r" % s)
+ return p
+
+
+class PackageSchema(cfgparser.Schema):
+ """Schema implementation with a <data-files> section type.
+
+ The <data-files> sections have keys that are glob-expanded (based
+ on information passed to the constructor) and combined into a
+ single .data_files member on the resulting package information
+ object. The value of the .data_files attribute is suitable for
+ passing to the distutils.core.setup() function.
+
+ """
+
+ def __init__(self, directory, reldir):
+ cfgparser.Schema.__init__(
+ self,
+ ({"script": path_ref,
+ "documentation": path_ref,
+ "header": path_ref},
+ ["extension"], None),
+ {"extension": ({"source": path_ref, "depends-on": path_ref,
+ "define" : cpp_definition, "undefine": cpp_names,
+ "language": str,
+ },
+ (), extension),
+ }
+ )
+ self.__cf = None
+ self.__datafiles = None
+ self.__directory = directory
+ self.__reldir = reldir
+
+ def getConfiguration(self):
+ assert self.__cf is None
+ self.__cf = cfgparser.Schema.getConfiguration(self)
+ self.__cf.data_files = []
+ return self.__cf
+
+ def startSection(self, parent, typename, name):
+ if self.__datafiles is not None:
+ raise cfgparser.ConfigurationError(
+ "can't nest another section inside <data-files> section")
+ if typename == "data-files":
+ if not name:
+ raise cfgparser.ConfigurationError(
+ "<data-files> section must have a name")
+ normname = posixpath.normpath(name)
+ for target, files in self.__cf.data_files:
+ if target == normname:
+ raise cfgparser.ConfigurationError(
+ "can't have two sections of the same name:"
+ " <data-files %s>" % name)
+ self.__datafiles = []
+ self.__cf.data_files.append((normname, self.__datafiles))
+ # The return value is passed around, but that's it
+ return ()
+ else:
+ return cfgparser.Schema.startSection(self, parent, typename, name)
+
+ def endSection(self, parent, typename, name, child):
+ if self.__datafiles is None:
+ cfgparser.Schema.endSection(self, parent, typename, name, child)
+ else:
+ # mutate self.__datafiles since the reference from
+ # self.__cf.data_files is what's actually used
+ self.__datafiles[:] = expand_globs(self.__directory,
+ self.__reldir,
+ self.__datafiles)
+ self.__datafiles = None
+
+ def addValue(self, section, key, value):
+ if self.__datafiles is not None:
+ if value:
+ raise cfgparser.ConfigurationError(
+ "each entry in a <data-files> section must be"
+ " a single glob pattern")
+ self.__datafiles.append(key)
+ else:
+ cfgparser.Schema.addValue(self, section, key, value)
Copied: zpkgtools/trunk/zpkgsetup/publication.py (from rev 25884, zpkgtools/trunk/zpkgtools/publication.py)
Copied: zpkgtools/trunk/zpkgsetup/setup.py (from rev 25884, zpkgtools/trunk/zpkgtools/setup.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/setup.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/setup.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,245 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Generator for distutils setup.py files.
+
+:Variables:
+ - `EXCLUDE_NAMES`: Names of files and directories that will be
+ excluded from copying. These are generally related to source
+ management systems, but don't need to be.
+
+ - `EXCLUDE_PATTERNS`: Glob patterns used to filter the set of files
+ that are copied. Any file with a name matching these patterns
+ will be ignored.
+
+"""
+
+import errno
+import fnmatch
+import os
+import posixpath
+import re
+import sys
+
+from zpkgsetup import package
+from zpkgsetup import publication
+
+
+# Names that are exluded from globbing results:
+EXCLUDE_NAMES = ["CVS", ".cvsignore", "RCS", "SCCS", ".svn"]
+EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~"]
+
+def filter_names(names):
+ """Given a list of file names, return those names that should be copied.
+ """
+ names = [n for n in names
+ if n not in EXCLUDE_NAMES]
+ # This is needed when building a distro from a working
+ # copy (likely a checkout) rather than a pristine export:
+ for pattern in EXCLUDE_PATTERNS:
+ names = [n for n in names
+ if not fnmatch.fnmatch(n, pattern)]
+ return names
+
+
+class SetupContext:
+ """Object representing the arguments to distutils.core.setup()."""
+
+ def __init__(self, pkgname, version, setup_file):
+ self._working_dir = os.path.dirname(os.path.abspath(setup_file))
+ self._pkgname = pkgname
+ self.version = version
+ self.packages = []
+ self.package_data = {}
+ self.package_dir = {}
+ self.ext_modules = []
+ self.scripts = []
+ self.platforms = None
+ self.classifiers = None
+ self.data_files = []
+
+ def initialize(self):
+ self.load_metadata(
+ os.path.join(self._working_dir, self._pkgname,
+ publication.PUBLICATION_CONF))
+ pkgdir = os.path.join(self._working_dir, self._pkgname)
+ self.scan(self._pkgname, pkgdir, self._pkgname)
+ depsdir = os.path.join(self._working_dir, "Dependencies")
+ if os.path.isdir(depsdir):
+ depnames = os.listdir(depsdir)
+ suffix = "-%s-%s" % (self._pkgname, self.version)
+ for name in depnames:
+ if name != "Includes" and not name.endswith(suffix):
+ # an unexpected name; we didn't put this here!
+ print >>sys.stderr, \
+ "unexpected name in Dependencies/: %r" % name
+ continue
+ depdir = os.path.join(depsdir, name)
+ if not os.path.isdir(depdir):
+ # a file; we didn't put this here either!
+ print >>sys.stderr, \
+ "unexpected file in Dependencies/: %r" % name
+ continue
+ depname = name[:-len(suffix)]
+ pkgdir = os.path.join(depdir, depname)
+ reldir = posixpath.join("Dependencies", name, depname)
+ self.scan(depname, pkgdir, reldir)
+ includes_dir = os.path.join(depsdir, "Includes")
+ if os.path.isdir(includes_dir):
+ for ext in self.ext_modules:
+ ext.include_dirs.append(includes_dir)
+
+ def setup(self):
+ kwargs = self.__dict__.copy()
+ for name in self.__dict__:
+ if name[0] == "_":
+ del kwargs[name]
+ if "--debug" in sys.argv:
+ import pprint
+ try:
+ pprint.pprint(kwargs)
+ except IOError, e:
+ if e.errno != errno.EPIPE:
+ raise
+ else:
+ if sys.version_info < (2, 3):
+ from distutils.dist import DistributionMetadata
+ DistributionMetadata.classifiers = None
+ DistributionMetadata.download_url = None
+ try:
+ from setuptools import setup
+ except ImportError:
+ # package_data can't be handled this way ;-(
+ if self.package_data:
+ print >>sys.stderr, (
+ "can't import setuptools;"
+ " some package data will not be properly installed")
+ from distutils.core import setup
+ setup(**kwargs)
+
+ def load_metadata(self, path):
+ f = open(path, "rU")
+ publication.load(f, metadata=self)
+ if self.platforms:
+ self.platforms = ", ".join(self.platforms)
+ m = re.match(r"\d+\.\d+(\.\d+)?(?:(?P<status>[ab])\d*)?$",
+ self.version)
+ if m is not None:
+ devstatus = publication.STABLE
+ status = m.group("status")
+ if status == "a":
+ devstatus = publication.ALPHA
+ elif status == "b":
+ devstatus = publication.BETA
+ publication.set_development_status(self, devstatus)
+
+ def scan(self, name, directory, reldir):
+ init_py = os.path.join(directory, "__init__.py")
+ if os.path.isfile(init_py):
+ self.scan_package(name, directory, reldir)
+ else:
+ self.scan_collection(name, directory, reldir)
+
+ def scan_collection(self, name, directory, reldir):
+ # load the collection metadata
+ pkginfo = package.loadCollectionInfo(directory, reldir)
+ self.scan_basic(pkginfo)
+
+ def scan_package(self, name, directory, reldir):
+ # load the package metadata
+ pkginfo = package.loadPackageInfo(name, directory, reldir)
+ self.scan_basic(pkginfo)
+ self.ext_modules.extend(pkginfo.extensions)
+ self.add_package_dir(name, reldir)
+
+ # scan the files in the directory:
+ files = filter_names(os.listdir(directory))
+ for fn in files:
+ fnbase, ext = os.path.splitext(fn)
+ path = os.path.join(directory, fn)
+ if os.path.isdir(path):
+ init_py = os.path.join(path, "__init__.py")
+ if os.path.isfile(init_py):
+ # if this package is published separately, skip it:
+ # XXX we shouldn't actually need this if we only
+ # use this class to scan in the generated
+ # distributions
+ if os.path.isfile(
+ os.path.join(path, publication.PUBLICATION_CONF)):
+ continue
+ pkgname = "%s.%s" % (name, fn)
+ self.scan_package(
+ pkgname, path, posixpath.join(reldir, fn))
+ else:
+ # an ordinary directory
+ self.scan_directory(name, path, fn)
+ # Only add the file as package data if it's not a Python
+ # source file; Python files are copied in automatically.
+ elif not fn.endswith(".py"):
+ self.add_package_file(name, fn)
+
+ # We need to check that any files that were labelled as
+ # scripts or application data aren't copied in as package
+ # data; they shouldn't be installed into the package itself.
+ #
+ # XXX I'm not sure whether documentation files should be
+ # removed from package_data or not, given that there's no spec
+ # for installing documentation other than for RPMs.
+ #
+ relbase = posixpath.join(reldir, "")
+ pkgfiles = self.package_data.get(name, [])
+ non_pkgdata = pkginfo.script + pkginfo.header
+ for dir, files in pkginfo.data_files:
+ non_pkgdata.extend(files)
+ for ext in pkginfo.extensions:
+ for fn in ext.sources + getattr(ext, "depends", []):
+ if fn not in non_pkgdata:
+ non_pkgdata.append(fn)
+ for fn in non_pkgdata:
+ pkgdatapath = fn[len(relbase):]
+ if pkgdatapath in pkgfiles:
+ pkgfiles.remove(pkgdatapath)
+
+ def scan_directory(self, pkgname, directory, reldir):
+ """Scan a data directory, adding files to package_data."""
+ files = filter_names(os.listdir(directory))
+ for fn in files:
+ path = os.path.join(directory, fn)
+ if os.path.isdir(path):
+ self.scan_directory(pkgname,
+ os.path.join(directory, fn),
+ posixpath.join(reldir, fn))
+ else:
+ self.add_package_file(pkgname, posixpath.join(reldir, fn))
+
+ def scan_basic(self, pkginfo):
+ self.scripts.extend(pkginfo.script)
+ if pkginfo.data_files:
+ if self.data_files:
+ # merge:
+ d = dict(self.data_files)
+ for dir, files in pkginfo.data_files:
+ L = d.setdefault(dir, [])
+ L.extend(files)
+ self.data_files = d.items()
+ else:
+ self.data_files = pkginfo.data_files
+
+ def add_package_dir(self, pkgname, reldir):
+ self.packages.append(pkgname)
+ if pkgname.replace(".", "/") != reldir:
+ self.package_dir[pkgname] = reldir
+
+ def add_package_file(self, pkgname, relfn):
+ L = self.package_data.setdefault(pkgname, [])
+ L.append(relfn)
Copied: zpkgtools/trunk/zpkgsetup/tests/input/package (from rev 25884, zpkgtools/trunk/zpkgtools/tests/input/package)
Copied: zpkgtools/trunk/zpkgsetup/tests/input/package2 (from rev 25884, zpkgtools/trunk/zpkgtools/tests/input/package2)
Added: zpkgtools/trunk/zpkgsetup/tests/runtests.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/tests/runtests.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgsetup/tests/runtests.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+##############################################################################
+#
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Script to run all the regression tests for zpkgtools."""
+
+import os
+import sys
+import unittest
+
+if __name__ == "__main__":
+ __file__ = sys.argv[0]
+
+TESTDIR = os.path.dirname(os.path.abspath(__file__))
+
+PKGDIR = os.path.dirname(TESTDIR) # the package directory
+TOPDIR = os.path.dirname(PKGDIR)
+
+
+def load_tests(name):
+ __import__(name)
+ mod = sys.modules[name]
+ return mod.test_suite()
+
+
+def make_directory_suite(pkgname, testdir):
+ L = []
+ for fn in os.listdir(testdir):
+ name, ext = os.path.splitext(fn)
+ if name[:4] == "test" and ext == ".py":
+ L.append(load_tests("%s.%s" % (pkgname, name)))
+ suite = L.pop()
+ for t in L:
+ suite.addTest(t)
+ return suite
+
+
+def test_suite():
+ return make_directory_suite("zpkgsetup.tests", TESTDIR)
+
+
+class MyTestProgram(unittest.TestProgram):
+ """Test runner program that doesn't use docstrings as descriptions."""
+
+ def runTests(self):
+ if self.testRunner is None:
+ self.testRunner = unittest.TextTestRunner(descriptions=False,
+ verbosity=self.verbosity)
+ unittest.TestProgram.runTests(self)
+
+
+if __name__ == "__main__":
+ if TOPDIR not in sys.path:
+ sys.path.insert(0, TOPDIR)
+ MyTestProgram(defaultTest="test_suite")
Property changes on: zpkgtools/trunk/zpkgsetup/tests/runtests.py
___________________________________________________________________
Name: svn:mime-type
+ text/x-python
Name: svn:eol-style
+ native
Copied: zpkgtools/trunk/zpkgsetup/tests/test_cfgparser.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_cfgparser.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,162 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.cfgparser."""
+
+import unittest
+
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+
+
+class SimpleSection:
+
+ finished = False
+ ending_parent = None
+ ending_typename = None
+ ending_name = None
+
+ def __init__(self, parent=None, typename=None, name=None):
+ self.parent = parent
+ self.typename = typename
+ self.name = name
+
+
+class AnythingGoesSchema:
+
+ def getConfiguration(self):
+ return SimpleSection()
+
+ def startSection(self, parent, typename, name):
+ return SimpleSection(parent, typename, name)
+
+ def finishSection(self, section):
+ section.finished = True
+ return section
+
+ def endSection(self, parent, typename, name, child):
+ child.ending_parent = parent
+ child.ending_typename = typename
+ child.ending_name = name
+ if not hasattr(parent, typename):
+ setattr(parent, typename, [])
+ getattr(parent, typename).append(child)
+ self.finishSection(child)
+
+ def addValue(self, section, key, value):
+ key = key.lower().replace("-", "_")
+ if not hasattr(section, key):
+ setattr(section, key, [])
+ getattr(section, key).append(value)
+
+
+class ParserTestCase(unittest.TestCase):
+
+ schema = AnythingGoesSchema()
+
+ def createParser(self, text=""):
+ sio = StringIO(text)
+ self.parser = cfgparser.Parser(sio, "<some-url>", self.schema)
+ return self.parser
+
+ def test_replace(self):
+ # "legal" values are those that are legal in ZConfig
+ eq = self.assertEqual
+ raises = self.assertRaises
+ replace = self.createParser().replace
+
+ # some legal values that don't have '$':
+ eq(replace(""), "")
+ eq(replace(" foo bar "), " foo bar ")
+ eq(replace("x"), "x")
+
+ # legal, supported values with '$':
+ eq(replace("$$"), "$")
+ eq(replace("$$$$"), "$$")
+ eq(replace("$$xyz$$"), "$xyz$")
+
+ # legal, unsupported values (all have '$'):
+ raises(cfgparser.ConfigurationError, replace, "$foo")
+ raises(cfgparser.ConfigurationError, replace, "${foo-bar}")
+
+ # illegal values:
+ raises(cfgparser.ConfigurationError, replace, "$")
+ raises(cfgparser.ConfigurationError, replace, "foo$")
+
+ def test_schema_use(self):
+ eq = self.assertEqual
+ p = self.createParser("""
+ # This is a comment.
+
+ key value 1
+ key value 2
+ <section/>
+ <section foo/>
+ <section>
+ key value 3
+ </section>
+ <section splat>
+ <inner>
+ key value 5
+ </inner>
+ key value 4
+ </section>
+ """)
+ cf = p.load()
+ self.check_section(cf, None, None, None, key=["value 1", "value 2"])
+ s1, s2, s3, s4 = cf.section
+ self.check_section(s1, cf, None, "section")
+ self.check_section(s2, cf, "foo", "section")
+ self.check_section(s3, cf, None, "section", key=["value 3"])
+ self.check_section(s4, cf, "splat", "section", key=["value 4"])
+ inner, = s4.inner
+ self.check_section(inner, s4, None, "inner", key=["value 5"])
+
+ def check_section(self, section, parent, name, typename, **attrs):
+ self.assert_(section.finished)
+ self.assert_(section.parent is parent)
+ self.assert_(section.parent is section.ending_parent)
+ self.assertEqual(section.name, name)
+ self.assertEqual(section.name, section.ending_name)
+ self.assertEqual(section.typename, typename)
+ self.assertEqual(section.typename, section.ending_typename)
+ for name, value in attrs.iteritems():
+ v = getattr(section, name)
+ self.assertEqual(v, value)
+
+
+class SchemaTestCase(unittest.TestCase):
+
+ top_level_converted = False
+
+ def setUp(self):
+ self.schema = cfgparser.Schema(
+ ({}, [], self.top_level_conversion))
+
+ def top_level_conversion(self, section):
+ self.top_level_converted = True
+ return section
+
+ def test_getConfiguration(self):
+ cf = self.schema.getConfiguration()
+ self.failIf(self.top_level_converted)
+
+
+def test_suite():
+ suite = unittest.makeSuite(ParserTestCase)
+ suite.addTest(unittest.makeSuite(SchemaTestCase))
+ return suite
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="test_suite")
Copied: zpkgtools/trunk/zpkgsetup/tests/test_package.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_package.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_package.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_package.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,213 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.package."""
+
+import doctest
+import os.path
+import shutil
+import tempfile
+import unittest
+
+from distutils.core import Extension
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+from zpkgsetup import package
+
+
+class PackageInfoTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.tmpdir = tempfile.mkdtemp(prefix="test_package_")
+
+ def tearDown(self):
+ shutil.rmtree(self.tmpdir)
+
+ def write_config(self, text):
+ self.write_file(package.PACKAGE_CONF, text)
+
+ def write_file(self, name, text):
+ f = open(os.path.join(self.tmpdir, name), "w")
+ f.write(text)
+ f.close()
+
+ def test_empty_pkginfo(self):
+ self.write_config("# empty configuration file\n")
+ pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+ eq = self.assertEqual
+ eq(pkginfo.extensions, [])
+ eq(pkginfo.documentation, [])
+ eq(pkginfo.script, [])
+
+ def test_missing_pkginfo(self):
+ pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+ eq = self.assertEqual
+ eq(pkginfo.extensions, [])
+ eq(pkginfo.documentation, [])
+ eq(pkginfo.script, [])
+
+ def test_nonempty_pkginfo(self):
+ self.write_config("documentation doc/README.txt\n"
+ "script bin/runme.py\n"
+ "<extension cricket>\n"
+ " source jiminy.c\n"
+ " define FOO\n"
+ " define BAR = splat\n"
+ " undefine CRUNCHY NUGGET\n"
+ " depends-on cricket.h\n"
+ " depends-on innerds.c\n"
+ " language C\n"
+ "</extension>\n")
+ os.mkdir(os.path.join(self.tmpdir, "doc"))
+ self.write_file(os.path.join("doc", "README.txt"),
+ "docs go here")
+ os.mkdir(os.path.join(self.tmpdir, "bin"))
+ self.write_file(os.path.join("bin", "runme.py"),
+ "#!/bin/sh\nexit\n")
+ pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+ eq = self.assertEqual
+ eq(len(pkginfo.extensions), 1)
+ eq(pkginfo.documentation, ["bar/doc/README.txt"])
+ eq(pkginfo.script, ["bar/bin/runme.py"])
+
+ ext = pkginfo.extensions[0]
+ self.assert_(isinstance(ext, Extension))
+ eq(ext.name, "foo.cricket")
+ eq(ext.sources, ["bar/jiminy.c"])
+ eq(ext.depends, ["bar/cricket.h", "bar/innerds.c"])
+ eq(ext.define_macros, [("FOO", None), ("BAR", "splat")])
+ eq(ext.undef_macros, ["CRUNCHY", "NUGGET"])
+ eq(ext.language, "C")
+
+ def test_broken_extension_too_many_languages(self):
+ self.write_config("<extension cricket>\n"
+ " source jiminy.c\n"
+ " language C\n"
+ " language C++\n"
+ "</extension>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+ def test_broken_extension_without_name(self):
+ self.write_config("<extension>\n"
+ " source jiminy.c\n"
+ "</extension>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+ def test_broken_extension_no_source(self):
+ self.write_config("<extension cricket/>")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+ def test_collection_empty_pkginfo(self):
+ self.write_config("# empty configuration file\n")
+ pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+ eq = self.assertEqual
+ eq(pkginfo.extensions, [])
+ eq(pkginfo.documentation, [])
+ eq(pkginfo.script, [])
+
+ def test_collection_missing_pkginfo(self):
+ pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+ eq = self.assertEqual
+ eq(pkginfo.extensions, [])
+ eq(pkginfo.documentation, [])
+ eq(pkginfo.script, [])
+
+ def test_collection_pkginfo(self):
+ self.write_config("documentation doc/*\n"
+ "script bin/*.py\n")
+ os.mkdir(os.path.join(self.tmpdir, "doc"))
+ self.write_file(os.path.join("doc", "README.txt"),
+ "docs go here")
+ os.mkdir(os.path.join(self.tmpdir, "bin"))
+ self.write_file(os.path.join("bin", "runme.py"),
+ "#!/bin/sh\nexit\n")
+ pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+ eq = self.assertEqual
+ eq(len(pkginfo.extensions), 0)
+ eq(pkginfo.documentation, ["doc/README.txt"])
+ eq(pkginfo.script, ["bin/runme.py"])
+
+ def test_collection_pkginfo_disallows_extensions(self):
+ self.write_config("<extension foo>\n"
+ " source foo.c\n"
+ "</extension>\n")
+ self.assertRaises(ValueError, package.loadCollectionInfo,
+ self.tmpdir, None)
+
+ def test_data_files_1(self):
+ self.write_config("<data-files etc>\n"
+ " foo*\n"
+ "</data-files>\n")
+ self.write_file("foo1.conf", "config goes here")
+ self.write_file("foo2.conf", "config goes here")
+ pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+ pkginfo.data_files[0][1].sort()
+ self.assertEqual(pkginfo.data_files,
+ [("etc", ["foo1.conf", "foo2.conf"])])
+
+ def test_data_files_2(self):
+ self.write_config("<data-files var>\n"
+ " foo2.conf\n"
+ "</data-files>\n"
+ "<data-files etc>\n"
+ " foo1.conf\n"
+ "</data-files>\n")
+ self.write_file("foo1.conf", "config goes here")
+ self.write_file("foo2.conf", "config goes here")
+ pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+ pkginfo.data_files.sort()
+ self.assertEqual(pkginfo.data_files,
+ [("etc", ["foo1.conf"]),
+ ("var", ["foo2.conf"])])
+
+ def test_data_files_error_has_value(self):
+ self.write_config("<data-files etc>\n"
+ " foo bar\n"
+ "</data-files>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadCollectionInfo, self.tmpdir, None)
+
+ def test_data_files_error_has_nested_section(self):
+ self.write_config("<data-files etc>\n"
+ " <extension foo>\n"
+ " </extension>\n"
+ "</data-files>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadCollectionInfo, self.tmpdir, None)
+
+ def test_data_files_error_section_without_name(self):
+ self.write_config("<data-files>\n"
+ "</data-files>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadCollectionInfo, self.tmpdir, None)
+
+ def test_data_files_error_sections_with_same_name(self):
+ self.write_config("<data-files etc>\n"
+ "</data-files>\n"
+ "<data-files etc/>\n"
+ "</data-files>\n")
+ self.assertRaises(cfgparser.ConfigurationError,
+ package.loadCollectionInfo, self.tmpdir, None)
+
+
+def test_suite():
+ suite = doctest.DocTestSuite("zpkgsetup.package")
+ suite.addTest(unittest.makeSuite(PackageInfoTestCase))
+ return suite
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="test_suite")
Copied: zpkgtools/trunk/zpkgsetup/tests/test_publication.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_publication.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_publication.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_publication.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.publication
+
+$Id: test_publication.py,v 1.1 2004/06/14 20:46:41 fdrake Exp $
+"""
+import unittest
+
+from zpkgsetup import publication
+
+
+class DevelopmentStatusTestCase(unittest.TestCase):
+
+ def test_set_development_status_replace_1(self):
+ metadata = publication.loads(
+ "Name: foo\n"
+ "Classifier: Development Status:: 3 - Alpha\n")
+ publication.set_development_status(metadata, publication.BETA)
+ self.assertEqual(metadata.classifiers, [publication.BETA])
+
+ def test_set_development_status_replace_2(self):
+ metadata = publication.loads(
+ "Name: foo\n"
+ "Classifier: Environment :: Console\n"
+ "Classifier: Development Status:: 3 - Alpha\n"
+ "Classifier: Intended Audience :: Developers\n")
+ publication.set_development_status(metadata, publication.BETA)
+ self.assertEqual(metadata.classifiers, [
+ "Environment :: Console",
+ publication.BETA,
+ "Intended Audience :: Developers",
+ ])
+
+ def test_set_development_status_append(self):
+ metadata = publication.loads(
+ "Name: foo\n"
+ "Classifier: Environment :: Console\n"
+ "Classifier: Intended Audience :: Developers\n")
+ publication.set_development_status(metadata, publication.BETA)
+ self.assertEqual(metadata.classifiers, [
+ "Environment :: Console",
+ "Intended Audience :: Developers",
+ publication.BETA,
+ ])
+
+
+def test_suite():
+ return unittest.makeSuite(DevelopmentStatusTestCase)
Copied: zpkgtools/trunk/zpkgsetup/tests/test_setup.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_setup.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_setup.py 2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_setup.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests of zpkgtools.setup."""
+
+import os
+import unittest
+
+from zpkgsetup import publication
+from zpkgsetup import setup
+
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+
+class SetupContextTestCase(unittest.TestCase):
+
+ def test_python_files_as_data(self):
+ packagedir = os.path.join(here, "input", "package")
+ publicationcfg = os.path.join(packagedir, publication.PUBLICATION_CONF)
+ setupfile = os.path.join(here, "input", "setup.py")
+ f = open(publicationcfg, "w")
+ f.write("Metadata-version: 1.0\n"
+ "Name: foo\n")
+ f.close()
+ try:
+ context = setup.SetupContext("package", "0.1.234", setupfile)
+ context.initialize()
+ context.package_data["package"].sort()
+ self.assertEqual(context.package_data,
+ {"package": ["PUBLICATION.cfg",
+ "datadir/justdata.py"]})
+ finally:
+ os.unlink(publicationcfg)
+
+ def test_extension_sources_are_not_package_data(self):
+ packagedir = os.path.join(here, "input", "package2")
+ setupfile = os.path.join(here, "input", "setup.py")
+ context = setup.SetupContext("package2", "0.1.234", setupfile)
+ context.initialize()
+ context.package_data["package2"].sort()
+ self.assertEqual(context.package_data,
+ {"package2": ["PUBLICATION.cfg", "SETUP.cfg"]})
+
+
+def test_suite():
+ return unittest.makeSuite(SetupContextTestCase)
Added: zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg
===================================================================
--- zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg 2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1 @@
+zpkgsetup
Modified: zpkgtools/trunk/zpkgtools/__init__.py
===================================================================
--- zpkgtools/trunk/zpkgtools/__init__.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/__init__.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,9 +23,10 @@
.. __: http://www.zope.org/Resources/ZPL
"""
+import zpkgsetup
-class Error(Exception):
+class Error(zpkgsetup.Error):
"""Base class for exceptions raised by zpkgtools."""
Modified: zpkgtools/trunk/zpkgtools/app.py
===================================================================
--- zpkgtools/trunk/zpkgtools/app.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/app.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,13 +23,14 @@
import zpkgtools
+from zpkgsetup import loggingapi as logging
+from zpkgsetup import package
+from zpkgsetup import publication
+
from zpkgtools import config
from zpkgtools import dependencies
from zpkgtools import include
from zpkgtools import loader
-from zpkgtools import loggingapi as logging
-from zpkgtools import package
-from zpkgtools import publication
from zpkgtools import runlog
@@ -199,7 +200,7 @@
"""Include any support code needed by the generated setup.py
files.
- This will add the ``setuptools`` and ``zpkgtools`` packages to
+ This will add the ``setuptools`` and ``zpkgsetup`` packages to
the output directory if not already present, but they won't be
added to the set of packages that will be installed by the
resulting distribution.
@@ -210,8 +211,8 @@
self.loader = loader.Loader()
os.mkdir(os.path.join(self.destination, "Support"))
self.include_support_package(
- "zpkgtools", ("cvs://cvs.zope.org/cvs-repository"
- ":Packages/zpkgtools/zpkgtools"))
+ "zpkgsetup", ("svn://svn.zope.org/repos/main/zpkgtools/tags/*/"
+ "zpkgsetup"))
self.include_support_package(
"setuptools", ("cvs://cvs.python.sourceforge.net/cvsroot/python"
":python/nondist/sandbox/setuptools/setuptools"))
@@ -443,7 +444,7 @@
self.ip.add_output(setup_py)
f = open(setup_py, "w")
print >>f, SETUP_HEADER
- print >>f, "context = zpkgtools.setup.SetupContext("
+ print >>f, "context = zpkgsetup.setup.SetupContext("
print >>f, " %r, %r, __file__)" % (self.name, version)
print >>f
print >>f, "context.initialize()"
@@ -472,7 +473,7 @@
if os.path.isdir(support_dir):
sys.path.insert(0, support_dir)
-import zpkgtools.setup
+import zpkgsetup.setup
"""
Deleted: zpkgtools/trunk/zpkgtools/cfgparser.py
===================================================================
--- zpkgtools/trunk/zpkgtools/cfgparser.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/cfgparser.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,360 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Extra-lite parser for a `ZConfig`_-like configuration syntax.
-
-There is no support for external schemas; schemas are simpler and must
-be specified using Python data structures.
-
-There is no support for any %-directives, but dollar signs in values
-must be doubled to ensure compatibility with `ZConfig`_.
-
-.. _ZConfig: http://www.zope.org/Members/fdrake/zconfig/
-
-"""
-
-import re
-
-
-class ConfigurationError(Exception):
- """Exception raised for errors in a configuration file.
-
- :ivar url: URL of the resource being read when the error was
- detected.
-
- :ivar lineno: Line number within the resource at which the
- error was detected.
-
- """
-
- def __init__(self, message, url=None, lineno=None):
- """Initialize the ConfigurationError instance.
-
- :param message: Text of the error message.
-
- :param url: URL of the resource being read when the error was
- detected.
-
- :param lineno: Line number within the resource at which the
- error was detected.
-
- """
- Exception.__init__(self, message)
- self.url = url
- self.lineno = lineno
-
- def __str__(self):
- s = Exception.__str__(self)
- if self.url:
- s = "%s\n(%s" % (s, self.url)
- if self.lineno is not None:
- s = "%s, line %s" % (s, self.lineno)
- s += ")"
- return s
-
-
-class Schema:
- """Schema definition that can be used by the Parser class to
- construct a configuration.
-
- The definition is defined as a set of *type definitions*. Each
- type definition is a triple containing a dictionary, a list, and a
- function (or `None`). The dictionary maps the names of the keys
- allowed in the section to conversion functions for the values (or
- None if no conversion is required). The list names the section
- types which can occur in the section. The function is used to
- convert a `SectionValue` representing the collected values to the
- actual value of the section itself; if `None` is used, no
- conversion is performed.
-
- """
-
- def __init__(self, toplevel, typedefs=None):
- """Initialize a schema definition based on type definitions.
-
- :param toplevel: Type definition that represents the otherwise
- anonymous top-level section of a configuration.
-
- :param typedefs: Mapping from typenames (which must be given
- as lower-case strings) to type definitions. Only section
- types specified in `typedefs` can be used anywhere in
- configurations described by the schema.
-
- """
- self._toplevel = toplevel
- if typedefs is None:
- typedefs = {}
- self._typedefs = typedefs
-
- def getConfiguration(self):
- """Return a configuration object for the top-level section.
-
- :return: New configuration object.
-
- The attributes of the configuration object represent values
- that have not been specified in a configuration file; these
- will be filled in during parsing.
- """
- return self.createSection(None, None, self._toplevel)
-
- def startSection(self, parent, typename, name):
- # make sure typename is defined:
- typedef = self._typedefs.get(typename)
- if typedef is None:
- raise ConfigurationError("unknown section type: %s" % typename)
- # make sure typename is allowed:
- x, sects, x = parent.getSectionDefinition()
- if typename not in sects:
- parent_type = parent.getSectionType()
- if parent_type:
- msg = ("%r sections not allowed in %r sections"
- % (typename, parent_type))
- else:
- msg = "%r sections not allowed" % typename
- raise ConfigurationError(msg)
- return self.createSection(name, typename, typedef)
-
- def createSection(self, name, typename, typedef):
- child = SectionValue(name, typename, typedef)
- keys, sects, x = typedef
- # initialize the defaults:
- for name in keys:
- name = name.lower().replace("-", "_")
- setattr(child, name, [])
- for name in sects:
- name = name.lower().replace("-", "_")
- setattr(child, name, [])
- return child
-
- def finishSection(self, section):
- x, x, datatype = section.getSectionDefinition()
- if datatype is not None:
- typename = section.getSectionType()
- try:
- section = datatype(section)
- except ValueError, e:
- raise ConfigurationError(
- "could not convert %r section value: %s"
- % (typename, e))
- return section
-
- def endSection(self, parent, typename, name, child):
- value = self.finishSection(child)
- getattr(parent, typename).append(value)
-
- def addValue(self, section, key, value):
- keys, x, x = section.getSectionDefinition()
- keyname = key.lower()
- if keyname not in keys:
- typename = section.getSectionType()
- if typename:
- msg = "key %r not defined in %r sections" % (key, typename)
- else:
- msg = "key %r not defined" % key
- raise ConfigurationError(msg)
- datatype = keys[keyname]
- if datatype is not None:
- try:
- value = datatype(value)
- except ValueError, e:
- raise ConfigurationError("could not convert value: %s" % e)
- attrname = keyname.replace("-", "_")
- getattr(section, attrname).append(value)
-
-
-# These regular expressions should match the corresponding definitions
-# in ZConfig.cfgparser since this needs to be a format that could be
-# read by ZConfig with an appropriate schema definition.
-#
-_name_re = r"[^\s()]+"
-_keyvalue_rx = re.compile(r"(?P<key>%s)\s*(?P<value>[^\s].*)?$"
- % _name_re)
-_section_start_rx = re.compile(r"(?P<type>%s)"
- r"(?:\s+(?P<name>%s))?"
- r"$"
- % (_name_re, _name_re))
-
-_nulljoin = "".join
-
-
-class Parser:
- """Parser for ZConfig-like configuration files."""
-
- def __init__(self, file, url, schema):
- self.schema = schema
- self.file = file
- self.url = url
- self.lineno = 0
- self.stack = [] # [(type, name, prevmatcher), ...]
-
- def nextline(self):
- line = self.file.readline()
- if line:
- self.lineno += 1
- return False, line.strip()
- else:
- return True, None
-
- def load(self):
- section = self.schema.getConfiguration()
- self.parse(section)
- try:
- return self.schema.finishSection(section)
- except ConfigurationError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
-
- def parse(self, section):
- done, line = self.nextline()
- while not done:
- if line[:1] in ("", "#"):
- # blank line or comment
- pass
-
- elif line[:2] == "</":
- # section end
- if line[-1] != ">":
- self.error("malformed section end")
- section = self.end_section(section, line[2:-1])
-
- elif line[0] == "<":
- # section start
- if line[-1] != ">":
- self.error("malformed section start")
- section = self.start_section(section, line[1:-1])
-
- elif line[0] == "%":
- self.error("ZConfig-style directives are not supported")
-
- else:
- self.handle_key_value(section, line)
-
- done, line = self.nextline()
-
- if self.stack:
- self.error("unclosed sections not allowed")
-
- def start_section(self, section, rest):
- isempty = rest[-1:] == "/"
- if isempty:
- text = rest[:-1].rstrip()
- else:
- text = rest.rstrip()
- # parse section start stuff here
- m = _section_start_rx.match(text)
- if not m:
- self.error("malformed section header")
- type, name = m.group('type', 'name')
- type = type.lower()
- #
- # XXX Argh! Converting section names to lower-case was a
- # mistake in ZConfig, but we have to honor case here for
- # <extension> sections. We need to add some way to control
- # the "nametype" of sections in ZConfig anyway.
- #
- # if name:
- # name = name.lower()
- #
- try:
- newsect = self.schema.startSection(section, type, name)
- except ConfigurationError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
- if isempty:
- try:
- self.schema.endSection(section, type, name, newsect)
- except ConfigurationError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
- return section
- else:
- self.stack.append((type, name, section))
- return newsect
-
- def end_section(self, section, rest):
- if not self.stack:
- self.error("unexpected section end")
- type = rest.rstrip().lower()
- opentype, name, prevsection = self.stack.pop()
- if type != opentype:
- self.error("unbalanced section end")
- try:
- self.schema.endSection(prevsection, type, name, section)
- except ConfigurationError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
- return prevsection
-
- def handle_key_value(self, section, rest):
- m = _keyvalue_rx.match(rest)
- if not m:
- self.error("malformed configuration data")
- key, value = m.group('key', 'value')
- if value:
- value = self.replace(value)
- else:
- value = ''
- try:
- self.schema.addValue(section, key, value)
- except ConfigurationError, e:
- e.lineno = self.lineno
- e.url = self.url
- raise
-
- def replace(self, text):
- parts = []
- rest = text
- while "$" in rest:
- i = rest.index("$")
- if i:
- parts.append(rest[:i])
- rest = rest[i+1:]
- if not rest:
- self.error("text cannot end with a bare '$'")
- if rest[0] == "$":
- parts.append("$")
- rest = rest[1:]
- else:
- self.error("unsupported substitution syntax")
- parts.append(rest)
- return _nulljoin(parts)
-
- def error(self, message):
- raise ConfigurationError(message, self.url, self.lineno)
-
-
-class SectionValue:
- """Generic bag-of-values object for a section."""
-
- def __init__(self, name, typename, typedef):
- self._name = name
- self._typename = typename
- self._typedef = typedef
-
- def getSectionName(self):
- """Return the name of the section, or `None`."""
- return self._name
-
- def getSectionType(self):
- """Return the name of the section type."""
- return self._typename
-
- def getSectionDefinition(self):
- """Return the data structure that represents the type of this
- section value.
- """
- return self._typedef
Modified: zpkgtools/trunk/zpkgtools/config.py
===================================================================
--- zpkgtools/trunk/zpkgtools/config.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/config.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -26,7 +26,7 @@
import os
import urllib
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
from zpkgtools import locationmap
Modified: zpkgtools/trunk/zpkgtools/include.py
===================================================================
--- zpkgtools/trunk/zpkgtools/include.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/include.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -14,41 +14,28 @@
"""Processor for inclusions when building a release.
:Variables:
- - `EXCLUDE_NAMES`: Names of files and directories that will be
- excluded from copying. These are generally related to source
- management systems, but don't need to be.
-
- - `EXCLUDE_PATTERNS`: Glob patterns used to filter the set of files
- that are copied. Any file with a name matching these patterns
- will be ignored.
-
- `PACKAGE_CONF`: The name of the file that specifies how the
package is assembled.
"""
-import fnmatch
import glob
import os
import posixpath
import shutil
import urllib
-from zpkgtools import Error
+from zpkgsetup import cfgparser
+from zpkgsetup import loggingapi as logging
+from zpkgsetup import publication
+from zpkgsetup import setup
-from zpkgtools import cfgparser
+from zpkgtools import Error
from zpkgtools import loader
-from zpkgtools import loggingapi as logging
-from zpkgtools import publication
logger = logging.getLogger(__name__)
-
-# Names that are exluded from globbing results:
-EXCLUDE_NAMES = ["CVS", ".cvsignore", "RCS", "SCCS", ".svn"]
-EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~"]
-
# Name of the configuration file:
PACKAGE_CONF = "PACKAGE.cfg"
@@ -102,19 +89,6 @@
return config
-def filter_names(names):
- """Given a list of file names, return those names that should be copied.
- """
- names = [n for n in names
- if n not in EXCLUDE_NAMES]
- # This is needed when building a distro from a working
- # copy (likely a checkout) rather than a pristine export:
- for pattern in EXCLUDE_PATTERNS:
- names = [n for n in names
- if not fnmatch.fnmatch(n, pattern)]
- return names
-
-
def normalize_path(path, type, group):
if ":" in path:
scheme, rest = urllib.splittype(path)
@@ -284,7 +258,7 @@
prefix = os.path.join(source, "")
for pat in patterns:
path = os.path.join(source, pat)
- expansions = filter_names(glob.glob(path))
+ expansions = setup.filter_names(glob.glob(path))
if not expansions:
raise InclusionSpecificationError(
"%r doesn't match any files in <%s>" % (pat, self.group),
@@ -295,7 +269,7 @@
excludes = []
for pat in self.excludes:
path = os.path.join(source, pat)
- expansions = filter_names(glob.glob(path))
+ expansions = setup.filter_names(glob.glob(path))
if not expansions:
raise InclusionSpecificationError(
"%r doesn't match any files in <%s>" % (pat, self.group),
@@ -374,8 +348,8 @@
# to modify the list of directories which are considered.
#
for dirname, dirs, files in os.walk(source, topdown=True):
- dirs[:] = filter_names(dirs)
- files = filter_names(files)
+ dirs[:] = setup.filter_names(dirs)
+ files = setup.filter_names(files)
# reldir is the name of the directory to write to,
# relative to destination. It will be '' at the top
Modified: zpkgtools/trunk/zpkgtools/loader.py
===================================================================
--- zpkgtools/trunk/zpkgtools/loader.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/loader.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -26,8 +26,9 @@
import urllib2
import urlparse
+from zpkgsetup import loggingapi as logging
+
from zpkgtools import cvsloader
-from zpkgtools import loggingapi as logging
from zpkgtools import svnloader
Modified: zpkgtools/trunk/zpkgtools/locationmap.py
===================================================================
--- zpkgtools/trunk/zpkgtools/locationmap.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/locationmap.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -22,9 +22,10 @@
import urlparse
import UserDict
+from zpkgsetup import loggingapi as logging
+
from zpkgtools import cvsloader
from zpkgtools import loader
-from zpkgtools import loggingapi as logging
from zpkgtools import svnloader
Deleted: zpkgtools/trunk/zpkgtools/loggingapi.py
===================================================================
--- zpkgtools/trunk/zpkgtools/loggingapi.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/loggingapi.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,92 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Compatibility wrapper around the logging package.
-
-If the logging package isn't available (as in Python 2.2), this
-provides a limited implementation so the zpkgtools setup.py support
-code doesn't fall over.
-
-This isn't sufficient to support building packages with Python 2.2.
-
-$Id: loggingapi.py,v 1.1 2004/06/11 19:24:35 fdrake Exp $
-"""
-
-try:
- from logging import getLogger
- from logging import CRITICAL, FATAL, ERROR, WARNING, WARN
- from logging import INFO, DEBUG, NOTSET
- from logging import StreamHandler
-
-except ImportError:
-
- CRITICAL = 50
- FATAL = CRITICAL
- ERROR = 40
- WARNING = 30
- WARN = WARNING
- INFO = 20
- DEBUG = 10
- NOTSET = 0
-
-
- _loggers = {}
-
- def getLogger(name=None):
- if "root" not in _loggers:
- _loggers["root"] = Logger("root")
- _loggers["root"].setLevel(WARNING)
- name = name or "root"
- if name not in _loggers:
- _loggers[name] = Logger(name, _loggers["root"])
- return _loggers[name]
-
-
- class Logger:
-
- def __init__(self, name, root=None):
- self.name = name
- self.level = NOTSET
- self._handler = None
- self._root = root
-
- def setLevel(self, level):
- self.level = level
-
- def addHandler(self, handler):
- self._handler = handler
-
- def log(self, level, msg, *args, **kwargs):
- loggers = [self]
- if self._root is not None:
- loggers.append(self._root)
-
- for logger in loggers:
- effective_level = logger.level
- if effective_level == NOTSET and logger._root is not None:
- effective_level = self._root.level
- if level >= effective_level:
- self._log(self.name, level, msg, args, kwargs)
-
- def _log(self, name, level, msg, args, kwargs):
- if args:
- msg = msg % args
- elif kwargs:
- msg = msg % kwargs
- msg = "%s(%s):%s" % (name, level, msg)
- print >>self._handler, msg
-
-
- def StreamHandler():
- import sys
- return sys.stderr
Deleted: zpkgtools/trunk/zpkgtools/package.py
===================================================================
--- zpkgtools/trunk/zpkgtools/package.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/package.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,518 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Support for handling package configuration files.
-
-The package configuration files handled by this module provide
-information about the software and documentation contents of a
-distribution component. The same kinds of information can be
-described for any component, with the exception that extensions only
-make sense for package components.
-
-Package configuration files use a syntax very like the `ZConfig`_
-package, but fewer features are available. The specific syntax is
-implemented by the `cfgparser` module.
-
-.. _ZConfig: http://www.zope.org/Members/fdrake/zconfig/
-
-There are only a few types of information which can appear in a
-package configuration file; the file is intended to describe what a
-package provides that is not a module or data file. The three types
-of things which can be listed in the file are:
-
-- scripts
-- documentation
-- extensions
-
-The scripts and documentation files are listed very simply::
-
- documentation *.txt
- documentation apiref.pdf
-
- script scritps/*
-
-The value to the right of the identifying keyword is a portable glob
-pattern, where *portable* here means the pattern uses the POSIX
-notation. Path components should be separated by forward slashes
-(like all paths used with distutils), ``?`` can be replaced by any
-single character, and ``*`` can be replaced by zero or more
-characters.
-
-
-:Variables:
- - `PACKAGE_CONF`: Name of the package information file.
-
-:Groups:
- - `Public interface`: loadCollectionInfo loadPackageInfo
- - `Helper functions`: create_extension expand_globs read_package_info
- - `Datatype functions`: cpp_definition cpp_names path_ref extension
-
-"""
-
-import glob
-import os
-import posixpath
-import re
-import urllib
-
-from distutils.core import Extension
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-
-
-PACKAGE_CONF = "SETUP.cfg"
-
-
-def loadPackageInfo(pkgname, directory, reldir):
- """Load package information for a Python package.
-
- :return: Package information object.
-
- :Parameters:
- - `pkgname`: Full name of the Python package to which the
- information being read applies. This is needed to construct
- Extension objects properly.
- - `directory`: Directory containing the package's __init__.py file.
- - `reldir`: Relative directory path with which file names from
- the information file will be joined. This should be in POSIX
- notation. It will not be used to locate files.
-
- """
- pkginfo = read_package_info(directory, reldir)
- pkginfo.extensions = [create_extension(ext, pkgname, reldir)
- for ext in pkginfo.extension]
- return pkginfo
-
-
-def loadCollectionInfo(directory, reldir):
- """Load package information for a collection.
-
- :return: Package information object.
-
- :Parameters:
- - `directory`: Directory containing the collection's files.
- - `reldir`: Relative directory path with which file names from
- the information file will be joined. This should be in POSIX
- notation. It will not be used to locate files.
-
- """
- pkginfo = read_package_info(directory, reldir)
- if pkginfo.extension:
- raise ValueError("extensions cannot be defined in collections")
- pkginfo.extensions = []
- return pkginfo
-
-
-def read_package_info(directory, reldir=None):
- """Read the package information file from a specified directory.
-
- :return: Package information object.
-
- :Parameters:
- - `directory`: Directory containing the collection's files.
- - `reldir`: Relative directory path with which file names from
- the information file will be joined. This should be in POSIX
- notation. It will not be used to locate files. It may be
- omitted or None; if so, filenames are not 'relocated' relative
- to where they are found.
-
- """
- path = os.path.join(directory, PACKAGE_CONF)
- if os.path.exists(path):
- path = os.path.realpath(path)
- url = "file://" + urllib.pathname2url(path)
- f = open(path)
- else:
- # Initialize using the cfgparser so we still get a package
- # data object with the right attributes:
- url = "<no file>"
- f = StringIO("")
- try:
- p = cfgparser.Parser(f, url, PackageSchema(directory, reldir))
- pkginfo = p.load()
- finally:
- f.close()
- pkginfo.documentation = expand_globs(directory, reldir,
- pkginfo.documentation)
- pkginfo.header = expand_globs(directory, reldir, pkginfo.header)
- pkginfo.script = expand_globs(directory, reldir, pkginfo.script)
-
- # need to post-process the data_files so included directories are
- # handled properly; distutils expects everything to be a file!
- #
- # XXX need tests!
- #
- datamap = {}
- for dir, paths in pkginfo.data_files:
- expand_data(directory, reldir, dir, paths, datamap)
- if "." in datamap and datamap["."] == []:
- del datamap["."]
- pkginfo.data_files = datamap.items()
-
- return pkginfo
-
-
-def expand_data(directory, reldir, targetdir, paths, datamap):
- #
- # `directory` is where we find things
- #
- # `reldir` is the relative location of directory in the source; we
- # need it so we can rip it off of the values in `paths`
- #
- # `targetdir` is where we want the things in `paths` copied in
- # POSIX notation
- #
- # `paths` is a list of paths to things we want copied, in POSIX
- # notation, with `reldir` prepended
- #
- # `datamap` is a mapping from target directory -> [files], where
- # files are really paths to actual files (not directories!) that
- # are to be copied to the target directory; the file paths are
- # given in POSIX notation and are prefixed by `reldir`
- #
- # All directories must be represented in the data map, even if
- # they're empty.
- #
- targetdir = posixpath.normpath(targetdir)
-
- # Make sure there's an entry for every directory we look at; that
- # ensures distutils will create empty directories for us.
- L = datamap.setdefault(targetdir, [])
-
- if reldir:
- prefix = posixpath.join(reldir, "")
- else:
- prefix = ""
-
- # for files, add to the list, otherwise recursively scan
- for src in paths:
- # strip `reldir`, convert to local path notation
- localpath = src[len(prefix):].replace("/", os.sep)
- # find the referenced path
- fullpath = os.path.join(directory, localpath)
- if os.path.isfile(fullpath):
- L.append(src)
- else:
- # directory; recurse
- basename = os.path.basename(fullpath)
- expand_data(
- directory, reldir, posixpath.join(targetdir, basename),
- [posixpath.join(src, name) for name in os.listdir(fullpath)],
- datamap)
-
-
-def create_extension(section, pkgname, reldir):
- """Create an `Extension` instance from a configuration section.
-
- :Parameters:
- - `section`: Section object from the configuration file.
- - `pkgname`: Full name of the containing package. This should
- be an empty string or ``None`` if the extension is not in a
- package.
- - `reldir`: Directory in which the extension lives, relative to
- the top of the distribution, given in POSIX notation.
-
- """
- kwargs = {}
- if pkgname:
- kwargs["name"] = "%s.%s" % (pkgname, section.name)
- else:
- kwargs["name"] = section.name
- kwargs["sources"] = [posixpath.join(reldir, fn)
- for fn in section.source]
- if section.define:
- kwargs["define_macros"] = section.define
- if section.undefine:
- kwargs["undef_macros"] = undefs = []
- for L in section.undefine:
- undefs.extend(L)
- if section.depends_on:
- kwargs["depends"] = [posixpath.join(reldir, fn)
- for fn in section.depends_on]
- if section.language:
- kwargs["language"] = section.language[0]
- if reldir and reldir != ".":
- kwargs["include_dirs"] = [reldir]
- return Extension(**kwargs)
-
-
-def expand_globs(directory, reldir, globlist):
- """Expand glob patterns for directory.
-
- :Parameters:
- - `directory`: The path to the directory to which the glob
- patterns are relative to.
- - `reldir`: Base directory to use for returning glob expansions.
- This should be a relative path in POSIX notation. This is not
- used for locating files.
- - `globlist`: List of glob patterns in POSIX notation. The
- patterns may refer to child directories of `directory`.
-
- :return: List of expansions in POSIX notation, using `reldir` as
- the base directory.
-
- Note that `directory` and `reldir` are two different names for the
- same directory.
-
- :warning: This function is not thread safe, as it changes the
- current working directory while it is running.
-
- """
- results = []
- pwd = os.getcwd()
- os.chdir(directory)
- try:
- for g in globlist:
- gs = g.replace("/", os.sep)
- filenames = glob.glob(gs)
- if not filenames:
- raise ValueError(
- "filename pattern %r doesn't match any files" % g)
- filenames = [fn.replace(os.sep, "/") for fn in filenames]
- if reldir:
- filenames = [posixpath.join(reldir, fn) for fn in filenames]
- results += filenames
- finally:
- os.chdir(pwd)
- return results
-
-
-# datatype functions referenced by the schema:
-
-def cpp_definition(s):
- r"""Return a 2-tuple representing a CPP #define.
-
- :rtype: (str, str or None)
-
- The first element of the tuple is the name to define, and the
- second is the value to use as the replacement text. In the input,
- the two parts should be separated by an equal sign.
-
- >>> cpp_definition('NAME=VALUE')
- ('NAME', 'VALUE')
- >>> cpp_definition('NAME=')
- ('NAME', '')
-
- Whitespace around the equal sign are ignored:
-
- >>> cpp_definition('NAME =\tVALUE')
- ('NAME', 'VALUE')
-
- If there is no equal sign, and defininition with no replacement
- text is used (equivalent to '#define NAME'):
-
- >>> cpp_definition('NAME')
- ('NAME', None)
-
- ValueError is raised if there is an error in the input:
-
- >>> cpp_definition('not-a-cpp-symbol')
- Traceback (most recent call last):
- ...
- ValueError: not a valid C identifier: 'not-a-cpp-symbol'
-
- """
- if "=" in s:
- name, value = s.split("=", 1)
- name = name.rstrip()
- value = value.lstrip()
- else:
- name = s
- value = None
- if _cpp_ident_match(name) is None:
- raise ValueError("not a valid C identifier: %r" % name)
- return name, value
-
-
-def cpp_names(s):
- r"""Return a list of CPP symbols from a string.
-
- :rtype: [str, ...]
-
- >>> cpp_names('NAME')
- ['NAME']
- >>> cpp_names('NAME1 NAME_2 A_B_C A123')
- ['NAME1', 'NAME_2', 'A_B_C', 'A123']
-
- If something is included which is not a valid identifier for CPP,
- ValueError is raised:
-
- >>> cpp_names('not-really!')
- Traceback (most recent call last):
- ...
- ValueError: not a valid C identifier: 'not-really!'
-
- >>> cpp_names('NAME ANOTHER not-really!')
- Traceback (most recent call last):
- ...
- ValueError: not a valid C identifier: 'not-really!'
-
- """
- names = s.split()
- for name in names:
- if _cpp_ident_match(name) is None:
- raise ValueError("not a valid C identifier: %r" % name)
- return names
-
-_cpp_ident_match = re.compile("[A-Za-z_][A-Za-z_0-9]*$").match
-
-
-def extension(section):
- """Transform `section`, checking several fields for valid values.
-
- :param section: Configuration section.
- :return: Modified section.
- """
- section.name = section.getSectionName()
- if not section.name:
- raise ValueError("extensions must be named")
- if not section.source:
- raise ValueError("at least one extension source file must be listed")
- if len(section.language) > 1:
- raise ValueError("language can only be specified once")
- return section
-
-
-def path_ref(s):
- """Datatype for a local path reference.
-
- :rtype: str
-
- >>> path_ref('README.txt')
- 'README.txt'
- >>> path_ref('./README.txt')
- 'README.txt'
- >>> path_ref('foo/bar/file.txt')
- 'foo/bar/file.txt'
-
- If a reference is not a relative path, ValueError is raised:
-
- >>> path_ref('/absolute/path')
- Traceback (most recent call last):
- ...
- ValueError: absolute paths are not allowed: '/absolute/path'
-
- >>> path_ref('/')
- Traceback (most recent call last):
- ...
- ValueError: absolute paths are not allowed: '/'
-
- References which contain Windows drive letters are not allowed:
-
- >>> path_ref('c:README.txt')
- Traceback (most recent call last):
- ...
- ValueError: Windows drive letters are not allowed: 'c:README.txt'
-
- If a reference is relative but points outside the local directory
- hierarchy, ValueError is raised:
-
- >>> path_ref('../somefile')
- Traceback (most recent call last):
- ...
- ValueError: relative paths may not point outside the containing tree: '../somefile'
-
- """
- if not s:
- raise ValueError("path references may not be empty")
- if s.find(":") == 1:
- # looks like a windows drive letter:
- raise ValueError("Windows drive letters are not allowed: %r" % s)
- p = posixpath.normpath(s)
- if p[:1] == "/":
- raise ValueError("absolute paths are not allowed: %r" % s)
- parts = p.split("/")
- if parts[0] == "..":
- raise ValueError("relative paths may not point outside"
- " the containing tree: %r" % s)
- return p
-
-
-class PackageSchema(cfgparser.Schema):
- """Schema implementation with a <data-files> section type.
-
- The <data-files> sections have keys that are glob-expanded (based
- on information passed to the constructor) and combined into a
- single .data_files member on the resulting package information
- object. The value of the .data_files attribute is suitable for
- passing to the distutils.core.setup() function.
-
- """
-
- def __init__(self, directory, reldir):
- cfgparser.Schema.__init__(
- self,
- ({"script": path_ref,
- "documentation": path_ref,
- "header": path_ref},
- ["extension"], None),
- {"extension": ({"source": path_ref, "depends-on": path_ref,
- "define" : cpp_definition, "undefine": cpp_names,
- "language": str,
- },
- (), extension),
- }
- )
- self.__cf = None
- self.__datafiles = None
- self.__directory = directory
- self.__reldir = reldir
-
- def getConfiguration(self):
- assert self.__cf is None
- self.__cf = cfgparser.Schema.getConfiguration(self)
- self.__cf.data_files = []
- return self.__cf
-
- def startSection(self, parent, typename, name):
- if self.__datafiles is not None:
- raise cfgparser.ConfigurationError(
- "can't nest another section inside <data-files> section")
- if typename == "data-files":
- if not name:
- raise cfgparser.ConfigurationError(
- "<data-files> section must have a name")
- normname = posixpath.normpath(name)
- for target, files in self.__cf.data_files:
- if target == normname:
- raise cfgparser.ConfigurationError(
- "can't have two sections of the same name:"
- " <data-files %s>" % name)
- self.__datafiles = []
- self.__cf.data_files.append((normname, self.__datafiles))
- # The return value is passed around, but that's it
- return ()
- else:
- return cfgparser.Schema.startSection(self, parent, typename, name)
-
- def endSection(self, parent, typename, name, child):
- if self.__datafiles is None:
- cfgparser.Schema.endSection(self, parent, typename, name, child)
- else:
- # mutate self.__datafiles since the reference from
- # self.__cf.data_files is what's actually used
- self.__datafiles[:] = expand_globs(self.__directory,
- self.__reldir,
- self.__datafiles)
- self.__datafiles = None
-
- def addValue(self, section, key, value):
- if self.__datafiles is not None:
- if value:
- raise cfgparser.ConfigurationError(
- "each entry in a <data-files> section must be"
- " a single glob pattern")
- self.__datafiles.append(key)
- else:
- cfgparser.Schema.addValue(self, section, key, value)
Deleted: zpkgtools/trunk/zpkgtools/publication.py
===================================================================
--- zpkgtools/trunk/zpkgtools/publication.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/publication.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,201 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Support for reading and generating publication metadata files.
-
-Such files include the PKG-INFO files generated by `distutils` as well
-as the PUBLICATION.cfg files used by **zpkg**.
-
-:var PUBLICATION_CONF: The default name of the file containing
- publication data as used by **zpkg**.
-
-"""
-from distutils.dist import DistributionMetadata
-from distutils.util import rfc822_escape
-from email.Parser import Parser
-from StringIO import StringIO
-
-
-PUBLICATION_CONF = "PUBLICATION.cfg"
-
-
-# XXX The dump() and dumps() methods are very similar to the
-# DistributionMetadata.write_pkg_info() method, but don't constrain
-# where the data is written. Much of this can be discarded if
-# portions of the PEP 262 patch (http://www.python.org/sf/562100) are
-# accepted.
-
-def dump(metadata, f):
- """Write package metadata to a file in PKG-INFO format.
-
- :param metadata: Metadata object to serialize.
-
- :param f: Open file object to write to.
-
- """
- metadata_version = "1.0"
- if (metadata.maintainer or metadata.maintainer_email
- or metadata.url or metadata.get_classifiers()):
- metadata_version = "1.1"
- print >>f, "Metadata-Version:", metadata_version
- print >>f, "Name:", metadata.get_name()
- if metadata.version:
- print >>f, "Version:", metadata.get_version()
- if metadata.description:
- print >>f, "Summary:", metadata.get_description()
- if metadata.url:
- print >>f, "Home-page:", metadata.get_url()
- if metadata.author:
- print >>f, "Author:", metadata.get_author()
- if metadata.author_email:
- print >>f, "Author-email:", metadata.get_author_email()
- if metadata.maintainer:
- print >>f, "Maintainer:", metadata.get_maintainer()
- if metadata.maintainer_email:
- print >>f, "Maintainer-email:", metadata.get_maintainer_email()
- if metadata.license:
- print >>f, "License:", metadata.get_license()
- if metadata.url:
- print >>f, "Download-URL:", metadata.url
- if metadata.long_description:
- long_desc = rfc822_escape(metadata.get_long_description())
- print >>f, "Description:", long_desc
- keywords = metadata.get_keywords()
- if keywords:
- print >>f, "Keywords:", ", ".join(keywords)
- for platform in metadata.get_platforms():
- print >>f, "Platform:", platform
- for classifier in metadata.get_classifiers():
- print >>f, "Classifier:", classifier
-
-
-def dumps(metadata):
- """Return package metadata serialized in PKG-INFO format.
-
- :return: String containing the serialized metadata.
- :rtype: str
-
- :param metadata: Metadata object to serialize.
-
- """
- sio = StringIO()
- dump(metadata, sio)
- return sio.getvalue()
-
-
-def load(f, versioninfo=False, metadata=None):
- """Parse a PKG-INFO file and return a DistributionMetadata instance.
-
- :return: Populated metadata object.
- :rtype: `DistributionMetadata`
-
- :param versioninfo: Flag indicating whether version-specific
- information should be included.
-
- :param metadata: Metadata object which should be populated from
- the publication data. If omitted, a fresh
- `DistributionMetadata` instance will be used.
-
- """
- parser = Parser()
- msg = parser.parse(f, headersonly=True)
- return _loadmsg(msg, versioninfo, metadata)
-
-
-def loads(text, versioninfo=False, metadata=None):
- """Parse PKG-INFO source text and return a DistributionMetadata instance.
-
- :return: Populated metadata object.
- :rtype: `DistributionMetadata`
-
- :param versioninfo: Flag indicating whether version-specific
- information should be included.
-
- :param metadata: Metadata object which should be populated from
- the publication data. If omitted, a fresh
- `DistributionMetadata` instance will be used.
-
- """
- parser = Parser()
- msg = parser.parsestr(text, headersonly=True)
- return _loadmsg(msg, versioninfo, metadata)
-
-
-def _loadmsg(msg, versioninfo, metadata=None):
- if metadata is None:
- metadata = DistributionMetadata()
-
- if versioninfo:
- metadata.version = _get_single_header(msg, "Version")
- metadata.download_url = _get_single_header(msg, "Download-URL")
- metadata.name = _get_single_header(msg, "Name")
- metadata.author = _get_single_header(msg, "Author")
- metadata.author_email = _get_single_header(msg, "Author-email")
- metadata.maintainer = _get_single_header(msg, "Maintainer")
- metadata.maintainer_email = _get_single_header(msg, "Maintainer-email")
- metadata.url = _get_single_header(msg, "Home-page")
- metadata.license = _get_single_header(msg, "License")
- metadata.description = _get_single_header(msg, "Summary")
- metadata.long_description = _get_single_header(msg, "Description")
-
- keywords = _get_single_header(msg, "Keywords", "")
- keywords = [s.strip() for s in keywords.split(",") if s.strip()]
- metadata.keywords = keywords or None
-
- platforms = msg.get_all("Platform")
- if platforms:
- metadata.platforms = platforms
-
- classifiers = msg.get_all("Classifier")
- if classifiers:
- metadata.classifiers = classifiers
-
- return metadata
-
-
-def _get_single_header(msg, name, default=None):
- """Return the value for a header that only occurs once in the input.
-
- :raises ValueError: If the header occurs more than once.
-
- """
- headers = msg.get_all(name)
- if headers and len(headers) > 1:
- raise ValueError("header %r can only be given once" % name)
- if headers:
- v = headers[0]
- if v == "UNKNOWN":
- return None
- else:
- return v
- else:
- return default
-
-
-
-ALPHA = "Development Status :: 3 - Alpha"
-BETA = "Development Status :: 4 - Beta"
-STABLE = "Development Status :: 5 - Production/Stable"
-
-def set_development_status(metadata, status):
- if not metadata.classifiers:
- metadata.classifiers = [status]
- return
- for i in range(len(metadata.classifiers)):
- classifier = metadata.classifiers[i]
- parts = [s.strip() for s in classifier.lower().split("::")]
- if parts[0] == "development status":
- metadata.classifiers[i] = status
- break
- else:
- metadata.classifiers.append(status)
Modified: zpkgtools/trunk/zpkgtools/runlog.py
===================================================================
--- zpkgtools/trunk/zpkgtools/runlog.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/runlog.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -16,7 +16,7 @@
import os
import sys
-from zpkgtools import loggingapi as logging
+from zpkgsetup import loggingapi as logging
def report_command(cmd):
Deleted: zpkgtools/trunk/zpkgtools/setup.py
===================================================================
--- zpkgtools/trunk/zpkgtools/setup.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/setup.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,217 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Generator for distutils setup.py files."""
-
-import errno
-import os
-import posixpath
-import re
-import sys
-
-from zpkgtools import include
-from zpkgtools import package
-from zpkgtools import publication
-
-
-class SetupContext:
- """Object representing the arguments to distutils.core.setup()."""
-
- def __init__(self, pkgname, version, setup_file):
- self._working_dir = os.path.dirname(os.path.abspath(setup_file))
- self._pkgname = pkgname
- self.version = version
- self.packages = []
- self.package_data = {}
- self.package_dir = {}
- self.ext_modules = []
- self.scripts = []
- self.platforms = None
- self.classifiers = None
- self.data_files = []
-
- def initialize(self):
- self.load_metadata(
- os.path.join(self._working_dir, self._pkgname,
- publication.PUBLICATION_CONF))
- pkgdir = os.path.join(self._working_dir, self._pkgname)
- self.scan(self._pkgname, pkgdir, self._pkgname)
- depsdir = os.path.join(self._working_dir, "Dependencies")
- if os.path.isdir(depsdir):
- depnames = os.listdir(depsdir)
- suffix = "-%s-%s" % (self._pkgname, self.version)
- for name in depnames:
- if name != "Includes" and not name.endswith(suffix):
- # an unexpected name; we didn't put this here!
- print >>sys.stderr, \
- "unexpected name in Dependencies/: %r" % name
- continue
- depdir = os.path.join(depsdir, name)
- if not os.path.isdir(depdir):
- # a file; we didn't put this here either!
- print >>sys.stderr, \
- "unexpected file in Dependencies/: %r" % name
- continue
- depname = name[:-len(suffix)]
- pkgdir = os.path.join(depdir, depname)
- reldir = posixpath.join("Dependencies", name, depname)
- self.scan(depname, pkgdir, reldir)
- includes_dir = os.path.join(depsdir, "Includes")
- if os.path.isdir(includes_dir):
- for ext in self.ext_modules:
- ext.include_dirs.append(includes_dir)
-
- def setup(self):
- kwargs = self.__dict__.copy()
- for name in self.__dict__:
- if name[0] == "_":
- del kwargs[name]
- if "--debug" in sys.argv:
- import pprint
- try:
- pprint.pprint(kwargs)
- except IOError, e:
- if e.errno != errno.EPIPE:
- raise
- else:
- if sys.version_info < (2, 3):
- from distutils.dist import DistributionMetadata
- DistributionMetadata.classifiers = None
- DistributionMetadata.download_url = None
- try:
- from setuptools import setup
- except ImportError:
- # package_data can't be handled this way ;-(
- if self.package_data:
- print >>sys.stderr, (
- "can't import setuptools;"
- " some package data will not be properly installed")
- from distutils.core import setup
- setup(**kwargs)
-
- def load_metadata(self, path):
- f = open(path, "rU")
- publication.load(f, metadata=self)
- if self.platforms:
- self.platforms = ", ".join(self.platforms)
- m = re.match(r"\d+\.\d+(\.\d+)?(?:(?P<status>[ab])\d*)?$",
- self.version)
- if m is not None:
- devstatus = publication.STABLE
- status = m.group("status")
- if status == "a":
- devstatus = publication.ALPHA
- elif status == "b":
- devstatus = publication.BETA
- publication.set_development_status(self, devstatus)
-
- def scan(self, name, directory, reldir):
- init_py = os.path.join(directory, "__init__.py")
- if os.path.isfile(init_py):
- self.scan_package(name, directory, reldir)
- else:
- self.scan_collection(name, directory, reldir)
-
- def scan_collection(self, name, directory, reldir):
- # load the collection metadata
- pkginfo = package.loadCollectionInfo(directory, reldir)
- self.scan_basic(pkginfo)
-
- def scan_package(self, name, directory, reldir):
- # load the package metadata
- pkginfo = package.loadPackageInfo(name, directory, reldir)
- self.scan_basic(pkginfo)
- self.ext_modules.extend(pkginfo.extensions)
- self.add_package_dir(name, reldir)
-
- # scan the files in the directory:
- files = include.filter_names(os.listdir(directory))
- for fn in files:
- fnbase, ext = os.path.splitext(fn)
- path = os.path.join(directory, fn)
- if os.path.isdir(path):
- init_py = os.path.join(path, "__init__.py")
- if os.path.isfile(init_py):
- # if this package is published separately, skip it:
- # XXX we shouldn't actually need this if we only
- # use this class to scan in the generated
- # distributions
- if os.path.isfile(
- os.path.join(path, publication.PUBLICATION_CONF)):
- continue
- pkgname = "%s.%s" % (name, fn)
- self.scan_package(
- pkgname, path, posixpath.join(reldir, fn))
- else:
- # an ordinary directory
- self.scan_directory(name, path, fn)
- # Only add the file as package data if it's not a Python
- # source file; Python files are copied in automatically.
- elif not fn.endswith(".py"):
- self.add_package_file(name, fn)
-
- # We need to check that any files that were labelled as
- # scripts or application data aren't copied in as package
- # data; they shouldn't be installed into the package itself.
- #
- # XXX I'm not sure whether documentation files should be
- # removed from package_data or not, given that there's no spec
- # for installing documentation other than for RPMs.
- #
- relbase = posixpath.join(reldir, "")
- pkgfiles = self.package_data.get(name, [])
- non_pkgdata = pkginfo.script + pkginfo.header
- for dir, files in pkginfo.data_files:
- non_pkgdata.extend(files)
- for ext in pkginfo.extensions:
- for fn in ext.sources + getattr(ext, "depends", []):
- if fn not in non_pkgdata:
- non_pkgdata.append(fn)
- for fn in non_pkgdata:
- pkgdatapath = fn[len(relbase):]
- if pkgdatapath in pkgfiles:
- pkgfiles.remove(pkgdatapath)
-
- def scan_directory(self, pkgname, directory, reldir):
- """Scan a data directory, adding files to package_data."""
- files = include.filter_names(os.listdir(directory))
- for fn in files:
- path = os.path.join(directory, fn)
- if os.path.isdir(path):
- self.scan_directory(pkgname,
- os.path.join(directory, fn),
- posixpath.join(reldir, fn))
- else:
- self.add_package_file(pkgname, posixpath.join(reldir, fn))
-
- def scan_basic(self, pkginfo):
- self.scripts.extend(pkginfo.script)
- if pkginfo.data_files:
- if self.data_files:
- # merge:
- d = dict(self.data_files)
- for dir, files in pkginfo.data_files:
- L = d.setdefault(dir, [])
- L.extend(files)
- self.data_files = d.items()
- else:
- self.data_files = pkginfo.data_files
-
- def add_package_dir(self, pkgname, reldir):
- self.packages.append(pkgname)
- if pkgname.replace(".", "/") != reldir:
- self.package_dir[pkgname] = reldir
-
- def add_package_file(self, pkgname, relfn):
- L = self.package_data.setdefault(pkgname, [])
- L.append(relfn)
Modified: zpkgtools/trunk/zpkgtools/tests/input/packages.map
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/input/packages.map 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/input/packages.map 2004-06-17 16:12:11 UTC (rev 25887)
@@ -4,4 +4,3 @@
collection:collection-2 collection-2/
package package/
-package2 package2/
Modified: zpkgtools/trunk/zpkgtools/tests/runtests.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/runtests.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/runtests.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -27,36 +27,13 @@
TOPDIR = os.path.dirname(PKGDIR)
-def load_tests(name):
- name = "zpkgtools.tests." + name
- __import__(name)
- mod = sys.modules[name]
- return mod.test_suite()
-
-
def test_suite():
- L = []
- for fn in os.listdir(TESTDIR):
- name, ext = os.path.splitext(fn)
- if name[:4] == "test" and ext == ".py":
- L.append(load_tests(name))
- suite = L.pop()
- for t in L:
- suite.addTest(t)
- return suite
+ from zpkgsetup.tests.runtests import make_directory_suite
+ return make_directory_suite("zpkgtools.tests", TESTDIR)
-class MyTestProgram(unittest.TestProgram):
- """Test runner program that doesn't use docstrings as descriptions."""
-
- def runTests(self):
- if self.testRunner is None:
- self.testRunner = unittest.TextTestRunner(descriptions=False,
- verbosity=self.verbosity)
- unittest.TestProgram.runTests(self)
-
-
if __name__ == "__main__":
if TOPDIR not in sys.path:
sys.path.insert(0, TOPDIR)
+ from zpkgsetup.tests.runtests import MyTestProgram
MyTestProgram(defaultTest="test_suite")
Modified: zpkgtools/trunk/zpkgtools/tests/test_app.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_app.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_app.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -22,12 +22,13 @@
from StringIO import StringIO
+from zpkgsetup import publication
+
import zpkgtools
from zpkgtools import app
from zpkgtools import include
from zpkgtools import loader
-from zpkgtools import publication
CMD = "./foo/bar.py"
Deleted: zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,162 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.cfgparser."""
-
-import unittest
-
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-
-
-class SimpleSection:
-
- finished = False
- ending_parent = None
- ending_typename = None
- ending_name = None
-
- def __init__(self, parent=None, typename=None, name=None):
- self.parent = parent
- self.typename = typename
- self.name = name
-
-
-class AnythingGoesSchema:
-
- def getConfiguration(self):
- return SimpleSection()
-
- def startSection(self, parent, typename, name):
- return SimpleSection(parent, typename, name)
-
- def finishSection(self, section):
- section.finished = True
- return section
-
- def endSection(self, parent, typename, name, child):
- child.ending_parent = parent
- child.ending_typename = typename
- child.ending_name = name
- if not hasattr(parent, typename):
- setattr(parent, typename, [])
- getattr(parent, typename).append(child)
- self.finishSection(child)
-
- def addValue(self, section, key, value):
- key = key.lower().replace("-", "_")
- if not hasattr(section, key):
- setattr(section, key, [])
- getattr(section, key).append(value)
-
-
-class ParserTestCase(unittest.TestCase):
-
- schema = AnythingGoesSchema()
-
- def createParser(self, text=""):
- sio = StringIO(text)
- self.parser = cfgparser.Parser(sio, "<some-url>", self.schema)
- return self.parser
-
- def test_replace(self):
- # "legal" values are those that are legal in ZConfig
- eq = self.assertEqual
- raises = self.assertRaises
- replace = self.createParser().replace
-
- # some legal values that don't have '$':
- eq(replace(""), "")
- eq(replace(" foo bar "), " foo bar ")
- eq(replace("x"), "x")
-
- # legal, supported values with '$':
- eq(replace("$$"), "$")
- eq(replace("$$$$"), "$$")
- eq(replace("$$xyz$$"), "$xyz$")
-
- # legal, unsupported values (all have '$'):
- raises(cfgparser.ConfigurationError, replace, "$foo")
- raises(cfgparser.ConfigurationError, replace, "${foo-bar}")
-
- # illegal values:
- raises(cfgparser.ConfigurationError, replace, "$")
- raises(cfgparser.ConfigurationError, replace, "foo$")
-
- def test_schema_use(self):
- eq = self.assertEqual
- p = self.createParser("""
- # This is a comment.
-
- key value 1
- key value 2
- <section/>
- <section foo/>
- <section>
- key value 3
- </section>
- <section splat>
- <inner>
- key value 5
- </inner>
- key value 4
- </section>
- """)
- cf = p.load()
- self.check_section(cf, None, None, None, key=["value 1", "value 2"])
- s1, s2, s3, s4 = cf.section
- self.check_section(s1, cf, None, "section")
- self.check_section(s2, cf, "foo", "section")
- self.check_section(s3, cf, None, "section", key=["value 3"])
- self.check_section(s4, cf, "splat", "section", key=["value 4"])
- inner, = s4.inner
- self.check_section(inner, s4, None, "inner", key=["value 5"])
-
- def check_section(self, section, parent, name, typename, **attrs):
- self.assert_(section.finished)
- self.assert_(section.parent is parent)
- self.assert_(section.parent is section.ending_parent)
- self.assertEqual(section.name, name)
- self.assertEqual(section.name, section.ending_name)
- self.assertEqual(section.typename, typename)
- self.assertEqual(section.typename, section.ending_typename)
- for name, value in attrs.iteritems():
- v = getattr(section, name)
- self.assertEqual(v, value)
-
-
-class SchemaTestCase(unittest.TestCase):
-
- top_level_converted = False
-
- def setUp(self):
- self.schema = cfgparser.Schema(
- ({}, [], self.top_level_conversion))
-
- def top_level_conversion(self, section):
- self.top_level_converted = True
- return section
-
- def test_getConfiguration(self):
- cf = self.schema.getConfiguration()
- self.failIf(self.top_level_converted)
-
-
-def test_suite():
- suite = unittest.makeSuite(ParserTestCase)
- suite.addTest(unittest.makeSuite(SchemaTestCase))
- return suite
-
-if __name__ == "__main__":
- unittest.main(defaultTest="test_suite")
Modified: zpkgtools/trunk/zpkgtools/tests/test_config.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_config.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_config.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -18,7 +18,7 @@
from StringIO import StringIO
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
from zpkgtools import config
Modified: zpkgtools/trunk/zpkgtools/tests/test_include.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_include.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_include.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,7 +23,8 @@
from os.path import join
from StringIO import StringIO
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
+
from zpkgtools import include
from zpkgtools import loader
Deleted: zpkgtools/trunk/zpkgtools/tests/test_package.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_package.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_package.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,213 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.package."""
-
-import doctest
-import os.path
-import shutil
-import tempfile
-import unittest
-
-from distutils.core import Extension
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-from zpkgtools import package
-
-
-class PackageInfoTestCase(unittest.TestCase):
-
- def setUp(self):
- self.tmpdir = tempfile.mkdtemp(prefix="test_package_")
-
- def tearDown(self):
- shutil.rmtree(self.tmpdir)
-
- def write_config(self, text):
- self.write_file(package.PACKAGE_CONF, text)
-
- def write_file(self, name, text):
- f = open(os.path.join(self.tmpdir, name), "w")
- f.write(text)
- f.close()
-
- def test_empty_pkginfo(self):
- self.write_config("# empty configuration file\n")
- pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
- eq = self.assertEqual
- eq(pkginfo.extensions, [])
- eq(pkginfo.documentation, [])
- eq(pkginfo.script, [])
-
- def test_missing_pkginfo(self):
- pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
- eq = self.assertEqual
- eq(pkginfo.extensions, [])
- eq(pkginfo.documentation, [])
- eq(pkginfo.script, [])
-
- def test_nonempty_pkginfo(self):
- self.write_config("documentation doc/README.txt\n"
- "script bin/runme.py\n"
- "<extension cricket>\n"
- " source jiminy.c\n"
- " define FOO\n"
- " define BAR = splat\n"
- " undefine CRUNCHY NUGGET\n"
- " depends-on cricket.h\n"
- " depends-on innerds.c\n"
- " language C\n"
- "</extension>\n")
- os.mkdir(os.path.join(self.tmpdir, "doc"))
- self.write_file(os.path.join("doc", "README.txt"),
- "docs go here")
- os.mkdir(os.path.join(self.tmpdir, "bin"))
- self.write_file(os.path.join("bin", "runme.py"),
- "#!/bin/sh\nexit\n")
- pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
- eq = self.assertEqual
- eq(len(pkginfo.extensions), 1)
- eq(pkginfo.documentation, ["bar/doc/README.txt"])
- eq(pkginfo.script, ["bar/bin/runme.py"])
-
- ext = pkginfo.extensions[0]
- self.assert_(isinstance(ext, Extension))
- eq(ext.name, "foo.cricket")
- eq(ext.sources, ["bar/jiminy.c"])
- eq(ext.depends, ["bar/cricket.h", "bar/innerds.c"])
- eq(ext.define_macros, [("FOO", None), ("BAR", "splat")])
- eq(ext.undef_macros, ["CRUNCHY", "NUGGET"])
- eq(ext.language, "C")
-
- def test_broken_extension_too_many_languages(self):
- self.write_config("<extension cricket>\n"
- " source jiminy.c\n"
- " language C\n"
- " language C++\n"
- "</extension>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
- def test_broken_extension_without_name(self):
- self.write_config("<extension>\n"
- " source jiminy.c\n"
- "</extension>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
- def test_broken_extension_no_source(self):
- self.write_config("<extension cricket/>")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
- def test_collection_empty_pkginfo(self):
- self.write_config("# empty configuration file\n")
- pkginfo = package.loadCollectionInfo(self.tmpdir, None)
- eq = self.assertEqual
- eq(pkginfo.extensions, [])
- eq(pkginfo.documentation, [])
- eq(pkginfo.script, [])
-
- def test_collection_missing_pkginfo(self):
- pkginfo = package.loadCollectionInfo(self.tmpdir, None)
- eq = self.assertEqual
- eq(pkginfo.extensions, [])
- eq(pkginfo.documentation, [])
- eq(pkginfo.script, [])
-
- def test_collection_pkginfo(self):
- self.write_config("documentation doc/*\n"
- "script bin/*.py\n")
- os.mkdir(os.path.join(self.tmpdir, "doc"))
- self.write_file(os.path.join("doc", "README.txt"),
- "docs go here")
- os.mkdir(os.path.join(self.tmpdir, "bin"))
- self.write_file(os.path.join("bin", "runme.py"),
- "#!/bin/sh\nexit\n")
- pkginfo = package.loadCollectionInfo(self.tmpdir, None)
- eq = self.assertEqual
- eq(len(pkginfo.extensions), 0)
- eq(pkginfo.documentation, ["doc/README.txt"])
- eq(pkginfo.script, ["bin/runme.py"])
-
- def test_collection_pkginfo_disallows_extensions(self):
- self.write_config("<extension foo>\n"
- " source foo.c\n"
- "</extension>\n")
- self.assertRaises(ValueError, package.loadCollectionInfo,
- self.tmpdir, None)
-
- def test_data_files_1(self):
- self.write_config("<data-files etc>\n"
- " foo*\n"
- "</data-files>\n")
- self.write_file("foo1.conf", "config goes here")
- self.write_file("foo2.conf", "config goes here")
- pkginfo = package.loadCollectionInfo(self.tmpdir, None)
- pkginfo.data_files[0][1].sort()
- self.assertEqual(pkginfo.data_files,
- [("etc", ["foo1.conf", "foo2.conf"])])
-
- def test_data_files_2(self):
- self.write_config("<data-files var>\n"
- " foo2.conf\n"
- "</data-files>\n"
- "<data-files etc>\n"
- " foo1.conf\n"
- "</data-files>\n")
- self.write_file("foo1.conf", "config goes here")
- self.write_file("foo2.conf", "config goes here")
- pkginfo = package.loadCollectionInfo(self.tmpdir, None)
- pkginfo.data_files.sort()
- self.assertEqual(pkginfo.data_files,
- [("etc", ["foo1.conf"]),
- ("var", ["foo2.conf"])])
-
- def test_data_files_error_has_value(self):
- self.write_config("<data-files etc>\n"
- " foo bar\n"
- "</data-files>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadCollectionInfo, self.tmpdir, None)
-
- def test_data_files_error_has_nested_section(self):
- self.write_config("<data-files etc>\n"
- " <extension foo>\n"
- " </extension>\n"
- "</data-files>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadCollectionInfo, self.tmpdir, None)
-
- def test_data_files_error_section_without_name(self):
- self.write_config("<data-files>\n"
- "</data-files>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadCollectionInfo, self.tmpdir, None)
-
- def test_data_files_error_sections_with_same_name(self):
- self.write_config("<data-files etc>\n"
- "</data-files>\n"
- "<data-files etc/>\n"
- "</data-files>\n")
- self.assertRaises(cfgparser.ConfigurationError,
- package.loadCollectionInfo, self.tmpdir, None)
-
-
-def test_suite():
- suite = doctest.DocTestSuite("zpkgtools.package")
- suite.addTest(unittest.makeSuite(PackageInfoTestCase))
- return suite
-
-if __name__ == "__main__":
- unittest.main(defaultTest="test_suite")
Deleted: zpkgtools/trunk/zpkgtools/tests/test_publication.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_publication.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_publication.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,59 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.publication
-
-$Id: test_publication.py,v 1.1 2004/06/14 20:46:41 fdrake Exp $
-"""
-import unittest
-
-from zpkgtools import publication
-
-
-class DevelopmentStatusTestCase(unittest.TestCase):
-
- def test_set_development_status_replace_1(self):
- metadata = publication.loads(
- "Name: foo\n"
- "Classifier: Development Status:: 3 - Alpha\n")
- publication.set_development_status(metadata, publication.BETA)
- self.assertEqual(metadata.classifiers, [publication.BETA])
-
- def test_set_development_status_replace_2(self):
- metadata = publication.loads(
- "Name: foo\n"
- "Classifier: Environment :: Console\n"
- "Classifier: Development Status:: 3 - Alpha\n"
- "Classifier: Intended Audience :: Developers\n")
- publication.set_development_status(metadata, publication.BETA)
- self.assertEqual(metadata.classifiers, [
- "Environment :: Console",
- publication.BETA,
- "Intended Audience :: Developers",
- ])
-
- def test_set_development_status_append(self):
- metadata = publication.loads(
- "Name: foo\n"
- "Classifier: Environment :: Console\n"
- "Classifier: Intended Audience :: Developers\n")
- publication.set_development_status(metadata, publication.BETA)
- self.assertEqual(metadata.classifiers, [
- "Environment :: Console",
- "Intended Audience :: Developers",
- publication.BETA,
- ])
-
-
-def test_suite():
- return unittest.makeSuite(DevelopmentStatusTestCase)
Deleted: zpkgtools/trunk/zpkgtools/tests/test_setup.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_setup.py 2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_setup.py 2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,57 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests of zpkgtools.setup."""
-
-import os
-import unittest
-
-from zpkgtools import publication
-from zpkgtools import setup
-
-
-here = os.path.dirname(os.path.abspath(__file__))
-
-
-class SetupContextTestCase(unittest.TestCase):
-
- def test_python_files_as_data(self):
- packagedir = os.path.join(here, "input", "package")
- publicationcfg = os.path.join(packagedir, publication.PUBLICATION_CONF)
- setupfile = os.path.join(here, "input", "setup.py")
- f = open(publicationcfg, "w")
- f.write("Metadata-version: 1.0\n"
- "Name: foo\n")
- f.close()
- try:
- context = setup.SetupContext("package", "0.1.234", setupfile)
- context.initialize()
- context.package_data["package"].sort()
- self.assertEqual(context.package_data,
- {"package": ["PUBLICATION.cfg",
- "datadir/justdata.py"]})
- finally:
- os.unlink(publicationcfg)
-
- def test_extension_sources_are_not_package_data(self):
- packagedir = os.path.join(here, "input", "package2")
- setupfile = os.path.join(here, "input", "setup.py")
- context = setup.SetupContext("package2", "0.1.234", setupfile)
- context.initialize()
- context.package_data["package2"].sort()
- self.assertEqual(context.package_data,
- {"package2": ["PUBLICATION.cfg", "SETUP.cfg"]})
-
-
-def test_suite():
- return unittest.makeSuite(SetupContextTestCase)
More information about the Zope-CVS
mailing list