[PATCH 05/13] python-extras: Move from lib/ to third_party/.
Jelmer Vernooij
jelmer at samba.org
Sat Nov 15 12:17:00 MST 2014
Change-Id: I7f95ab5bb46a72aa0aa45e2275677ddc6a9e5f14
Signed-off-by: Jelmer Vernooij <jelmer at samba.org>
---
lib/extras/.gitignore | 35 ----
lib/extras/.testr.conf | 4 -
lib/extras/LICENSE | 26 ---
lib/extras/MANIFEST.in | 6 -
lib/extras/Makefile | 30 ----
lib/extras/NEWS | 27 ---
lib/extras/README.rst | 57 -------
lib/extras/extras/__init__.py | 103 ------------
lib/extras/extras/tests/__init__.py | 17 --
lib/extras/extras/tests/test_extras.py | 186 ---------------------
lib/extras/setup.cfg | 4 -
lib/extras/setup.py | 48 ------
lib/update-external.sh | 2 +-
lib/wscript_build | 1 -
python/samba/__init__.py | 2 +-
python/samba/tests/__init__.py | 4 +-
selftest/selftesthelpers.py | 6 +-
selftest/subunithelper.py | 2 +-
third_party/python-extras/.gitignore | 35 ++++
third_party/python-extras/.testr.conf | 4 +
third_party/python-extras/LICENSE | 26 +++
third_party/python-extras/MANIFEST.in | 6 +
third_party/python-extras/Makefile | 30 ++++
third_party/python-extras/NEWS | 27 +++
third_party/python-extras/README.rst | 57 +++++++
third_party/python-extras/extras/__init__.py | 103 ++++++++++++
third_party/python-extras/extras/tests/__init__.py | 17 ++
.../python-extras/extras/tests/test_extras.py | 186 +++++++++++++++++++++
third_party/python-extras/setup.cfg | 4 +
third_party/python-extras/setup.py | 48 ++++++
third_party/wscript_build | 1 +
31 files changed, 552 insertions(+), 552 deletions(-)
delete mode 100644 lib/extras/.gitignore
delete mode 100644 lib/extras/.testr.conf
delete mode 100644 lib/extras/LICENSE
delete mode 100644 lib/extras/MANIFEST.in
delete mode 100644 lib/extras/Makefile
delete mode 100644 lib/extras/NEWS
delete mode 100644 lib/extras/README.rst
delete mode 100644 lib/extras/extras/__init__.py
delete mode 100644 lib/extras/extras/tests/__init__.py
delete mode 100644 lib/extras/extras/tests/test_extras.py
delete mode 100644 lib/extras/setup.cfg
delete mode 100755 lib/extras/setup.py
create mode 100644 third_party/python-extras/.gitignore
create mode 100644 third_party/python-extras/.testr.conf
create mode 100644 third_party/python-extras/LICENSE
create mode 100644 third_party/python-extras/MANIFEST.in
create mode 100644 third_party/python-extras/Makefile
create mode 100644 third_party/python-extras/NEWS
create mode 100644 third_party/python-extras/README.rst
create mode 100644 third_party/python-extras/extras/__init__.py
create mode 100644 third_party/python-extras/extras/tests/__init__.py
create mode 100644 third_party/python-extras/extras/tests/test_extras.py
create mode 100644 third_party/python-extras/setup.cfg
create mode 100755 third_party/python-extras/setup.py
diff --git a/lib/extras/.gitignore b/lib/extras/.gitignore
deleted file mode 100644
index cfc114c..0000000
--- a/lib/extras/.gitignore
+++ /dev/null
@@ -1,35 +0,0 @@
-*.py[co]
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
-.installed.cfg
-MANIFEST
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-
-#Translations
-*.mo
-
-#Mr Developer
-.mr.developer.cfg
-
-# editors
-*.swp
-*~
-
-# Testrepository
-.testrepository
diff --git a/lib/extras/.testr.conf b/lib/extras/.testr.conf
deleted file mode 100644
index 8a65628..0000000
--- a/lib/extras/.testr.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-test_command=${PYTHON:-python} -m subunit.run discover . $LISTOPT $IDOPTION
-test_id_option=--load-list $IDFILE
-test_list_option=--list
diff --git a/lib/extras/LICENSE b/lib/extras/LICENSE
deleted file mode 100644
index 4dfca45..0000000
--- a/lib/extras/LICENSE
+++ /dev/null
@@ -1,26 +0,0 @@
-Copyright (c) 2010-2012 the extras authors.
-
-The extras authors are:
- * Jonathan Lange
- * Martin Pool
- * Robert Collins
-
-and are collectively referred to as "extras developers".
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/lib/extras/MANIFEST.in b/lib/extras/MANIFEST.in
deleted file mode 100644
index da2696e..0000000
--- a/lib/extras/MANIFEST.in
+++ /dev/null
@@ -1,6 +0,0 @@
-include LICENSE
-include Makefile
-include MANIFEST.in
-include NEWS
-include README.rst
-include .gitignore
diff --git a/lib/extras/Makefile b/lib/extras/Makefile
deleted file mode 100644
index 270e8d1..0000000
--- a/lib/extras/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# See README.rst for copyright and licensing details.
-
-PYTHON=python
-SOURCES=$(shell find extras -name "*.py")
-
-check:
- PYTHONPATH=$(PWD) $(PYTHON) -m testtools.run extras.tests.test_suite
-
-TAGS: ${SOURCES}
- ctags -e -R extras/
-
-tags: ${SOURCES}
- ctags -R extras/
-
-clean:
- rm -f TAGS tags
- find extras -name "*.pyc" -exec rm '{}' \;
-
-### Documentation ###
-
-apidocs:
- # pydoctor emits deprecation warnings under Ubuntu 10.10 LTS
- PYTHONWARNINGS='ignore::DeprecationWarning' \
- pydoctor --make-html --add-package extras \
- --docformat=restructuredtext --project-name=extras \
- --project-url=https://launchpad.net/extras
-
-
-.PHONY: apidocs
-.PHONY: check clean
diff --git a/lib/extras/NEWS b/lib/extras/NEWS
deleted file mode 100644
index 60713b8..0000000
--- a/lib/extras/NEWS
+++ /dev/null
@@ -1,27 +0,0 @@
-extras NEWS
-+++++++++++
-
-Changes and improvements to extras_, grouped by release.
-
-NEXT
-~~~~
-
-0.0.3
-~~~~~
-
-* Extras setup.py would break on older testtools releases, which could break
- installs of newer testtools due to extras then failing to install.
- (Robert Collins)
-
-0.0.2
-~~~~~
-
-* Fix Makefile to not have cruft leftover from testtools.
-
-0.0.1
-~~~~~
-
-* Initial extraction from testtools.
-
-
-.. _extras: http://pypi.python.org/pypi/extras
diff --git a/lib/extras/README.rst b/lib/extras/README.rst
deleted file mode 100644
index 7d3f10b..0000000
--- a/lib/extras/README.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-======
-extras
-======
-
-extras is a set of extensions to the Python standard library, originally
-written to make the code within testtools cleaner, but now split out for
-general use outside of a testing context.
-
-
-Documentation
--------------
-
-pydoc extras is your friend. extras currently contains the following functions:
-
-* try_import
-
-* try_imports
-
-* safe_hasattr
-
-Which do what their name suggests.
-
-
-Licensing
----------
-
-This project is distributed under the MIT license and copyright is owned by
-the extras authors. See LICENSE for details.
-
-
-Required Dependencies
----------------------
-
- * Python 2.6+ or 3.0+
-
-
-Bug reports and patches
------------------------
-
-Please report bugs using github issues at <https://github.com/testing-cabal/extras>.
-Patches can also be submitted via github. You can mail the authors directly
-via the mailing list testtools-dev at lists.launchpad.net. (Note that Launchpad
-discards email from unknown addresses - be sure to sign up for a Launchpad
-account before mailing the list, or your mail will be silently discarded).
-
-
-History
--------
-
-extras used to be testtools.helpers, and was factored out when folk wanted to
-use it separately.
-
-
-Thanks
-------
-
- * Martin Pool
diff --git a/lib/extras/extras/__init__.py b/lib/extras/extras/__init__.py
deleted file mode 100644
index 5f16625..0000000
--- a/lib/extras/extras/__init__.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
-
-"""Extensions to the Python standard library."""
-
-import sys
-
-__all__ = [
- 'safe_hasattr',
- 'try_import',
- 'try_imports',
- ]
-
-# same format as sys.version_info: "A tuple containing the five components of
-# the version number: major, minor, micro, releaselevel, and serial. All
-# values except releaselevel are integers; the release level is 'alpha',
-# 'beta', 'candidate', or 'final'. The version_info value corresponding to the
-# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a
-# releaselevel of 'dev' for unreleased under-development code.
-#
-# If the releaselevel is 'alpha' then the major/minor/micro components are not
-# established at this point, and setup.py will use a version of next-$(revno).
-# If the releaselevel is 'final', then the tarball will be major.minor.micro.
-# Otherwise it is major.minor.micro~$(revno).
-
-__version__ = (0, 0, 3, 'final', 0)
-
-
-def try_import(name, alternative=None, error_callback=None):
- """Attempt to import ``name``. If it fails, return ``alternative``.
-
- When supporting multiple versions of Python or optional dependencies, it
- is useful to be able to try to import a module.
-
- :param name: The name of the object to import, e.g. ``os.path`` or
- ``os.path.join``.
- :param alternative: The value to return if no module can be imported.
- Defaults to None.
- :param error_callback: If non-None, a callable that is passed the ImportError
- when the module cannot be loaded.
- """
- module_segments = name.split('.')
- last_error = None
- while module_segments:
- module_name = '.'.join(module_segments)
- try:
- module = __import__(module_name)
- except ImportError:
- last_error = sys.exc_info()[1]
- module_segments.pop()
- continue
- else:
- break
- else:
- if last_error is not None and error_callback is not None:
- error_callback(last_error)
- return alternative
- nonexistent = object()
- for segment in name.split('.')[1:]:
- module = getattr(module, segment, nonexistent)
- if module is nonexistent:
- if last_error is not None and error_callback is not None:
- error_callback(last_error)
- return alternative
- return module
-
-
-_RAISE_EXCEPTION = object()
-def try_imports(module_names, alternative=_RAISE_EXCEPTION, error_callback=None):
- """Attempt to import modules.
-
- Tries to import the first module in ``module_names``. If it can be
- imported, we return it. If not, we go on to the second module and try
- that. The process continues until we run out of modules to try. If none
- of the modules can be imported, either raise an exception or return the
- provided ``alternative`` value.
-
- :param module_names: A sequence of module names to try to import.
- :param alternative: The value to return if no module can be imported.
- If unspecified, we raise an ImportError.
- :param error_callback: If None, called with the ImportError for *each*
- module that fails to load.
- :raises ImportError: If none of the modules can be imported and no
- alternative value was specified.
- """
- module_names = list(module_names)
- for module_name in module_names:
- module = try_import(module_name, error_callback=error_callback)
- if module:
- return module
- if alternative is _RAISE_EXCEPTION:
- raise ImportError(
- "Could not import any of: %s" % ', '.join(module_names))
- return alternative
-
-
-def safe_hasattr(obj, attr, _marker=object()):
- """Does 'obj' have an attribute 'attr'?
-
- Use this rather than built-in hasattr, as the built-in swallows exceptions
- in some versions of Python and behaves unpredictably with respect to
- properties.
- """
- return getattr(obj, attr, _marker) is not _marker
diff --git a/lib/extras/extras/tests/__init__.py b/lib/extras/extras/tests/__init__.py
deleted file mode 100644
index e0d7d4a..0000000
--- a/lib/extras/extras/tests/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
-
-"""Tests for extras."""
-
-from unittest import TestSuite, TestLoader
-
-
-def test_suite():
- from extras.tests import (
- test_extras,
- )
- modules = [
- test_extras,
- ]
- loader = TestLoader()
- suites = map(loader.loadTestsFromModule, modules)
- return TestSuite(suites)
diff --git a/lib/extras/extras/tests/test_extras.py b/lib/extras/extras/tests/test_extras.py
deleted file mode 100644
index 33dc87c..0000000
--- a/lib/extras/extras/tests/test_extras.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
-
-from testtools import TestCase
-from testtools.matchers import (
- Equals,
- Is,
- Not,
- )
-
-from extras import (
- safe_hasattr,
- try_import,
- try_imports,
- )
-
-def check_error_callback(test, function, arg, expected_error_count,
- expect_result):
- """General test template for error_callback argument.
-
- :param test: Test case instance.
- :param function: Either try_import or try_imports.
- :param arg: Name or names to import.
- :param expected_error_count: Expected number of calls to the callback.
- :param expect_result: Boolean for whether a module should
- ultimately be returned or not.
- """
- cb_calls = []
- def cb(e):
- test.assertIsInstance(e, ImportError)
- cb_calls.append(e)
- try:
- result = function(arg, error_callback=cb)
- except ImportError:
- test.assertFalse(expect_result)
- else:
- if expect_result:
- test.assertThat(result, Not(Is(None)))
- else:
- test.assertThat(result, Is(None))
- test.assertEquals(len(cb_calls), expected_error_count)
-
-
-class TestSafeHasattr(TestCase):
-
- def test_attribute_not_there(self):
- class Foo(object):
- pass
- self.assertEqual(False, safe_hasattr(Foo(), 'anything'))
-
- def test_attribute_there(self):
- class Foo(object):
- pass
- foo = Foo()
- foo.attribute = None
- self.assertEqual(True, safe_hasattr(foo, 'attribute'))
-
- def test_property_there(self):
- class Foo(object):
- @property
- def attribute(self):
- return None
- foo = Foo()
- self.assertEqual(True, safe_hasattr(foo, 'attribute'))
-
- def test_property_raises(self):
- class Foo(object):
- @property
- def attribute(self):
- 1/0
- foo = Foo()
- self.assertRaises(ZeroDivisionError, safe_hasattr, foo, 'attribute')
-
-
-class TestTryImport(TestCase):
-
- def test_doesnt_exist(self):
- # try_import('thing', foo) returns foo if 'thing' doesn't exist.
- marker = object()
- result = try_import('doesntexist', marker)
- self.assertThat(result, Is(marker))
-
- def test_None_is_default_alternative(self):
- # try_import('thing') returns None if 'thing' doesn't exist.
- result = try_import('doesntexist')
- self.assertThat(result, Is(None))
-
- def test_existing_module(self):
- # try_import('thing', foo) imports 'thing' and returns it if it's a
- # module that exists.
- result = try_import('os', object())
- import os
- self.assertThat(result, Is(os))
-
- def test_existing_submodule(self):
- # try_import('thing.another', foo) imports 'thing' and returns it if
- # it's a module that exists.
- result = try_import('os.path', object())
- import os
- self.assertThat(result, Is(os.path))
-
- def test_nonexistent_submodule(self):
- # try_import('thing.another', foo) imports 'thing' and returns foo if
- # 'another' doesn't exist.
- marker = object()
- result = try_import('os.doesntexist', marker)
- self.assertThat(result, Is(marker))
-
- def test_object_from_module(self):
- # try_import('thing.object') imports 'thing' and returns
- # 'thing.object' if 'thing' is a module and 'object' is not.
- result = try_import('os.path.join')
- import os
- self.assertThat(result, Is(os.path.join))
-
- def test_error_callback(self):
- # the error callback is called on failures.
- check_error_callback(self, try_import, 'doesntexist', 1, False)
-
- def test_error_callback_missing_module_member(self):
- # the error callback is called on failures to find an object
- # inside an existing module.
- check_error_callback(self, try_import, 'os.nonexistent', 1, False)
-
- def test_error_callback_not_on_success(self):
- # the error callback is not called on success.
- check_error_callback(self, try_import, 'os.path', 0, True)
-
-
-class TestTryImports(TestCase):
-
- def test_doesnt_exist(self):
- # try_imports('thing', foo) returns foo if 'thing' doesn't exist.
- marker = object()
- result = try_imports(['doesntexist'], marker)
- self.assertThat(result, Is(marker))
-
- def test_fallback(self):
- result = try_imports(['doesntexist', 'os'])
- import os
- self.assertThat(result, Is(os))
-
- def test_None_is_default_alternative(self):
- # try_imports('thing') returns None if 'thing' doesn't exist.
- e = self.assertRaises(
- ImportError, try_imports, ['doesntexist', 'noreally'])
- self.assertThat(
- str(e),
- Equals("Could not import any of: doesntexist, noreally"))
-
- def test_existing_module(self):
- # try_imports('thing', foo) imports 'thing' and returns it if it's a
- # module that exists.
- result = try_imports(['os'], object())
- import os
- self.assertThat(result, Is(os))
-
- def test_existing_submodule(self):
- # try_imports('thing.another', foo) imports 'thing' and returns it if
- # it's a module that exists.
- result = try_imports(['os.path'], object())
- import os
- self.assertThat(result, Is(os.path))
-
- def test_nonexistent_submodule(self):
- # try_imports('thing.another', foo) imports 'thing' and returns foo if
- # 'another' doesn't exist.
- marker = object()
- result = try_imports(['os.doesntexist'], marker)
- self.assertThat(result, Is(marker))
-
- def test_fallback_submodule(self):
- result = try_imports(['os.doesntexist', 'os.path'])
- import os
- self.assertThat(result, Is(os.path))
-
- def test_error_callback(self):
- # One error for every class that doesn't exist.
- check_error_callback(self, try_imports,
- ['os.doesntexist', 'os.notthiseither'],
- 2, False)
- check_error_callback(self, try_imports,
- ['os.doesntexist', 'os.notthiseither', 'os'],
- 2, True)
- check_error_callback(self, try_imports,
- ['os.path'],
- 0, True)
diff --git a/lib/extras/setup.cfg b/lib/extras/setup.cfg
deleted file mode 100644
index c319dc7..0000000
--- a/lib/extras/setup.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-[test]
-test_module = extras.tests
-buffer=1
-catch=1
diff --git a/lib/extras/setup.py b/lib/extras/setup.py
deleted file mode 100755
index 56612d0..0000000
--- a/lib/extras/setup.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-"""Distutils installer for extras."""
-
-from setuptools import setup
-import os.path
-
-import extras
-testtools_cmd = extras.try_import('testtools.TestCommand')
-
-
-def get_version():
- """Return the version of extras that we are building."""
- version = '.'.join(
- str(component) for component in extras.__version__[0:3])
- return version
-
-
-def get_long_description():
- readme_path = os.path.join(
- os.path.dirname(__file__), 'README.rst')
- return open(readme_path).read()
-
-
-cmdclass = {}
-
-if testtools_cmd is not None:
- cmdclass['test'] = testtools_cmd
-
-
-setup(name='extras',
- author='Testing cabal',
- author_email='testtools-dev at lists.launchpad.net',
- url='https://github.com/testing-cabal/extras',
- description=('Useful extra bits for Python - things that shold be '
- 'in the standard library'),
- long_description=get_long_description(),
- version=get_version(),
- classifiers=[
- "Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- ],
- packages=[
- 'extras',
- 'extras.tests',
- ],
- cmdclass=cmdclass)
diff --git a/lib/update-external.sh b/lib/update-external.sh
index 6327d2c..61bcac3 100755
--- a/lib/update-external.sh
+++ b/lib/update-external.sh
@@ -39,7 +39,7 @@ rsync --exclude=wscript -avz --delete "$WORKDIR/zlib/" "$THIRD_PARTY_DIR/zlib/"
echo "Updating extra..."
git clone git://github.com/testing-cabal/extras "$WORKDIR/extras"
rm -rf "$WORKDIR/extras/.git"
-rsync -avz --delete "$WORKDIR/extras/" "$LIBDIR/extras/"
+rsync -avz --delete "$WORKDIR/extras/" "$THIRD_PARTY_DIR/python-extras/"
echo "Updating mimeparse..."
svn co http://mimeparse.googlecode.com/svn/trunk/ "$WORKDIR/mimeparse"
diff --git a/lib/wscript_build b/lib/wscript_build
index 002074b..a3f304c 100644
--- a/lib/wscript_build
+++ b/lib/wscript_build
@@ -6,7 +6,6 @@ import os, Options
external_libs = {
"subunit": "subunit/python/subunit",
"testtools": "testtools/testtools",
- "extras": "extras/extras",
}
list = []
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index 5d1aba7..d49bcd8 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -351,7 +351,7 @@ def ensure_third_party_module(modulename, location, check=lambda mod: True):
:return: The module object
"""
try:
- __import__(modulename)
+ mod = __import__(modulename)
except ImportError:
mod = import_bundled_package(modulename, location,
source_tree_container="third_party",
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 8e662ed..667f548 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -26,8 +26,8 @@ from samba.samdb import SamDB
import subprocess
import tempfile
-samba.ensure_external_module("mimeparse", "mimeparse")
-samba.ensure_external_module("extras", "extras")
+samba.ensure_third_party_module("mimeparse", "mimeparse")
+samba.ensure_third_party_module("extras", "extras")
samba.ensure_external_module("testtools", "testtools")
# Other modules import these two classes from here, for convenience:
diff --git a/selftest/selftesthelpers.py b/selftest/selftesthelpers.py
index c88424f..2c6f87f 100644
--- a/selftest/selftesthelpers.py
+++ b/selftest/selftesthelpers.py
@@ -68,8 +68,8 @@ else:
python = os.getenv("PYTHON", "python")
# Set a default value, overridden if we find a working one on the system
-tap2subunit = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/lib/extras:%s/third_party/mimeparse %s %s/lib/subunit/filters/tap2subunit" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir())
-subunit2to1 = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/lib/extras:%s/third_party/mimeparse %s %s/lib/subunit/filters/subunit-2to1" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir())
+tap2subunit = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/third_party/python-extras:%s/third_party/mimeparse %s %s/lib/subunit/filters/tap2subunit" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir())
+subunit2to1 = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/third_party/python-extras:%s/third_party/mimeparse %s %s/lib/subunit/filters/subunit-2to1" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir())
tap2subunit_version = 2
sub = subprocess.Popen("tap2subunit", stdin=subprocess.PIPE,
@@ -186,7 +186,7 @@ def planpythontestsuite(env, module, name=None, extra_path=[]):
pypath.extend([
"%s/lib/subunit/python" % srcdir(),
"%s/lib/testtools" % srcdir(),
- "%s/lib/extras" % srcdir(),
+ "%s/third_party/python-extras" % srcdir(),
"%s/third_party/mimeparse" % srcdir()])
args = [python, "-m", "subunit.run", "$LISTOPT", "$LOADLIST", module]
if pypath:
diff --git a/selftest/subunithelper.py b/selftest/subunithelper.py
index 73f756c..dddb29b 100644
--- a/selftest/subunithelper.py
+++ b/selftest/subunithelper.py
@@ -19,7 +19,7 @@ __all__ = ['parse_results']
import samba
samba.ensure_third_party_module("mimeparse", "mimeparse")
-samba.ensure_external_module("extras", "extras")
+samba.ensure_third_party_module("extras", "python-extras")
samba.ensure_external_module("testtools", "testtools")
def check_subunit(mod):
try:
diff --git a/third_party/python-extras/.gitignore b/third_party/python-extras/.gitignore
new file mode 100644
index 0000000..cfc114c
--- /dev/null
+++ b/third_party/python-extras/.gitignore
@@ -0,0 +1,35 @@
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+MANIFEST
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# editors
+*.swp
+*~
+
+# Testrepository
+.testrepository
diff --git a/third_party/python-extras/.testr.conf b/third_party/python-extras/.testr.conf
new file mode 100644
index 0000000..8a65628
--- /dev/null
+++ b/third_party/python-extras/.testr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_command=${PYTHON:-python} -m subunit.run discover . $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list
diff --git a/third_party/python-extras/LICENSE b/third_party/python-extras/LICENSE
new file mode 100644
index 0000000..4dfca45
--- /dev/null
+++ b/third_party/python-extras/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2010-2012 the extras authors.
+
+The extras authors are:
+ * Jonathan Lange
+ * Martin Pool
+ * Robert Collins
+
+and are collectively referred to as "extras developers".
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/python-extras/MANIFEST.in b/third_party/python-extras/MANIFEST.in
new file mode 100644
index 0000000..da2696e
--- /dev/null
+++ b/third_party/python-extras/MANIFEST.in
@@ -0,0 +1,6 @@
+include LICENSE
+include Makefile
+include MANIFEST.in
+include NEWS
+include README.rst
+include .gitignore
diff --git a/third_party/python-extras/Makefile b/third_party/python-extras/Makefile
new file mode 100644
index 0000000..270e8d1
--- /dev/null
+++ b/third_party/python-extras/Makefile
@@ -0,0 +1,30 @@
+# See README.rst for copyright and licensing details.
+
+PYTHON=python
+SOURCES=$(shell find extras -name "*.py")
+
+check:
+ PYTHONPATH=$(PWD) $(PYTHON) -m testtools.run extras.tests.test_suite
+
+TAGS: ${SOURCES}
+ ctags -e -R extras/
+
+tags: ${SOURCES}
+ ctags -R extras/
+
+clean:
+ rm -f TAGS tags
+ find extras -name "*.pyc" -exec rm '{}' \;
+
+### Documentation ###
+
+apidocs:
+ # pydoctor emits deprecation warnings under Ubuntu 10.10 LTS
+ PYTHONWARNINGS='ignore::DeprecationWarning' \
+ pydoctor --make-html --add-package extras \
+ --docformat=restructuredtext --project-name=extras \
+ --project-url=https://launchpad.net/extras
+
+
+.PHONY: apidocs
+.PHONY: check clean
diff --git a/third_party/python-extras/NEWS b/third_party/python-extras/NEWS
new file mode 100644
index 0000000..60713b8
--- /dev/null
+++ b/third_party/python-extras/NEWS
@@ -0,0 +1,27 @@
+extras NEWS
++++++++++++
+
+Changes and improvements to extras_, grouped by release.
+
+NEXT
+~~~~
+
+0.0.3
+~~~~~
+
+* Extras setup.py would break on older testtools releases, which could break
+ installs of newer testtools due to extras then failing to install.
+ (Robert Collins)
+
+0.0.2
+~~~~~
+
+* Fix Makefile to not have cruft leftover from testtools.
+
+0.0.1
+~~~~~
+
+* Initial extraction from testtools.
+
+
+.. _extras: http://pypi.python.org/pypi/extras
diff --git a/third_party/python-extras/README.rst b/third_party/python-extras/README.rst
new file mode 100644
index 0000000..7d3f10b
--- /dev/null
+++ b/third_party/python-extras/README.rst
@@ -0,0 +1,57 @@
+======
+extras
+======
+
+extras is a set of extensions to the Python standard library, originally
+written to make the code within testtools cleaner, but now split out for
+general use outside of a testing context.
+
+
+Documentation
+-------------
+
+pydoc extras is your friend. extras currently contains the following functions:
+
+* try_import
+
+* try_imports
+
+* safe_hasattr
+
+Which do what their name suggests.
+
+
+Licensing
+---------
+
+This project is distributed under the MIT license and copyright is owned by
+the extras authors. See LICENSE for details.
+
+
+Required Dependencies
+---------------------
+
+ * Python 2.6+ or 3.0+
+
+
+Bug reports and patches
+-----------------------
+
+Please report bugs using github issues at <https://github.com/testing-cabal/extras>.
+Patches can also be submitted via github. You can mail the authors directly
+via the mailing list testtools-dev at lists.launchpad.net. (Note that Launchpad
+discards email from unknown addresses - be sure to sign up for a Launchpad
+account before mailing the list, or your mail will be silently discarded).
+
+
+History
+-------
+
+extras used to be testtools.helpers, and was factored out when folk wanted to
+use it separately.
+
+
+Thanks
+------
+
+ * Martin Pool
diff --git a/third_party/python-extras/extras/__init__.py b/third_party/python-extras/extras/__init__.py
new file mode 100644
index 0000000..5f16625
--- /dev/null
+++ b/third_party/python-extras/extras/__init__.py
@@ -0,0 +1,103 @@
+# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
+
+"""Extensions to the Python standard library."""
+
+import sys
+
+__all__ = [
+ 'safe_hasattr',
+ 'try_import',
+ 'try_imports',
+ ]
+
+# same format as sys.version_info: "A tuple containing the five components of
+# the version number: major, minor, micro, releaselevel, and serial. All
+# values except releaselevel are integers; the release level is 'alpha',
+# 'beta', 'candidate', or 'final'. The version_info value corresponding to the
+# Python version 2.0 is (2, 0, 0, 'final', 0)." Additionally we use a
+# releaselevel of 'dev' for unreleased under-development code.
+#
+# If the releaselevel is 'alpha' then the major/minor/micro components are not
+# established at this point, and setup.py will use a version of next-$(revno).
+# If the releaselevel is 'final', then the tarball will be major.minor.micro.
+# Otherwise it is major.minor.micro~$(revno).
+
+__version__ = (0, 0, 3, 'final', 0)
+
+
+def try_import(name, alternative=None, error_callback=None):
+ """Attempt to import ``name``. If it fails, return ``alternative``.
+
+ When supporting multiple versions of Python or optional dependencies, it
+ is useful to be able to try to import a module.
+
+ :param name: The name of the object to import, e.g. ``os.path`` or
+ ``os.path.join``.
+ :param alternative: The value to return if no module can be imported.
+ Defaults to None.
+ :param error_callback: If non-None, a callable that is passed the ImportError
+ when the module cannot be loaded.
+ """
+ module_segments = name.split('.')
+ last_error = None
+ while module_segments:
+ module_name = '.'.join(module_segments)
+ try:
+ module = __import__(module_name)
+ except ImportError:
+ last_error = sys.exc_info()[1]
+ module_segments.pop()
+ continue
+ else:
+ break
+ else:
+ if last_error is not None and error_callback is not None:
+ error_callback(last_error)
+ return alternative
+ nonexistent = object()
+ for segment in name.split('.')[1:]:
+ module = getattr(module, segment, nonexistent)
+ if module is nonexistent:
+ if last_error is not None and error_callback is not None:
+ error_callback(last_error)
+ return alternative
+ return module
+
+
+_RAISE_EXCEPTION = object()
+def try_imports(module_names, alternative=_RAISE_EXCEPTION, error_callback=None):
+ """Attempt to import modules.
+
+ Tries to import the first module in ``module_names``. If it can be
+ imported, we return it. If not, we go on to the second module and try
+ that. The process continues until we run out of modules to try. If none
+ of the modules can be imported, either raise an exception or return the
+ provided ``alternative`` value.
+
+ :param module_names: A sequence of module names to try to import.
+ :param alternative: The value to return if no module can be imported.
+ If unspecified, we raise an ImportError.
+ :param error_callback: If None, called with the ImportError for *each*
+ module that fails to load.
+ :raises ImportError: If none of the modules can be imported and no
+ alternative value was specified.
+ """
+ module_names = list(module_names)
+ for module_name in module_names:
+ module = try_import(module_name, error_callback=error_callback)
+ if module:
+ return module
+ if alternative is _RAISE_EXCEPTION:
+ raise ImportError(
+ "Could not import any of: %s" % ', '.join(module_names))
+ return alternative
+
+
+def safe_hasattr(obj, attr, _marker=object()):
+ """Does 'obj' have an attribute 'attr'?
+
+ Use this rather than built-in hasattr, as the built-in swallows exceptions
+ in some versions of Python and behaves unpredictably with respect to
+ properties.
+ """
+ return getattr(obj, attr, _marker) is not _marker
diff --git a/third_party/python-extras/extras/tests/__init__.py b/third_party/python-extras/extras/tests/__init__.py
new file mode 100644
index 0000000..e0d7d4a
--- /dev/null
+++ b/third_party/python-extras/extras/tests/__init__.py
@@ -0,0 +1,17 @@
+# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
+
+"""Tests for extras."""
+
+from unittest import TestSuite, TestLoader
+
+
+def test_suite():
+ from extras.tests import (
+ test_extras,
+ )
+ modules = [
+ test_extras,
+ ]
+ loader = TestLoader()
+ suites = map(loader.loadTestsFromModule, modules)
+ return TestSuite(suites)
diff --git a/third_party/python-extras/extras/tests/test_extras.py b/third_party/python-extras/extras/tests/test_extras.py
new file mode 100644
index 0000000..33dc87c
--- /dev/null
+++ b/third_party/python-extras/extras/tests/test_extras.py
@@ -0,0 +1,186 @@
+# Copyright (c) 2010-2012 extras developers. See LICENSE for details.
+
+from testtools import TestCase
+from testtools.matchers import (
+ Equals,
+ Is,
+ Not,
+ )
+
+from extras import (
+ safe_hasattr,
+ try_import,
+ try_imports,
+ )
+
+def check_error_callback(test, function, arg, expected_error_count,
+ expect_result):
+ """General test template for error_callback argument.
+
+ :param test: Test case instance.
+ :param function: Either try_import or try_imports.
+ :param arg: Name or names to import.
+ :param expected_error_count: Expected number of calls to the callback.
+ :param expect_result: Boolean for whether a module should
+ ultimately be returned or not.
+ """
+ cb_calls = []
+ def cb(e):
+ test.assertIsInstance(e, ImportError)
+ cb_calls.append(e)
+ try:
+ result = function(arg, error_callback=cb)
+ except ImportError:
+ test.assertFalse(expect_result)
+ else:
+ if expect_result:
+ test.assertThat(result, Not(Is(None)))
+ else:
+ test.assertThat(result, Is(None))
+ test.assertEquals(len(cb_calls), expected_error_count)
+
+
+class TestSafeHasattr(TestCase):
+
+ def test_attribute_not_there(self):
+ class Foo(object):
+ pass
+ self.assertEqual(False, safe_hasattr(Foo(), 'anything'))
+
+ def test_attribute_there(self):
+ class Foo(object):
+ pass
+ foo = Foo()
+ foo.attribute = None
+ self.assertEqual(True, safe_hasattr(foo, 'attribute'))
+
+ def test_property_there(self):
+ class Foo(object):
+ @property
+ def attribute(self):
+ return None
+ foo = Foo()
+ self.assertEqual(True, safe_hasattr(foo, 'attribute'))
+
+ def test_property_raises(self):
+ class Foo(object):
+ @property
+ def attribute(self):
+ 1/0
+ foo = Foo()
+ self.assertRaises(ZeroDivisionError, safe_hasattr, foo, 'attribute')
+
+
+class TestTryImport(TestCase):
+
+ def test_doesnt_exist(self):
+ # try_import('thing', foo) returns foo if 'thing' doesn't exist.
+ marker = object()
+ result = try_import('doesntexist', marker)
+ self.assertThat(result, Is(marker))
+
+ def test_None_is_default_alternative(self):
+ # try_import('thing') returns None if 'thing' doesn't exist.
+ result = try_import('doesntexist')
+ self.assertThat(result, Is(None))
+
+ def test_existing_module(self):
+ # try_import('thing', foo) imports 'thing' and returns it if it's a
+ # module that exists.
+ result = try_import('os', object())
+ import os
+ self.assertThat(result, Is(os))
+
+ def test_existing_submodule(self):
+ # try_import('thing.another', foo) imports 'thing' and returns it if
+ # it's a module that exists.
+ result = try_import('os.path', object())
+ import os
+ self.assertThat(result, Is(os.path))
+
+ def test_nonexistent_submodule(self):
+ # try_import('thing.another', foo) imports 'thing' and returns foo if
+ # 'another' doesn't exist.
+ marker = object()
+ result = try_import('os.doesntexist', marker)
+ self.assertThat(result, Is(marker))
+
+ def test_object_from_module(self):
+ # try_import('thing.object') imports 'thing' and returns
+ # 'thing.object' if 'thing' is a module and 'object' is not.
+ result = try_import('os.path.join')
+ import os
+ self.assertThat(result, Is(os.path.join))
+
+ def test_error_callback(self):
+ # the error callback is called on failures.
+ check_error_callback(self, try_import, 'doesntexist', 1, False)
+
+ def test_error_callback_missing_module_member(self):
+ # the error callback is called on failures to find an object
+ # inside an existing module.
+ check_error_callback(self, try_import, 'os.nonexistent', 1, False)
+
+ def test_error_callback_not_on_success(self):
+ # the error callback is not called on success.
+ check_error_callback(self, try_import, 'os.path', 0, True)
+
+
+class TestTryImports(TestCase):
+
+ def test_doesnt_exist(self):
+ # try_imports('thing', foo) returns foo if 'thing' doesn't exist.
+ marker = object()
+ result = try_imports(['doesntexist'], marker)
+ self.assertThat(result, Is(marker))
+
+ def test_fallback(self):
+ result = try_imports(['doesntexist', 'os'])
+ import os
+ self.assertThat(result, Is(os))
+
+ def test_None_is_default_alternative(self):
+ # try_imports('thing') returns None if 'thing' doesn't exist.
+ e = self.assertRaises(
+ ImportError, try_imports, ['doesntexist', 'noreally'])
+ self.assertThat(
+ str(e),
+ Equals("Could not import any of: doesntexist, noreally"))
+
+ def test_existing_module(self):
+ # try_imports('thing', foo) imports 'thing' and returns it if it's a
+ # module that exists.
+ result = try_imports(['os'], object())
+ import os
+ self.assertThat(result, Is(os))
+
+ def test_existing_submodule(self):
+ # try_imports('thing.another', foo) imports 'thing' and returns it if
+ # it's a module that exists.
+ result = try_imports(['os.path'], object())
+ import os
+ self.assertThat(result, Is(os.path))
+
+ def test_nonexistent_submodule(self):
+ # try_imports('thing.another', foo) imports 'thing' and returns foo if
+ # 'another' doesn't exist.
+ marker = object()
+ result = try_imports(['os.doesntexist'], marker)
+ self.assertThat(result, Is(marker))
+
+ def test_fallback_submodule(self):
+ result = try_imports(['os.doesntexist', 'os.path'])
+ import os
+ self.assertThat(result, Is(os.path))
+
+ def test_error_callback(self):
+ # One error for every class that doesn't exist.
+ check_error_callback(self, try_imports,
+ ['os.doesntexist', 'os.notthiseither'],
+ 2, False)
+ check_error_callback(self, try_imports,
+ ['os.doesntexist', 'os.notthiseither', 'os'],
+ 2, True)
+ check_error_callback(self, try_imports,
+ ['os.path'],
+ 0, True)
diff --git a/third_party/python-extras/setup.cfg b/third_party/python-extras/setup.cfg
new file mode 100644
index 0000000..c319dc7
--- /dev/null
+++ b/third_party/python-extras/setup.cfg
@@ -0,0 +1,4 @@
+[test]
+test_module = extras.tests
+buffer=1
+catch=1
diff --git a/third_party/python-extras/setup.py b/third_party/python-extras/setup.py
new file mode 100755
index 0000000..56612d0
--- /dev/null
+++ b/third_party/python-extras/setup.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+"""Distutils installer for extras."""
+
+from setuptools import setup
+import os.path
+
+import extras
+testtools_cmd = extras.try_import('testtools.TestCommand')
+
+
+def get_version():
+ """Return the version of extras that we are building."""
+ version = '.'.join(
+ str(component) for component in extras.__version__[0:3])
+ return version
+
+
+def get_long_description():
+ readme_path = os.path.join(
+ os.path.dirname(__file__), 'README.rst')
+ return open(readme_path).read()
+
+
+cmdclass = {}
+
+if testtools_cmd is not None:
+ cmdclass['test'] = testtools_cmd
+
+
+setup(name='extras',
+ author='Testing cabal',
+ author_email='testtools-dev at lists.launchpad.net',
+ url='https://github.com/testing-cabal/extras',
+ description=('Useful extra bits for Python - things that shold be '
+ 'in the standard library'),
+ long_description=get_long_description(),
+ version=get_version(),
+ classifiers=[
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ ],
+ packages=[
+ 'extras',
+ 'extras.tests',
+ ],
+ cmdclass=cmdclass)
diff --git a/third_party/wscript_build b/third_party/wscript_build
index 5781ee0..a86732e 100644
--- a/third_party/wscript_build
+++ b/third_party/wscript_build
@@ -6,6 +6,7 @@ import os
external_libs = {
"dns.resolver": "dnspython/dns",
"mimeparse": "mimeparse",
+ "extras": "python-extras/extras",
}
list = []
--
2.1.3
More information about the samba-technical
mailing list