You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2015/06/05 15:58:34 UTC

qpid-proton git commit: PROTON-895: Rely on python to build downloaded tarball

Repository: qpid-proton
Updated Branches:
  refs/heads/master caaabb7bd -> 3db3cf178


PROTON-895: Rely on python to build downloaded tarball

Instead of using cmake to build the downloaded tarball, rely on python
for building and installing the library. This process is not only
cleaner but also plays nicer with the environment we're trying to give
support to.

In addition to the above, this plays nicer with the user and removes a
requirement for having the library installed. Note that the built
library will no longer overwrite system libraries but it'll be placed
along to the python bindings we're building.

(cherry picked from commit f2e97708a9c0da049bbc5089909fc31ab092edf8)


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/3db3cf17
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/3db3cf17
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/3db3cf17

Branch: refs/heads/master
Commit: 3db3cf1783f1b91211028842389801316d10b8ba
Parents: caaabb7
Author: Flavio Percoco <fl...@gmail.com>
Authored: Fri May 29 15:14:48 2015 +0200
Committer: Ken Giusti <kg...@apache.org>
Committed: Fri Jun 5 09:02:38 2015 -0400

----------------------------------------------------------------------
 proton-c/CMakeLists.txt                       |  26 +-
 proton-c/bindings/python/setup.py             | 286 ++++++++++++++-------
 proton-c/bindings/python/setuputils/bundle.py |   4 +-
 proton-c/bindings/python/setuputils/log.py    |   2 +-
 proton-c/bindings/python/setuputils/misc.py   |  88 +------
 proton-c/bindings/python/tox.ini              |  36 +++
 tests/python/proton_tests/common.py           |  12 +-
 7 files changed, 276 insertions(+), 178 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 1347f16..b534e86 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -501,6 +501,7 @@ endif (CMAKE_SYSTEM_NAME STREQUAL Windows)
 
 # python test: tests/python/proton-test
 if (BUILD_PYTHON)
+  set (pn_c_root "${CMAKE_BINARY_DIR}/proton")
   set (py_root "${pn_test_root}/python")
   set (py_src "${CMAKE_CURRENT_SOURCE_DIR}/bindings/python")
   set (py_bin "${CMAKE_CURRENT_BINARY_DIR}/bindings/python")
@@ -515,7 +516,7 @@ if (BUILD_PYTHON)
   to_native_path ("${py_pythonpath}" py_pythonpath)
   add_test (NAME python-test
             COMMAND ${env_py}
-                    "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" ${VALGRIND_ENV}
+	             "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" "PKG_CONFIG_PATH=${pn_c_root}" ${VALGRIND_ENV}
                     ${PYTHON_EXECUTABLE} "${py_root}/proton-test")
   set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: .* 0 failed")
   else (NOT OLD_ADD_TEST_COMMAND)
@@ -524,11 +525,32 @@ if (BUILD_PYTHON)
   to_native_path ("${py_pythonpath}" py_pythonpath)
   add_test (python-test
             ${env_py}
-            "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" ${VALGRIND_ENV}
+	    "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" "PKG_CONFIG_PATH=${pn_c_root}" ${VALGRIND_ENV}
             ${PYTHON_EXECUTABLE} "${py_root}/proton-test")
   set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: .* 0 failed")
   endif (NOT OLD_ADD_TEST_COMMAND)
 
