[Python-checkins] distutils2: merged upstream
tarek.ziade
python-checkins at python.org
Sun Jul 4 11:48:38 CEST 2010
tarek.ziade pushed be8f96b7c538 to distutils2:
http://hg.python.org/distutils2/rev/be8f96b7c538
changeset: 259:be8f96b7c538
parent: 258:0b00b7e6e0b8
parent: 133:d519643faee6
user: Konrad Delong <konryd at gmail.com>
date: Sun May 09 13:02:57 2010 -0400
summary: merged upstream
files:
diff --git a/.hgtags b/.hgtags
new file mode 100644
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1,1 @@
+5847fb2b7549fb301882c1054eb8b3d0893e3570 1.0a1
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -2,9 +2,16 @@
CHANGES
=======
-1.0a1
------
+1.0a2 - ?
+--------
-- Initial import from the stdlib
+-
+1.0a1 - 2010-05-06
+------------------
+- Initial import from the stdlib [tarek]
+- Added support for PEP 376 in distutils2.version [tarek]
+- Added support for PEP 345 in distutils2.metadata [tarek]
+- Added distutils2.util.find_package [tarek]
+
diff --git a/src/README.txt b/src/README.txt
--- a/src/README.txt
+++ b/src/README.txt
@@ -1,5 +1,15 @@
-======
-README
-======
+==========
+Distutils2
+==========
+Welcome to Distutils2 !
+Distutils2 is the new version of Distutils. It's not backward compatible with
+Distutils but provides more features, and implement most new packaging
+standards.
+
+See the documentation at http://packages.python.org/Distutils2 for more info.
+
+**Beware that Distutils2 is its in early stage and should not be used in
+production. Its API is subject to changes**
+
diff --git a/src/distutils2/__init__.py b/src/distutils2/__init__.py
--- a/src/distutils2/__init__.py
+++ b/src/distutils2/__init__.py
@@ -10,7 +10,7 @@
__all__ = ['__version__', 'setup']
__revision__ = "$Id: __init__.py 78020 2010-02-06 16:37:32Z benjamin.peterson $"
-__version__ = "1.0a1"
+__version__ = "1.0a2"
from distutils2.core import setup
diff --git a/src/distutils2/metadata.py b/src/distutils2/metadata.py
--- a/src/distutils2/metadata.py
+++ b/src/distutils2/metadata.py
@@ -103,20 +103,44 @@
if marker in keys:
return True
return False
+
keys = fields.keys()
- is_1_1 = _has_marker(keys, _314_MARKERS)
- is_1_2 = _has_marker(keys, _345_MARKERS)
+ possible_versions = ['1.0', '1.1', '1.2']
+
+
+ # first let's try to see if a field is not part of one of the version
+ for key in keys:
+ if key not in _241_FIELDS and '1.0' in possible_versions:
+ possible_versions.remove('1.0')
+ if key not in _314_FIELDS and '1.1' in possible_versions:
+ possible_versions.remove('1.1')
+ if key not in _345_FIELDS and '1.2' in possible_versions:
+ possible_versions.remove('1.2')
+
+ # possible_version contains qualified versions
+ if len(possible_versions) == 1:
+ return possible_versions[0] # found !
+ elif len(possible_versions) == 0:
+ raise MetadataConflictError('Unknown metadata set')
+
+ # let's see if one unique marker is found
+ is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS)
+ is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS)
if is_1_1 and is_1_2:
- raise MetadataConflictError('You used both 1.1 and 1.2 fields')
+ raise MetadataConflictError('You used incompatible 1.1 and 1.2 fields')
# we have the choice, either 1.0, or 1.2
# - 1.0 has a broken Summary field but work with all tools
# - 1.1 is to avoid
# - 1.2 fixes Summary but is not spreaded yet
if not is_1_1 and not is_1_2:
- return PKG_INFO_PREFERRED_VERSION
+ # we couldn't find any specific marker
+ if PKG_INFO_PREFERRED_VERSION in possible_versions:
+ return PKG_INFO_PREFERRED_VERSION
if is_1_1:
return '1.1'
+
+ # default marker when 1.0 is disqualified
return '1.2'
_ATTR2FIELD = {'metadata_version': 'Metadata-Version',
@@ -269,6 +293,8 @@
if field in _LISTFIELDS:
# we can have multiple lines
values = msg.get_all(field)
+ if field in _LISTTUPLEFIELDS and values is not None:
+ values = [tuple(value.split(',')) for value in values]
self.set(field, values)
else:
# single line
@@ -299,6 +325,9 @@
values = values.replace('\n', '\n |')
values = [values]
+ if field in _LISTTUPLEFIELDS:
+ values = [','.join(value) for value in values]
+
for value in values:
self._write_field(fileobject, field, value)
diff --git a/src/distutils2/tests/test_metadata.py b/src/distutils2/tests/test_metadata.py
--- a/src/distutils2/tests/test_metadata.py
+++ b/src/distutils2/tests/test_metadata.py
@@ -4,7 +4,8 @@
import sys
from StringIO import StringIO
-from distutils2.metadata import DistributionMetadata, _interpret
+from distutils2.metadata import (DistributionMetadata, _interpret,
+ PKG_INFO_PREFERRED_VERSION)
class DistributionMetadataTestCase(unittest2.TestCase):
@@ -200,6 +201,31 @@
self.assertEquals(missing, ['Name', 'Home-page'])
self.assertEquals(len(warnings), 2)
+ def test_best_choice(self):
+ metadata = DistributionMetadata()
+ metadata['Version'] = '1.0'
+ self.assertEquals(metadata.version, PKG_INFO_PREFERRED_VERSION)
+ metadata['Classifier'] = ['ok']
+ self.assertEquals(metadata.version, '1.2')
+
+ def test_project_urls(self):
+ # project-url is a bit specific, make sure we write it
+ # properly in PKG-INFO
+ metadata = DistributionMetadata()
+ metadata['Version'] = '1.0'
+ metadata['Project-Url'] = [('one', 'http://ok')]
+ self.assertEquals(metadata['Project-Url'], [('one', 'http://ok')])
+ file_ = StringIO()
+ metadata.write_file(file_)
+ file_.seek(0)
+ res = file_.read().split('\n')
+ self.assertIn('Project-URL: one,http://ok', res)
+
+ file_.seek(0)
+ metadata = DistributionMetadata()
+ metadata.read_file(file_)
+ self.assertEquals(metadata['Project-Url'], [('one', 'http://ok')])
+
def test_suite():
return unittest2.makeSuite(DistributionMetadataTestCase)
diff --git a/src/distutils2/tests/test_util.py b/src/distutils2/tests/test_util.py
--- a/src/distutils2/tests/test_util.py
+++ b/src/distutils2/tests/test_util.py
@@ -14,7 +14,7 @@
check_environ, split_quoted, strtobool,
rfc822_escape, get_compiler_versions,
_find_exe_version, _MAC_OS_X_LD_VERSION,
- byte_compile)
+ byte_compile, find_packages)
from distutils2 import util
from distutils2.tests import support
@@ -32,7 +32,9 @@
self.stdout = StringIO(exes[self.cmd])
self.stderr = StringIO()
-class UtilTestCase(support.EnvironGuard, unittest2.TestCase):
+class UtilTestCase(support.EnvironGuard,
+ support.TempdirManager,
+ unittest2.TestCase):
def setUp(self):
super(UtilTestCase, self).setUp()
@@ -257,6 +259,44 @@
self.assertRaises(DistutilsFileError, util.newer, 'xxx', 'xxx')
+ def test_find_packages(self):
+ # let's create a structure we want to scan:
+ #
+ # pkg1
+ # __init__
+ # pkg2
+ # __init__
+ # pkg3
+ # __init__
+ # pkg6
+ # __init__
+ # pkg4 <--- not a pkg
+ # pkg8
+ # __init__
+ # pkg5
+ # __init__
+ #
+ root = self.mkdtemp()
+ pkg1 = os.path.join(root, 'pkg1')
+ os.mkdir(pkg1)
+ self.write_file(os.path.join(pkg1, '__init__.py'))
+ os.mkdir(os.path.join(pkg1, 'pkg2'))
+ self.write_file(os.path.join(pkg1, 'pkg2', '__init__.py'))
+ os.mkdir(os.path.join(pkg1, 'pkg3'))
+ self.write_file(os.path.join(pkg1, 'pkg3', '__init__.py'))
+ os.mkdir(os.path.join(pkg1, 'pkg3', 'pkg6'))
+ self.write_file(os.path.join(pkg1, 'pkg3', 'pkg6', '__init__.py'))
+ os.mkdir(os.path.join(pkg1, 'pkg4'))
+ os.mkdir(os.path.join(pkg1, 'pkg4', 'pkg8'))
+ self.write_file(os.path.join(pkg1, 'pkg4', 'pkg8', '__init__.py'))
+ pkg5 = os.path.join(root, 'pkg5')
+ os.mkdir(pkg5)
+ self.write_file(os.path.join(pkg5, '__init__.py'))
+
+ res = find_packages([root], ['pkg1.pkg2'])
+ self.assertEquals(res, ['pkg1', 'pkg5', 'pkg1.pkg3', 'pkg1.pkg3.pkg6'])
+
+
def test_suite():
return unittest2.makeSuite(UtilTestCase)
diff --git a/src/distutils2/util.py b/src/distutils2/util.py
--- a/src/distutils2/util.py
+++ b/src/distutils2/util.py
@@ -7,6 +7,7 @@
__revision__ = "$Id: util.py 77761 2010-01-26 22:46:15Z tarek.ziade $"
import sys, os, string, re
+from fnmatch import fnmatchcase
from distutils2.errors import (DistutilsPlatformError, DistutilsFileError,
DistutilsByteCompileError)
@@ -543,3 +544,70 @@
f.write(line + "\n")
f.close()
+def _is_package(path):
+ """Returns True if path is a package (a dir with an __init__ file."""
+ if not os.path.isdir(path):
+ return False
+ return os.path.isfile(os.path.join(path, '__init__.py'))
+
+def _under(path, root):
+ path = path.split(os.sep)
+ root = root.split(os.sep)
+ if len(root) > len(path):
+ return False
+ for pos, part in enumerate(root):
+ if path[pos] != part:
+ return False
+ return True
+
+def _package_name(root_path, path):
+ """Returns a dotted package name, given a subpath."""
+ if not _under(path, root_path):
+ raise ValueError('"%s" is not a subpath of "%s"' % (path, root_path))
+ return path[len(root_path) + 1:].replace(os.sep, '.')
+
+def find_packages(paths=('.',), exclude=()):
+ """Return a list all Python packages found recursively within
+ directories 'paths'
+
+ 'paths' should be supplied as a sequence of "cross-platform"
+ (i.e. URL-style) path; it will be converted to the appropriate local
+ path syntax.
+
+ 'exclude' is a sequence of package names to exclude; '*' can be used as
+ a wildcard in the names, such that 'foo.*' will exclude all subpackages
+ of 'foo' (but not 'foo' itself).
+ """
+ packages = []
+ discarded = []
+ def _discarded(path):
+ for discard in discarded:
+ if _under(path, discard):
+ return True
+ return False
+
+ for path in paths:
+ path = convert_path(path)
+ for root, dirs, files in os.walk(path):
+ for dir_ in dirs:
+ fullpath = os.path.join(root, dir_)
+ if _discarded(fullpath):
+ continue
+ # we work only with Python packages
+ if not _is_package(fullpath):
+ discarded.append(fullpath)
+ continue
+ # see if it's excluded
+ excluded = False
+ package_name = _package_name(path, fullpath)
+ for pattern in exclude:
+ if fnmatchcase(package_name, pattern):
+ excluded = True
+ break
+ if excluded:
+ continue
+
+ # adding it to the list
+ packages.append(package_name)
+ return packages
+
diff --git a/src/setup.py b/src/setup.py
--- a/src/setup.py
+++ b/src/setup.py
@@ -8,6 +8,7 @@
from distutils2.command.sdist import sdist
from distutils2.command.install import install
from distutils2 import __version__ as VERSION
+from distutils2.util import find_packages
f = open('README.txt')
try:
@@ -67,20 +68,36 @@
if sys.version < '2.6':
setup_kwargs['scripts'] = ['distutils2/mkpkg.py']
+_CLASSIFIERS = """\
+Development Status :: 3 - Alpha
+Intended Audience :: Developers
+License :: OSI Approved :: Python Software Foundation License
+Operating System :: OS Independent
+Programming Language :: Python
+Topic :: Software Development :: Libraries :: Python Modules
+Topic :: System :: Archiving :: Packaging
+Topic :: System :: Systems Administration
+Topic :: Utilities"""
+
setup (name="Distutils2",
version=VERSION,
- description="Python Distribution Utilities",
+ summary="Python Distribution Utilities",
+ keywords=['packaging', 'distutils'],
author="Tarek Ziade",
author_email="tarek at ziade.org",
- url="http://www.python.org/sigs/distutils-sig",
+ home_page="http://bitbucket.org/tarek/distutils2/wiki/Home",
license="PSF",
- long_description=README,
- packages=['distutils2',
- 'distutils2.command',
- 'distutils2.tests',
- 'distutils2._backport'],
+ description=README,
+ classifier=_CLASSIFIERS.split('\n'),
+ packages=find_packages(),
cmdclass={'sdist': sdist_hg, 'install': install_hg},
package_data={'distutils2._backport': ['sysconfig.cfg']},
+ project_url=[('Mailing-list',
+ 'http://mail.python.org/mailman/listinfo/distutils-sig/'),
+ ('Documentation',
+ 'http://packages.python.org/Distutils2'),
+ ('Repository', 'http://hg.python.org/distutils2'),
+ ('Bug tracker', 'http://bugs.python.org')],
**setup_kwargs
)
--
Repository URL: http://hg.python.org/distutils2
More information about the Python-checkins
mailing list