+  # Eventually, we'll get rid of this check when other
+  # platforms will be supported. Since `setup.py` will skip
+  # the build for non linux plaforms, it doesn't make sense
+  # to try to run them.
+  if (CMAKE_SYSTEM_NAME STREQUAL Linux)
+     find_program(TOX_CMD "tox")
+     if (TOX_CMD)
+         list (APPEND py_path "${Proton_BINARY_DIR}/tests/tools/apps/c")
+         to_native_path ("${py_path}" py_path)
+         to_native_path ("${py_pythonpath}" py_pythonpath)
+         add_test (NAME python-tox-test
+                   COMMAND ${env_py}
+		   "PATH=${py_path}" ${VALGRIND_ENV}
+                   tox
+		   WORKING_DIRECTORY ${py_src})
+         set_tests_properties(python-tox-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: .* 0 failed")
+     else (TOX_CMD)
+         message(STATUS "The tox tool is not available - skipping the python-tox-tests")
+     endif (TOX_CMD)
+  endif (CMAKE_SYSTEM_NAME STREQUAL Linux)
+
 endif (BUILD_PYTHON)
 
 find_program(RUBY_EXE "ruby")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/bindings/python/setup.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setup.py b/proton-c/bindings/python/setup.py
index 09fa76a..b255580 100755
--- a/proton-c/bindings/python/setup.py
+++ b/proton-c/bindings/python/setup.py
@@ -67,12 +67,14 @@ in the system. The rest of the comands and steps are done normally without any k
 of monkey patching.
 """
 
+import glob
 import os
 import subprocess
 import sys
 
 import distutils.spawn as ds_spawn
 import distutils.sysconfig as ds_sys
+from distutils.ccompiler import new_compiler, get_default_compiler
 from distutils.core import setup, Extension
 from distutils.command.build import build
 from distutils.command.build_ext import build_ext
@@ -82,102 +84,193 @@ from setuputils import log
 from setuputils import misc
 
 
-class CustomBuildOrder(build):
-    # NOTE(flaper87): The sole purpose of this class is to re-order
-    # the commands execution so that `build_ext` is executed *before*
-    # build_py. We need this to make sure `cproton.py` is generated
-    # before the python modules are collected. Otherwise, it won't
-    # be installed.
-    sub_commands = [
-        ('build_ext', build.has_ext_modules),
-        ('build_py', build.has_pure_modules),
-        ('build_clib', build.has_c_libraries),
-        ('build_scripts', build.has_scripts),
-    ]
-
-
-class CheckingBuildExt(build_ext):
-    """Subclass build_ext to build qpid-proton using `cmake`"""
-
-    def build_extensions(self):
-        self.check_extensions_list(self.extensions)
-
-        for ext in self.extensions:
-            self.build_extension(ext)
-
-    def build_cmake_proton(self, ext):
-        if not ds_spawn.find_executable('cmake'):
-            log.fatal("cmake needed for this script it work")
-
-        try:
-            ds_spawn.spawn(['cmake'] + ext.extra_compile_args + ext.sources)
-            ds_spawn.spawn(['make', 'install'])
-        except ds_spawn.DistutilsExecError:
-            msg = "Error while running cmake"
-            msg += "\nrun 'setup.py build --help' for build options"
-            log.fatal(msg)
-
-    def build_extension(self, ext):
-        if ext.name == 'cmake_cproton':
-            return self.build_cmake_proton(ext)
-
-        return build_ext.build_extension(self, ext)
-
-    def run(self):
-        # Discover qpid-proton in the system
-        self.distribution.run_command('configure')
-        build_ext.run(self)
-
-
 class Configure(build_ext):
     description = "Discover Qpid Proton version"
 
+    @property
+    def compiler_type(self):
+        compiler = self.compiler
+        if compiler is None:
+            return get_default_compiler()
+        elif isinstance(compiler, str):
+            return compiler
+        else:
+            return compiler.compiler_type
+
     def bundle_libqpid_proton_extension(self):
         base = self.get_finalized_command('build').build_base
+        build_include = os.path.join(base, 'include')
         install = self.get_finalized_command('install').install_base
-        bundledir = os.path.join(base, "bundled")
+        install_lib = self.get_finalized_command('install').install_lib
         ext_modules = self.distribution.ext_modules
 
         log.info("Using bundled libqpid-proton")
 
-        if not os.path.exists(bundledir):
-            os.makedirs(bundledir)
-
-        bundle.fetch_libqpid_proton(bundledir)
-
-        libqpid_proton_dir = os.path.join(bundledir, 'qpid-proton')
-
-        # NOTE(flaper87): Find prefix. We need to run make ourselves
+        if 'QPID_PROTON_SRC' not in os.environ:
+            bundledir = os.path.join(base, "bundled")
+            if not os.path.exists(bundledir):
+                os.makedirs(bundledir)
+            bundle.fetch_libqpid_proton(bundledir)
+            libqpid_proton_dir = os.path.abspath(os.path.join(bundledir, 'qpid-proton'))
+        else:
+            libqpid_proton_dir = os.path.abspath(os.environ['QPID_PROTON_SRC'])
+
+        log.debug("Using libqpid-proton src: %s" % libqpid_proton_dir)
+
+        proton_base = os.path.join(libqpid_proton_dir, 'proton-c')
+        proton_src = os.path.join(proton_base, 'src')
+        proton_include = os.path.join(proton_base, 'include')
+
+        if not os.path.exists(build_include):
+            os.makedirs(build_include)
+            os.mkdir(os.path.join(build_include, 'proton'))
+
+        # Generate `protocol.h` by calling the python
+        # script found in the source dir.
+        with open(os.path.join(build_include, 'protocol.h'), 'wb') as header:
+            subprocess.Popen([sys.executable, os.path.join(proton_src, 'protocol.h.py')],
+                              env={'PYTHONPATH': proton_base}, stdout=header)
+
+        # Generate `encodings.h` by calling the python
+        # script found in the source dir.
+        with open(os.path.join(build_include, 'encodings.h'), 'wb') as header:
+            subprocess.Popen([sys.executable,
+                              os.path.join(proton_src, 'codec', 'encodings.h.py')],
+                              env={'PYTHONPATH': proton_base}, stdout=header)
+
+        # Create a custom, temporary, version.h file mapping the
+        # major and minor versions from the downloaded tarbal. This version should
+        # match the ones in the bundle module
+        with open(os.path.join(build_include, 'proton', 'version.h'), "wb") as ver:
+            version_text = """
+#ifndef _PROTON_VERSION_H
+#define _PROTON_VERSION_H 1
+#define PN_VERSION_MAJOR %i
+#define PN_VERSION_MINOR %i
+#endif /* version.h */
+""" % bundle.min_qpid_proton
+            ver.write(version_text)
+
+        # Collect all the C files that need to be built.
+        # we could've used `glob(.., '*', '*.c')` but I preferred going
+        # with an explicit list of subdirs that we can control and expand
+        # depending on the version. Specifically, lets avoid adding things
+        # we don't need.
+        sources = []
+        libraries = ['uuid']
+
+        for subdir in ['object', 'framing', 'codec', 'dispatcher',
+                       'engine', 'events', 'transport',
+                       'message', 'reactor', 'messenger',
+                       'handlers', 'posix']:
+
+            sources.extend(glob.glob(os.path.join(proton_src, subdir, '*.c')))
+
+        sources.extend(filter(lambda x: not x.endswith('dump.c'),
+                       glob.iglob(os.path.join(proton_src, '*.c'))))
+
+        # Check whether openssl is installed by poking
+        # pkg-config for a minimum version 0. If it's installed, it should
+        # return True and we'll use it. Otherwise, we'll use the stub.
+        if misc.pkg_config_version(atleast='0', module='openssl'):
+            libraries += ['ssl', 'crypto']
+            sources.append(os.path.join(proton_src, 'ssl', 'openssl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'ssl', 'ssl_stub.c'))
+
+        cc = new_compiler(compiler=self.compiler_type)
+        cc.output_dir = self.build_temp
+
+        # Some systems need to link to
+        # `rt`. Check whether `clock_getttime` is around
+        # and if not, link on rt.
+        if not cc.has_function('clock_getttime'):
+            libraries.append('rt')
+
+        # 0.10 added an implementation for cyrus. Check
+        # if it is available before adding the implementation to the sources
+        # list. Eventually, `sasl.c` will be added and one of the existing
+        # implementations will be used.
+        if not cc.has_function('sasl_set_path', libraries=('sasl2')):
+            libraries.append('sasl2')
+            sources.append(os.path.join(proton_src, 'sasl', 'cyrus_sasl.c'))
+        else:
+            sources.append(os.path.join(proton_src, 'sasl', 'none_sasl.c'))
+
+        sources.append(os.path.join(proton_src, 'sasl', 'sasl.c'))
+
+        # Create an extension for the bundled qpid-proton
+        # library and let distutils do the build step for us.
+        # This is not the `swig` library... What's going to be built by this
+        # `Extension` is qpid-proton itself. For the swig library, pls, see the
+        # dependencies in the `setup` function call and how it's extended further
+        # down this method.
         libqpid_proton = Extension(
-            'cmake_cproton',
-            sources = [libqpid_proton_dir],
-
-            # NOTE(flaper87): Disable all bindings, set the prefix to whatever
-            # is in `distutils.sysconfig.PREFIX` and finally, disable testing
-            # as well. The python binding will be built by this script later
-            # on. Don't let cmake do it.
-            extra_compile_args = ['-DCMAKE_INSTALL_PREFIX:PATH=%s' % install,
-                                  '-DBUILD_PYTHON=False',
-                                  '-DBUILD_JAVA=False',
-                                  '-DBUILD_PERL=False',
-                                  '-DBUILD_RUBY=False',
-                                  '-DBUILD_PHP=False',
-                                  '-DBUILD_JAVASCRIPT=False',
-                                  '-DBUILD_TESTING=False',
-            ]
+            'libqpid-proton',
+
+            # List of `.c` files that will be compiled.
+            # `sources` is defined earlier on in this method and it's mostly
+            # filled dynamically except for a few cases where files are added
+            # depending on the presence of some libraries.
+            sources=sources,
+
+            # Libraries that need to be linked to should
+            # be added to this list. `libraries` is defined earlier on
+            # in this same method and it's filled depending on some
+            # conditions. You'll find comments on each of those.
+            libraries=libraries,
+
+            # Changes to this list should be rare.
+            # However, this is where new headers' dirs are added.
+            # This list translates to `-I....` flags.
+            include_dirs=[build_include, proton_src, proton_include],
+
+            # If you need to add a default flag, this is
+            # the place. All these compile arguments will be appended to
+            # the GCC command. This list of flags is not used during the
+            # linking phase.
+            extra_compile_args = [
+                '-std=gnu99',
+                '-Dqpid_proton_EXPORTS',
+                '-DUSE_ATOLL',
+                '-DUSE_CLOCK_GETTIME',
+                '-DUSE_STRERROR_R',
+                '-DUSE_UUID_GENERATE',
+            ],
+
+            # If you need to add flags to the linking phase
+            # this is the right place to do it. Just like the compile flags,
+            # this is a list of flags that will be appended to the link
+            # command.
+            extra_link_args = []
         )
 
-        # NOTE(flaper87): Register this new extension and make
+
+        # Extend the `swig` module `Extension` and add a few
+        # extra options. For instance, we'll add new library dirs where `swig`
+        # should look for headers and libraries. In addition to this, we'll
+        # also append a `runtime path` where the qpid-proton library for this
+        # swig extension should be looked up from whenever the proton bindings
+        # are imported. We need this because the library will live in the
+        # site-packages along with the proton bindings instead of being in the
+        # common places like `/usr/lib` or `/usr/local/lib`.
+        #
+        # This is not the place where you'd add "default" flags. If you need to
+        # add flags like `-thread` please read the `setup` function call at the
+        # bottom of this file and see the examples there.
+        _cproton = self.distribution.ext_modules[-1]
+        _cproton.library_dirs.append(self.build_lib)
+        _cproton.include_dirs.append(proton_include)
+        _cproton.include_dirs.append(os.path.join(proton_src, 'bindings', 'python'))
+
+        _cproton.swig_opts.append('-I%s' % build_include)
+        _cproton.swig_opts.append('-I%s' % proton_include)
+
+        _cproton.runtime_library_dirs.extend([install_lib])
+
+        # Register this new extension and make
         # sure it's built and installed *before* `_cproton`.
         self.distribution.ext_modules.insert(0, libqpid_proton)
-        return install
-
-    def set_cproton_settings(self, prefix=None):
-        settings = misc.settings_from_prefix(prefix)
-        ext = self.distribution.ext_modules[-1]
-
-        for k, v in settings.items():
-            setattr(ext, k, v)
 
     def check_qpid_proton_version(self):
         """check the qpid_proton version"""
@@ -186,20 +279,40 @@ class Configure(build_ext):
         return (misc.pkg_config_version(max_version=target_version) and
                 misc.pkg_config_version(atleast=bundle.min_qpid_proton_str))
 
-
     @property
     def bundle_proton(self):
+        """Bundled proton if the conditions below are met."""
         return sys.platform == 'linux2' and not self.check_qpid_proton_version()
 
     def run(self):
-        prefix = None
         if self.bundle_proton:
-            prefix = self.bundle_libqpid_proton_extension()
+            self.bundle_libqpid_proton_extension()
 
-        self.set_cproton_settings(prefix)
+
+class CustomBuildOrder(build):
+    # The sole purpose of this class is to re-order
+    # the commands execution so that `build_ext` is executed *before*
+    # build_py. We need this to make sure `cproton.py` is generated
+    # before the python modules are collected. Otherwise, it won't
+    # be installed.
+    sub_commands = [
+        ('build_ext', build.has_ext_modules),
+        ('build_py', build.has_pure_modules),
+        ('build_clib', build.has_c_libraries),
+        ('build_scripts', build.has_scripts),
+    ]
+
+
+class CheckingBuildExt(build_ext):
+    """Subclass build_ext to build qpid-proton using `cmake`"""
+
+    def run(self):
+        # Discover qpid-proton in the system
+        self.distribution.run_command('configure')
+        build_ext.run(self)
 
 
-# NOTE(flaper87): Override `build_ext` and add `configure`
+# Override `build_ext` and add `configure`
 cmdclass = {'configure': Configure,
             'build': CustomBuildOrder,
             'build_ext': CheckingBuildExt}
@@ -219,4 +332,5 @@ setup(name='python-qpid-proton',
                    "Programming Language :: Python"],
       cmdclass = cmdclass,
       ext_modules=[Extension('_cproton', ['cproton.i'],
+                             swig_opts=['-threads'],
                              libraries=['qpid-proton'])])

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/bindings/python/setuputils/bundle.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/bundle.py b/proton-c/bindings/python/setuputils/bundle.py
index 920744d..13b88e0 100644
--- a/proton-c/bindings/python/setuputils/bundle.py
+++ b/proton-c/bindings/python/setuputils/bundle.py
@@ -32,10 +32,10 @@ from . import log
 #-----------------------------------------------------------------------------
 # Constants
 #-----------------------------------------------------------------------------
-min_qpid_proton = (0, 9)
+min_qpid_proton = (0, 10)
 min_qpid_proton_str = "%i.%i" % min_qpid_proton
 
-bundled_version = (0,9,1)
+bundled_version = (0, 10, 0)
 bundled_version_str = "%i.%i.%i" % bundled_version
 libqpid_proton = "qpid-proton-%s.tar.gz" % bundled_version_str
 libqpid_proton_url = ("http://www.apache.org/dist/qpid/proton/%s/%s" %

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/bindings/python/setuputils/log.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/log.py b/proton-c/bindings/python/setuputils/log.py
index 1e051d4..f11b255 100644
--- a/proton-c/bindings/python/setuputils/log.py
+++ b/proton-c/bindings/python/setuputils/log.py
@@ -26,7 +26,7 @@ if os.environ.get('DEBUG'):
     logger.setLevel(logging.DEBUG)
 else:
     logger.setLevel(logging.INFO)
-    logger.addHandler(logging.StreamHandler(sys.stderr))
+logger.addHandler(logging.StreamHandler(sys.stderr))
 
 
 def debug(msg):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/bindings/python/setuputils/misc.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/setuputils/misc.py b/proton-c/bindings/python/setuputils/misc.py
index 8978371..cf6b97f 100644
--- a/proton-c/bindings/python/setuputils/misc.py
+++ b/proton-c/bindings/python/setuputils/misc.py
@@ -19,89 +19,7 @@ import sys
 from . import log
 
 
-def settings_from_prefix(prefix=None):
-    """Load appropriate library/include settings from qpid-proton prefix
-
-    NOTE: Funcion adapted from PyZMQ, which is itself Modified BSD licensed.
-
-    :param prefix: The install prefix where the dependencies are expected to be
-    """
-    settings = {}
-    settings['libraries'] = []
-    settings['include_dirs'] = []
-    settings['library_dirs'] = []
-    settings['swig_opts'] = ['-threads']
-    settings['runtime_library_dirs'] = []
-    settings['extra_link_args'] = []
-
-    if sys.platform.startswith('win'):
-        settings['libraries'].append('libqpid-proton')
-
-        if prefix:
-            settings['include_dirs'] += [os.path.join(prefix, 'include')]
-            settings['library_dirs'] += [os.path.join(prefix, 'lib')]
-    else:
-
-        # If prefix is not explicitly set, pull it from pkg-config by default.
-
-        if not prefix:
-            try:
-                cmd = 'pkg-config --variable=prefix --print-errors libqpid-proton'.split()
-                p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-            except OSError as e:
-                if e.errno == errno.ENOENT:
-                    log.info("pkg-config not found")
-                else:
-                    log.warn("Running pkg-config failed - %s." % e)
-                p = None
-            if p is not None:
-                if p.wait():
-                    log.info("Did not find libqpid-proton via pkg-config:")
-                    log.info(p.stderr.read().decode())
-                else:
-                    prefix = p.stdout.readline().strip().decode()
-                    log.info("Using qpid-proton-prefix %s (found via pkg-config)." % prefix)
-
-        settings['libraries'].append('qpid-proton')
-        # add pthread on freebsd
-        if sys.platform.startswith('freebsd'):
-            settings['libraries'].append('pthread')
-
-        if sys.platform == 'sunos5':
-          if platform.architecture()[0] == '32bit':
-            settings['extra_link_args'] += ['-m32']
-          else:
-            settings['extra_link_args'] += ['-m64']
-        if prefix:
-            settings['include_dirs'] += [os.path.join(prefix, 'include')]
-            settings['library_dirs'] += [os.path.join(prefix, 'lib')]
-            settings['library_dirs'] += [os.path.join(prefix, 'lib64')]
-
-        else:
-            if sys.platform == 'darwin' and os.path.isdir('/opt/local/lib'):
-                # allow macports default
-                settings['include_dirs'] += ['/opt/local/include']
-                settings['library_dirs'] += ['/opt/local/lib']
-                settings['library_dirs'] += ['/opt/local/lib64']
-            if os.environ.get('VIRTUAL_ENV', None):
-                # find libqpid_proton installed in virtualenv
-                env = os.environ['VIRTUAL_ENV']
-                settings['include_dirs'] += [os.path.join(env, 'include')]
-                settings['library_dirs'] += [os.path.join(env, 'lib')]
-                settings['library_dirs'] += [os.path.join(env, 'lib64')]
-
-        if sys.platform != 'darwin':
-            settings['runtime_library_dirs'] += [
-                os.path.abspath(x) for x in settings['library_dirs']
-            ]
-
-    for d in settings['include_dirs']:
-        settings['swig_opts'] += ['-I' + d]
-
-    return settings
-
-
-def pkg_config_version(atleast=None, max_version=None):
+def pkg_config_version(atleast=None, max_version=None, module='libqpid-proton'):
     """Check the qpid_proton version using pkg-config
 
     This function returns True/False depending on whether
@@ -119,7 +37,7 @@ def pkg_config_version(atleast=None, max_version=None):
         cmd = ['pkg-config',
                '--%s-version=%s' % (atleast and 'atleast' or 'max',
                                     atleast or max_version),
-               'libqpid-proton']
+               module]
         p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     except OSError as e:
         if e.errno == errno.ENOENT:
@@ -133,5 +51,5 @@ def pkg_config_version(atleast=None, max_version=None):
         log.info(p.stderr.read().decode())
         return False
 
-    log.info("Using libqpid-proton (found via pkg-config).")
+    log.info("Using %s (found via pkg-config)." % module)
     return True

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/proton-c/bindings/python/tox.ini
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/tox.ini b/proton-c/bindings/python/tox.ini
new file mode 100644
index 0000000..aab5e4e
--- /dev/null
+++ b/proton-c/bindings/python/tox.ini
@@ -0,0 +1,36 @@
+[tox]
+envlist = build
+minversion = 1.4
+skipdist = True
+
+[testenv]
+changedir = {toxinidir}/../../proton-c/include/
+setenv =
+    VIRTUAL_ENV={envdir}
+passenv =
+    PKG_CONFIG_PATH
+    CFLAGS
+commands =
+    pip install -e {toxinidir}
+    tests/python/proton-test {posargs}
+
+[testenv:pep8]
+commands = flake8
+
+[testenv:docs]
+commands = python setup.py build_sphinx
+
+[testenv:build]
+usedevelop = False
+skipdist = True
+changedir = {toxinidir}
+platform = linux2
+skip_install = True
+setenv =
+    VIRTUAL_ENV={envdir}
+    PKG_CONFIG_PATH=None
+    QPID_PROTON_SRC={toxinidir}/../../../
+    DEBUG=True
+commands =
+    {envbindir}/python setup.py build -b {envbindir}/build install
+    {toxinidir}/../../../tests/python/proton-test {posargs}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/3db3cf17/tests/python/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/tests/python/proton_tests/common.py b/tests/python/proton_tests/common.py
index 1b8dbdb..83a39f8 100644
--- a/tests/python/proton_tests/common.py
+++ b/tests/python/proton_tests/common.py
@@ -219,14 +219,22 @@ class MessengerApp(object):
                     foundfile = self.findfile(cmd[0], os.environ['PATH'])
                     if foundfile is None:
                         foundfile = self.findfile(cmd[0], os.environ['PYTHONPATH'])
-                        assert foundfile is not None, "Unable to locate file '%s' in PATH or PYTHONPATH" % cmd[0]
+                        msg = "Unable to locate file '%s' in PATH or PYTHONPATH" % cmd[0]
+                        raise Skipped("Skipping test - %s" % msg)
+
                     del cmd[0:1]
                     cmd.insert(0, foundfile)
                     cmd.insert(0, sys.executable)
             self._process = Popen(cmd, stdout=PIPE, stderr=STDOUT, bufsize=4096)
         except OSError, e:
             print("ERROR: '%s'" % e)
-            assert False, "Unable to execute command '%s', is it in your PATH?" % cmd[0]
+            msg = "Unable to execute command '%s', is it in your PATH?" % cmd[0]
+
+            # NOTE(flaper87): Skip the test if the command is not found.
+            if e.errno == 2:
+              raise Skipped("Skipping test - %s" % msg)
+            assert False, msg
+
         self._ready()  # wait for it to initialize
 
     def stop(self):


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org