From commits-noreply at bitbucket.org Thu Aug 1 07:43:08 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 05:43:08 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. Message-ID: <20130801054308.2537.81744@app01.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/fedb1afd3a51/ Changeset: fedb1afd3a51 User: hpk42 Date: 2013-08-01 07:43:00 Summary: fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. (this is just changing the CHANGELOG entry because the bug was already fixed earlier) Affected #: 1 file diff -r 73015defd88f6a45ba44fd6e109b03bc8b3e82e9 -r fedb1afd3a51e963d60071491f5dac182b1e3bf4 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -65,7 +65,7 @@ - fix junitxml generation when test output contains control characters, addressing issue267, thanks Jaap Broekhuizen -- honor --tb style for setup/teardown errors as well. Thanks Maho. +- fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. - fix issue307 - use yaml.safe_load in example, thanks Mark Eichin. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Aug 1 07:48:56 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 01 Aug 2013 05:48:56 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#26 (master - e568fef) Message-ID: <51f9f6c758610_246242584cf@7a983db1-2104-4deb-b34e-e7c9861fd67a.mail> Build Update for hpk42/pytest ------------------------------------- Build: #26 Status: Still Failing Duration: 4 minutes and 15 seconds Commit: e568fef (master) Author: holger krekel Message: fix issue338: honor --tb style for setup/teardown errors as well. Thanks Maho. (this is just changing the CHANGELOG entry because the bug was already fixed earlier) View the changeset: https://github.com/hpk42/pytest/compare/95f25c1bc1c3...e568fefd54c4 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9722832 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 1 09:31:40 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 07:31:40 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add license note to README Message-ID: <20130801073140.25227.41357@app03.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/e93ac22bce4a/ Changeset: e93ac22bce4a User: hpk42 Date: 2013-08-01 09:31:34 Summary: add license note to README Affected #: 1 file diff -r fedb1afd3a51e963d60071491f5dac182b1e3bf4 -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 README.rst --- a/README.rst +++ b/README.rst @@ -42,3 +42,4 @@ Copyright Holger Krekel and others, 2004-2013 +Licensed under the MIT license. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 09:42:54 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 07:42:54 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue334: don't recommend distribute but setuptools everywhere, also remove implicit distribute_setup support from setup.py. Message-ID: <20130801074254.30767.8816@app13.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/2d92b2270aba/ Changeset: 2d92b2270aba User: hpk42 Date: 2013-08-01 09:42:44 Summary: fix issue334: don't recommend distribute but setuptools everywhere, also remove implicit distribute_setup support from setup.py. Affected #: 6 files diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- remove implicit distribute_setup support from setup.py. + - integrate tab-completion on options through use of "argcomplete". Thanks Anthon van der Neut for the PR. diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb distribute_setup.py --- a/distribute_setup.py +++ /dev/null @@ -1,497 +0,0 @@ -#!python -"""Bootstrap distribute installation - -If you want to use setuptools in your package's setup.py, just include this -file in the same directory with it, and add this to the top of your setup.py:: - - from distribute_setup import use_setuptools - use_setuptools() - -If you want to require a specific version of setuptools, set a download -mirror, or use an alternate download directory, you can do so by supplying -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import os -import sys -import time -import fnmatch -import tempfile -import tarfile -from distutils import log - -try: - from site import USER_SITE -except ImportError: - USER_SITE = None - -try: - import subprocess - - def _python_cmd(*args): - args = (sys.executable,) + args - return subprocess.call(args) == 0 - -except ImportError: - # will be used for python 2.3 - def _python_cmd(*args): - args = (sys.executable,) + args - # quoting arguments if windows - if sys.platform == 'win32': - def quote(arg): - if ' ' in arg: - return '"%s"' % arg - return arg - args = [quote(arg) for arg in args] - return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 - -DEFAULT_VERSION = "0.6.27" -DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" -SETUPTOOLS_FAKED_VERSION = "0.6c11" - -SETUPTOOLS_PKG_INFO = """\ -Metadata-Version: 1.0 -Name: setuptools -Version: %s -Summary: xxxx -Home-page: xxx -Author: xxx -Author-email: xxx -License: xxx -Description: xxx -""" % SETUPTOOLS_FAKED_VERSION - - -def _install(tarball, install_args=()): - # extracting the tarball - tmpdir = tempfile.mkdtemp() - log.warn('Extracting in %s', tmpdir) - old_wd = os.getcwd() - try: - os.chdir(tmpdir) - tar = tarfile.open(tarball) - _extractall(tar) - tar.close() - - # going in the directory - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) - os.chdir(subdir) - log.warn('Now working in %s', subdir) - - # installing - log.warn('Installing Distribute') - if not _python_cmd('setup.py', 'install', *install_args): - log.warn('Something went wrong during the installation.') - log.warn('See the error message above.') - finally: - os.chdir(old_wd) - - -def _build_egg(egg, tarball, to_dir): - # extracting the tarball - tmpdir = tempfile.mkdtemp() - log.warn('Extracting in %s', tmpdir) - old_wd = os.getcwd() - try: - os.chdir(tmpdir) - tar = tarfile.open(tarball) - _extractall(tar) - tar.close() - - # going in the directory - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) - os.chdir(subdir) - log.warn('Now working in %s', subdir) - - # building an egg - log.warn('Building a Distribute egg in %s', to_dir) - _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) - - finally: - os.chdir(old_wd) - # returning the result - log.warn(egg) - if not os.path.exists(egg): - raise IOError('Could not build the egg.') - - -def _do_download(version, download_base, to_dir, download_delay): - egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' - % (version, sys.version_info[0], sys.version_info[1])) - if not os.path.exists(egg): - tarball = download_setuptools(version, download_base, - to_dir, download_delay) - _build_egg(egg, tarball, to_dir) - sys.path.insert(0, egg) - import setuptools - setuptools.bootstrap_install_from = egg - - -def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, download_delay=15, no_fake=True): - # making sure we use the absolute path - to_dir = os.path.abspath(to_dir) - was_imported = 'pkg_resources' in sys.modules or \ - 'setuptools' in sys.modules - try: - try: - import pkg_resources - if not hasattr(pkg_resources, '_distribute'): - if not no_fake: - _fake_setuptools() - raise ImportError - except ImportError: - return _do_download(version, download_base, to_dir, download_delay) - try: - pkg_resources.require("distribute>="+version) - return - except pkg_resources.VersionConflict: - e = sys.exc_info()[1] - if was_imported: - sys.stderr.write( - "The required version of distribute (>=%s) is not available,\n" - "and can't be installed while this script is running. Please\n" - "install a more recent version first, using\n" - "'easy_install -U distribute'." - "\n\n(Currently using %r)\n" % (version, e.args[0])) - sys.exit(2) - else: - del pkg_resources, sys.modules['pkg_resources'] # reload ok - return _do_download(version, download_base, to_dir, - download_delay) - except pkg_resources.DistributionNotFound: - return _do_download(version, download_base, to_dir, - download_delay) - finally: - if not no_fake: - _create_fake_setuptools_pkg_info(to_dir) - -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, delay=15): - """Download distribute from a specified location and return its filename - - `version` should be a valid distribute version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download - attempt. - """ - # making sure we use the absolute path - to_dir = os.path.abspath(to_dir) - try: - from urllib.request import urlopen - except ImportError: - from urllib2 import urlopen - tgz_name = "distribute-%s.tar.gz" % version - url = download_base + tgz_name - saveto = os.path.join(to_dir, tgz_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - log.warn("Downloading %s", url) - src = urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = src.read() - dst = open(saveto, "wb") - dst.write(data) - finally: - if src: - src.close() - if dst: - dst.close() - return os.path.realpath(saveto) - -def _no_sandbox(function): - def __no_sandbox(*args, **kw): - try: - from setuptools.sandbox import DirectorySandbox - if not hasattr(DirectorySandbox, '_old'): - def violation(*args): - pass - DirectorySandbox._old = DirectorySandbox._violation - DirectorySandbox._violation = violation - patched = True - else: - patched = False - except ImportError: - patched = False - - try: - return function(*args, **kw) - finally: - if patched: - DirectorySandbox._violation = DirectorySandbox._old - del DirectorySandbox._old - - return __no_sandbox - -def _patch_file(path, content): - """Will backup the file then patch it""" - existing_content = open(path).read() - if existing_content == content: - # already patched - log.warn('Already patched.') - return False - log.warn('Patching...') - _rename_path(path) - f = open(path, 'w') - try: - f.write(content) - finally: - f.close() - return True - -_patch_file = _no_sandbox(_patch_file) - -def _same_content(path, content): - return open(path).read() == content - -def _rename_path(path): - new_name = path + '.OLD.%s' % time.time() - log.warn('Renaming %s into %s', path, new_name) - os.rename(path, new_name) - return new_name - -def _remove_flat_installation(placeholder): - if not os.path.isdir(placeholder): - log.warn('Unkown installation at %s', placeholder) - return False - found = False - for file in os.listdir(placeholder): - if fnmatch.fnmatch(file, 'setuptools*.egg-info'): - found = True - break - if not found: - log.warn('Could not locate setuptools*.egg-info') - return - - log.warn('Removing elements out of the way...') - pkg_info = os.path.join(placeholder, file) - if os.path.isdir(pkg_info): - patched = _patch_egg_dir(pkg_info) - else: - patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) - - if not patched: - log.warn('%s already patched.', pkg_info) - return False - # now let's move the files out of the way - for element in ('setuptools', 'pkg_resources.py', 'site.py'): - element = os.path.join(placeholder, element) - if os.path.exists(element): - _rename_path(element) - else: - log.warn('Could not find the %s element of the ' - 'Setuptools distribution', element) - return True - -_remove_flat_installation = _no_sandbox(_remove_flat_installation) - -def _after_install(dist): - log.warn('After install bootstrap.') - placeholder = dist.get_command_obj('install').install_purelib - _create_fake_setuptools_pkg_info(placeholder) - -def _create_fake_setuptools_pkg_info(placeholder): - if not placeholder or not os.path.exists(placeholder): - log.warn('Could not find the install location') - return - pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) - setuptools_file = 'setuptools-%s-py%s.egg-info' % \ - (SETUPTOOLS_FAKED_VERSION, pyver) - pkg_info = os.path.join(placeholder, setuptools_file) - if os.path.exists(pkg_info): - log.warn('%s already exists', pkg_info) - return - - if not os.access(pkg_info, os.W_OK): - log.warn("Don't have permissions to write %s, skipping", pkg_info) - - log.warn('Creating %s', pkg_info) - f = open(pkg_info, 'w') - try: - f.write(SETUPTOOLS_PKG_INFO) - finally: - f.close() - - pth_file = os.path.join(placeholder, 'setuptools.pth') - log.warn('Creating %s', pth_file) - f = open(pth_file, 'w') - try: - f.write(os.path.join(os.curdir, setuptools_file)) - finally: - f.close() - -_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) - -def _patch_egg_dir(path): - # let's check if it's already patched - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - if os.path.exists(pkg_info): - if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): - log.warn('%s already patched.', pkg_info) - return False - _rename_path(path) - os.mkdir(path) - os.mkdir(os.path.join(path, 'EGG-INFO')) - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - f = open(pkg_info, 'w') - try: - f.write(SETUPTOOLS_PKG_INFO) - finally: - f.close() - return True - -_patch_egg_dir = _no_sandbox(_patch_egg_dir) - -def _before_install(): - log.warn('Before install bootstrap.') - _fake_setuptools() - - -def _under_prefix(location): - if 'install' not in sys.argv: - return True - args = sys.argv[sys.argv.index('install')+1:] - for index, arg in enumerate(args): - for option in ('--root', '--prefix'): - if arg.startswith('%s=' % option): - top_dir = arg.split('root=')[-1] - return location.startswith(top_dir) - elif arg == option: - if len(args) > index: - top_dir = args[index+1] - return location.startswith(top_dir) - if arg == '--user' and USER_SITE is not None: - return location.startswith(USER_SITE) - return True - - -def _fake_setuptools(): - log.warn('Scanning installed packages') - try: - import pkg_resources - except ImportError: - # we're cool - log.warn('Setuptools or Distribute does not seem to be installed.') - return - ws = pkg_resources.working_set - try: - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', - replacement=False)) - except TypeError: - # old distribute API - setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) - - if setuptools_dist is None: - log.warn('No setuptools distribution found') - return - # detecting if it was already faked - setuptools_location = setuptools_dist.location - log.warn('Setuptools installation detected at %s', setuptools_location) - - # if --root or --preix was provided, and if - # setuptools is not located in them, we don't patch it - if not _under_prefix(setuptools_location): - log.warn('Not patching, --root or --prefix is installing Distribute' - ' in another location') - return - - # let's see if its an egg - if not setuptools_location.endswith('.egg'): - log.warn('Non-egg installation') - res = _remove_flat_installation(setuptools_location) - if not res: - return - else: - log.warn('Egg installation') - pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') - if (os.path.exists(pkg_info) and - _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): - log.warn('Already patched.') - return - log.warn('Patching...') - # let's create a fake egg replacing setuptools one - res = _patch_egg_dir(setuptools_location) - if not res: - return - log.warn('Patched done.') - _relaunch() - - -def _relaunch(): - log.warn('Relaunching...') - # we have to relaunch the process - # pip marker to avoid a relaunch bug - if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: - sys.argv[0] = 'setup.py' - args = [sys.executable] + sys.argv - sys.exit(subprocess.call(args)) - - -def _extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - import copy - import operator - from tarfile import ExtractError - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 448 # decimal for oct 0700 - self.extract(tarinfo, path) - - # Reverse sort directories. - if sys.version_info < (2, 4): - def sorter(dir1, dir2): - return cmp(dir1.name, dir2.name) - directories.sort(sorter) - directories.reverse() - else: - directories.sort(key=operator.attrgetter('name'), reverse=True) - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError: - e = sys.exc_info()[1] - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - -def _build_install_args(argv): - install_args = [] - user_install = '--user' in argv - if user_install and sys.version_info < (2,6): - log.warn("--user requires Python 2.6 or later") - raise SystemExit(1) - if user_install: - install_args.append('--user') - return install_args - -def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - tarball = download_setuptools() - _install(tarball, _build_install_args(argv)) - - -if __name__ == '__main__': - main(sys.argv[1:]) diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb doc/en/faq.txt --- a/doc/en/faq.txt +++ b/doc/en/faq.txt @@ -171,16 +171,8 @@ protect its generated command line script. This leads to infinite recursion when running a test that instantiates Processes. -A good solution is to `install Distribute`_ as a drop-in replacement -for setuptools and then re-install ``pytest``. Otherwise you could -fix the script that is created by setuptools by inserting an -``if __name__ == '__main__'``. Or you can create a "pytest.py" -script with this content and invoke that with the python version:: - - import pytest - if __name__ == '__main__': - pytest.main() - -.. _`install distribute`: http://pypi.python.org/pypi/distribute#installation-instructions +As of middle 2013, there shouldn't be a problem anymore when you +use the standard setuptools (note that distribute has been merged +back into setuptools which is now shipped directly with virtualenv). .. include:: links.inc diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb doc/en/getting-started.txt --- a/doc/en/getting-started.txt +++ b/doc/en/getting-started.txt @@ -198,11 +198,8 @@ `Install pip`_ for a state of the art python package installer. -Or consult `distribute docs`_ to install the ``easy_install`` -tool on your machine. - -You may also use the older `setuptools`_ project but it lacks bug fixes -and does not work on Python3. +Install `setuptools`_ to get ``easy_install`` which allows to install +``.egg`` binary format packages in addition to source-based ones. py.test not found on Windows despite installation? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb doc/en/goodpractises.txt --- a/doc/en/goodpractises.txt +++ b/doc/en/goodpractises.txt @@ -46,8 +46,6 @@ python runtests.py -.. _`Distribute for installation`: http://pypi.python.org/pypi/distribute#installation-instructions -.. _`distribute installation`: http://pypi.python.org/pypi/distribute Integrating with distutils / ``python setup.py test`` @@ -92,12 +90,11 @@ options. -Integration with setuptools/distribute test commands +Integration with setuptools test commands ---------------------------------------------------- -Distribute/Setuptools support test requirements, -which means its really easy to extend its test command -to support running a pytest from test requirements:: +Setuptools supports writing our own Test command for invoking +pytest:: from setuptools.command.test import test as TestCommand import sys diff -r e93ac22bce4a9ed4999ea0ca3a1d7a213829b143 -r 2d92b2270aba23d130c8e75c4f145e1e45427deb setup.py --- a/setup.py +++ b/setup.py @@ -1,10 +1,5 @@ import os, sys -try: - from setuptools import setup, Command -except ImportError: - from distribute_setup import use_setuptools - use_setuptools() - from setuptools import setup, Command +from setuptools import setup, Command long_description = open("README.rst").read() def main(): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 10:30:28 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 08:30:28 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130801083028.8640.51647@app12.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/e2889c9a0d75/ Changeset: e2889c9a0d75 Branch: argcomplete User: Anthon van der Neut Date: 2013-07-31 16:03:53 Summary: fix for tests running subprocesses of py.test after test_argcomplete (which all still ran with argcompletion enabled) -> fail Affected #: 1 file diff -r f44d44a4142b72a260007e413e6419549b3c1dc1 -r e2889c9a0d75963201f2d098482f28002a199f6f testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -176,7 +176,7 @@ @pytest.mark.skipif("sys.version_info < (2,5)") def test_argcomplete(testdir): if not py.path.local.sysfind('bash'): - pytest.skip("bash not available") + pytest.skip("bash not available") import os script = os.path.join(os.getcwd(), 'test_argcomplete') with open(str(script), 'w') as fp: @@ -185,6 +185,10 @@ # so we use bash fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) ' '8>&1 9>&2') + # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able + # to handle a keyword argument env that replaces os.environ in popen or + # extends the copy, advantage: could not forget to restore + orgenv = os.environ.copy() os.environ['_ARGCOMPLETE'] = "1" os.environ['_ARGCOMPLETE_IFS'] = "\x0b" os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:' @@ -206,3 +210,5 @@ os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) + # restore environment + os.environ = orgenv.copy() https://bitbucket.org/hpk42/pytest/commits/5ac465ea2d43/ Changeset: 5ac465ea2d43 Branch: argcomplete User: Anthon van der Neut Date: 2013-07-31 21:33:13 Summary: monkeypatch for os.environment changes Affected #: 1 file diff -r e2889c9a0d75963201f2d098482f28002a199f6f -r 5ac465ea2d438ae71524197ecfd5a8f4ce2d4d90 testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -174,7 +174,7 @@ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) @pytest.mark.skipif("sys.version_info < (2,5)") -def test_argcomplete(testdir): +def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): pytest.skip("bash not available") import os @@ -188,14 +188,13 @@ # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able # to handle a keyword argument env that replaces os.environ in popen or # extends the copy, advantage: could not forget to restore - orgenv = os.environ.copy() - os.environ['_ARGCOMPLETE'] = "1" - os.environ['_ARGCOMPLETE_IFS'] = "\x0b" - os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:' + monkeypatch.setenv('_ARGCOMPLETE', "1") + monkeypatch.setenv('_ARGCOMPLETE_IFS',"\x0b") + monkeypatch.setenv('COMP_WORDBREAKS', ' \\t\\n"\\\'><=;|&(:') arg = '--fu' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) print dir(result), result.ret if result.ret == 255: @@ -206,9 +205,8 @@ os.mkdir('test_argcomplete.d') arg = 'test_argc' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) # restore environment - os.environ = orgenv.copy() https://bitbucket.org/hpk42/pytest/commits/b425db448787/ Changeset: b425db448787 User: hpk42 Date: 2013-08-01 10:30:24 Summary: Merged in anthon_van_der_neut/pytest/argcomplete (pull request #51) fix for tests running subprocesses of py.test after test_argcomplete Affected #: 1 file diff -r 2d92b2270aba23d130c8e75c4f145e1e45427deb -r b425db44878707b9688b8d4d179be349e341afed testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -174,9 +174,9 @@ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) @pytest.mark.skipif("sys.version_info < (2,5)") -def test_argcomplete(testdir): +def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): - pytest.skip("bash not available") + pytest.skip("bash not available") import os script = os.path.join(os.getcwd(), 'test_argcomplete') with open(str(script), 'w') as fp: @@ -185,13 +185,16 @@ # so we use bash fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) ' '8>&1 9>&2') - os.environ['_ARGCOMPLETE'] = "1" - os.environ['_ARGCOMPLETE_IFS'] = "\x0b" - os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:' + # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able + # to handle a keyword argument env that replaces os.environ in popen or + # extends the copy, advantage: could not forget to restore + monkeypatch.setenv('_ARGCOMPLETE', "1") + monkeypatch.setenv('_ARGCOMPLETE_IFS',"\x0b") + monkeypatch.setenv('COMP_WORDBREAKS', ' \\t\\n"\\\'><=;|&(:') arg = '--fu' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) print dir(result), result.ret if result.ret == 255: @@ -202,7 +205,8 @@ os.mkdir('test_argcomplete.d') arg = 'test_argc' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) + # restore environment Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 10:38:17 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 08:38:17 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: remove an entry Message-ID: <20130801083817.22825.21147@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/fb8e713b7ab8/ Changeset: fb8e713b7ab8 User: hpk42 Date: 2013-08-01 10:37:45 Summary: remove an entry Affected #: 1 file diff -r b425db44878707b9688b8d4d179be349e341afed -r fb8e713b7ab8c382f0d7d579005b12611204763b ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,10 +1,4 @@ -improve / add to dependency/test resource injection -------------------------------------------------------------- -tags: wish feature docs - -write up better examples showing the connection between -the two. refine parametrize API ------------------------------------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 10:41:02 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 08:41:02 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: remove an old issue. Message-ID: <20130801084102.7807.97427@app01.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/dbd8f1c68619/ Changeset: dbd8f1c68619 User: hpk42 Date: 2013-08-01 10:40:55 Summary: remove an old issue. Affected #: 1 file diff -r fb8e713b7ab8c382f0d7d579005b12611204763b -r dbd8f1c68619e305e9b1a64a31fa61081b0e2068 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -88,20 +88,6 @@ record which implementations of a hook succeeded and only call their teardown. -consider and document __init__ file usage in test directories ---------------------------------------------------------------- -tags: bug core - -Currently, a test module is imported with its fully qualified -package path, determined by checking __init__ files upwards. -This has the side effect that a source package at the root -of the test dir could be imported as well. This is somewhat -convenient but complicates the picture for running tests against -different versions of a package. Also, implicit sys.path -manipulations are problematic per-se. Maybe factorting out -a pytest_addsyspath hook which can be disabled from the command line -makes sense. In any case documentation/recommendations for -certain scenarios makes sense. relax requirement to have tests/testing contain an __init__ ---------------------------------------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 10:43:07 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 08:43:07 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: no funcargs for setup functions, rather use autouse fixtures. Message-ID: <20130801084307.22328.97961@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/a594ba9a0faf/ Changeset: a594ba9a0faf User: hpk42 Date: 2013-08-01 10:43:02 Summary: no funcargs for setup functions, rather use autouse fixtures. Affected #: 1 file diff -r dbd8f1c68619e305e9b1a64a31fa61081b0e2068 -r a594ba9a0faf78e105a5fdd0dea188ac20a7eeeb ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -200,28 +200,6 @@ having py.test.config and ensuretemp coming from a plugin rather than being there from the start. -consider allowing funcargs for setup methods --------------------------------------------------------------- -tags: experimental-wish - -Users have expressed the wish to have funcargs available to setup -functions. Experiment with allowing funcargs there - it might -also help to make the py.test.ensuretemp and config deprecation. -For filling funcargs for setup methods, we could call funcarg -factories with a request object that not have a cls/function -attributes. However, how to handle parametrized test functions -and funcargs? - -maybe introduce a setup method like: - - setup_invocation(self, request) - -which has full access to the test invocation through "request" -through which you can get funcargvalues, use cached_setup etc. -Therefore, the access to funcargs would be indirect but it -could be consistently implemented. setup_invocation() would -be a "glue" function for bringing together the xUnit and funcargs -world. consider pytest_addsyspath hook ----------------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 10:57:43 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 08:57:43 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: plugin versions are displayed now. Message-ID: <20130801085743.6846.25118@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/352136038501/ Changeset: 352136038501 User: hpk42 Date: 2013-08-01 10:57:36 Summary: plugin versions are displayed now. Affected #: 1 file diff -r a594ba9a0faf78e105a5fdd0dea188ac20a7eeeb -r 3521360385012cfc91587afff35e9115ea656fbb ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -213,13 +213,6 @@ and pytest_configure. -show plugin information in test header ----------------------------------------------------------------- -tags: feature - -Now that external plugins are becoming more numerous -it would be useful to have external plugins along with -their versions displayed as a header line. deprecate global py.test.config usage ---------------------------------------------------------------- Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 11:00:01 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 09:00:01 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: small mod to test BND Message-ID: <20130801090001.29886.30904@app13.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/a9a6b115c610/ Changeset: a9a6b115c610 User: hpk42 Date: 2013-08-01 10:59:45 Summary: small mod to test BND Affected #: 1 file diff -r 3521360385012cfc91587afff35e9115ea656fbb -r a9a6b115c610037725edd24732ff430d13276209 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -203,7 +203,7 @@ consider pytest_addsyspath hook ----------------------------------------- -tags: +tags: wish py.test could call a new pytest_addsyspath() in order to systematically allow manipulation of sys.path and to inhibit it via --no-addsyspath Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 11:31:49 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 09:31:49 -0000 Subject: [Pytest-commit] commit/pytest: 4 new changesets Message-ID: <20130801093149.24798.60459@app10.ash-private.bitbucket.org> 4 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/beb37acf4967/ Changeset: beb37acf4967 User: magopian Date: 2013-08-01 11:12:02 Summary: fixes #335: document ExceptionInfo returned by pytest.raises Affected #: 1 file diff -r 2d92b2270aba23d130c8e75c4f145e1e45427deb -r beb37acf49678f8a9c6c2dc3bb586df5f96dd173 doc/en/assert.txt --- a/doc/en/assert.txt +++ b/doc/en/assert.txt @@ -78,6 +78,12 @@ # do checks related to excinfo.type, excinfo.value, excinfo.traceback +``excinfo`` is a `py.code.ExceptionInfo`_ instance, which is a wrapper around +the actual exception raised. + +.. _py.code.ExceptionInfo: + http://pylib.readthedocs.org/en/latest/code.html#py-code-exceptioninfo + If you want to write test code that works on Python 2.4 as well, you may also use two other ways to test for an expected exception:: https://bitbucket.org/hpk42/pytest/commits/fb9780b2d817/ Changeset: fb9780b2d817 User: magopian Date: 2013-08-01 11:12:59 Summary: Merged hpk42/pytest into default Affected #: 2 files diff -r beb37acf49678f8a9c6c2dc3bb586df5f96dd173 -r fb9780b2d8170817a14786a207addb0b6259b873 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,10 +1,4 @@ -improve / add to dependency/test resource injection -------------------------------------------------------------- -tags: wish feature docs - -write up better examples showing the connection between -the two. refine parametrize API ------------------------------------------------------------- @@ -94,20 +88,6 @@ record which implementations of a hook succeeded and only call their teardown. -consider and document __init__ file usage in test directories ---------------------------------------------------------------- -tags: bug core - -Currently, a test module is imported with its fully qualified -package path, determined by checking __init__ files upwards. -This has the side effect that a source package at the root -of the test dir could be imported as well. This is somewhat -convenient but complicates the picture for running tests against -different versions of a package. Also, implicit sys.path -manipulations are problematic per-se. Maybe factorting out -a pytest_addsyspath hook which can be disabled from the command line -makes sense. In any case documentation/recommendations for -certain scenarios makes sense. relax requirement to have tests/testing contain an __init__ ---------------------------------------------------------------- @@ -220,32 +200,10 @@ having py.test.config and ensuretemp coming from a plugin rather than being there from the start. -consider allowing funcargs for setup methods --------------------------------------------------------------- -tags: experimental-wish - -Users have expressed the wish to have funcargs available to setup -functions. Experiment with allowing funcargs there - it might -also help to make the py.test.ensuretemp and config deprecation. -For filling funcargs for setup methods, we could call funcarg -factories with a request object that not have a cls/function -attributes. However, how to handle parametrized test functions -and funcargs? - -maybe introduce a setup method like: - - setup_invocation(self, request) - -which has full access to the test invocation through "request" -through which you can get funcargvalues, use cached_setup etc. -Therefore, the access to funcargs would be indirect but it -could be consistently implemented. setup_invocation() would -be a "glue" function for bringing together the xUnit and funcargs -world. consider pytest_addsyspath hook ----------------------------------------- -tags: +tags: wish py.test could call a new pytest_addsyspath() in order to systematically allow manipulation of sys.path and to inhibit it via --no-addsyspath @@ -255,13 +213,6 @@ and pytest_configure. -show plugin information in test header ----------------------------------------------------------------- -tags: feature - -Now that external plugins are becoming more numerous -it would be useful to have external plugins along with -their versions displayed as a header line. deprecate global py.test.config usage ---------------------------------------------------------------- diff -r beb37acf49678f8a9c6c2dc3bb586df5f96dd173 -r fb9780b2d8170817a14786a207addb0b6259b873 testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -174,9 +174,9 @@ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) @pytest.mark.skipif("sys.version_info < (2,5)") -def test_argcomplete(testdir): +def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): - pytest.skip("bash not available") + pytest.skip("bash not available") import os script = os.path.join(os.getcwd(), 'test_argcomplete') with open(str(script), 'w') as fp: @@ -185,13 +185,16 @@ # so we use bash fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) ' '8>&1 9>&2') - os.environ['_ARGCOMPLETE'] = "1" - os.environ['_ARGCOMPLETE_IFS'] = "\x0b" - os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:' + # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able + # to handle a keyword argument env that replaces os.environ in popen or + # extends the copy, advantage: could not forget to restore + monkeypatch.setenv('_ARGCOMPLETE', "1") + monkeypatch.setenv('_ARGCOMPLETE_IFS',"\x0b") + monkeypatch.setenv('COMP_WORDBREAKS', ' \\t\\n"\\\'><=;|&(:') arg = '--fu' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) print dir(result), result.ret if result.ret == 255: @@ -202,7 +205,8 @@ os.mkdir('test_argcomplete.d') arg = 'test_argc' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) + # restore environment https://bitbucket.org/hpk42/pytest/commits/548650c26c6a/ Changeset: 548650c26c6a User: magopian Date: 2013-08-01 11:19:47 Summary: refs #335: clarify that the exception info returned by pytest.raises is a py.code.ExceptionInfo() Affected #: 1 file diff -r beb37acf49678f8a9c6c2dc3bb586df5f96dd173 -r 548650c26c6a9cd76852d29a5c70c37fcb90075c _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -844,6 +844,8 @@ """ assert that a code block/function call raises @ExpectedException and raise a failure exception otherwise. + This helper produces a ``py.code.ExceptionInfo()`` object. + If using Python 2.5 or above, you may use this function as a context manager:: https://bitbucket.org/hpk42/pytest/commits/82586cb1b93a/ Changeset: 82586cb1b93a User: magopian Date: 2013-08-01 11:20:30 Summary: merge Affected #: 2 files diff -r 548650c26c6a9cd76852d29a5c70c37fcb90075c -r 82586cb1b93aeb43f2582cbf1cdf615a708287b9 ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,10 +1,4 @@ -improve / add to dependency/test resource injection -------------------------------------------------------------- -tags: wish feature docs - -write up better examples showing the connection between -the two. refine parametrize API ------------------------------------------------------------- @@ -94,20 +88,6 @@ record which implementations of a hook succeeded and only call their teardown. -consider and document __init__ file usage in test directories ---------------------------------------------------------------- -tags: bug core - -Currently, a test module is imported with its fully qualified -package path, determined by checking __init__ files upwards. -This has the side effect that a source package at the root -of the test dir could be imported as well. This is somewhat -convenient but complicates the picture for running tests against -different versions of a package. Also, implicit sys.path -manipulations are problematic per-se. Maybe factorting out -a pytest_addsyspath hook which can be disabled from the command line -makes sense. In any case documentation/recommendations for -certain scenarios makes sense. relax requirement to have tests/testing contain an __init__ ---------------------------------------------------------------- @@ -220,32 +200,10 @@ having py.test.config and ensuretemp coming from a plugin rather than being there from the start. -consider allowing funcargs for setup methods --------------------------------------------------------------- -tags: experimental-wish - -Users have expressed the wish to have funcargs available to setup -functions. Experiment with allowing funcargs there - it might -also help to make the py.test.ensuretemp and config deprecation. -For filling funcargs for setup methods, we could call funcarg -factories with a request object that not have a cls/function -attributes. However, how to handle parametrized test functions -and funcargs? - -maybe introduce a setup method like: - - setup_invocation(self, request) - -which has full access to the test invocation through "request" -through which you can get funcargvalues, use cached_setup etc. -Therefore, the access to funcargs would be indirect but it -could be consistently implemented. setup_invocation() would -be a "glue" function for bringing together the xUnit and funcargs -world. consider pytest_addsyspath hook ----------------------------------------- -tags: +tags: wish py.test could call a new pytest_addsyspath() in order to systematically allow manipulation of sys.path and to inhibit it via --no-addsyspath @@ -255,13 +213,6 @@ and pytest_configure. -show plugin information in test header ----------------------------------------------------------------- -tags: feature - -Now that external plugins are becoming more numerous -it would be useful to have external plugins along with -their versions displayed as a header line. deprecate global py.test.config usage ---------------------------------------------------------------- diff -r 548650c26c6a9cd76852d29a5c70c37fcb90075c -r 82586cb1b93aeb43f2582cbf1cdf615a708287b9 testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -174,9 +174,9 @@ result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) @pytest.mark.skipif("sys.version_info < (2,5)") -def test_argcomplete(testdir): +def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): - pytest.skip("bash not available") + pytest.skip("bash not available") import os script = os.path.join(os.getcwd(), 'test_argcomplete') with open(str(script), 'w') as fp: @@ -185,13 +185,16 @@ # so we use bash fp.write('COMP_WORDBREAKS="$COMP_WORDBREAKS" $(which py.test) ' '8>&1 9>&2') - os.environ['_ARGCOMPLETE'] = "1" - os.environ['_ARGCOMPLETE_IFS'] = "\x0b" - os.environ['COMP_WORDBREAKS'] = ' \\t\\n"\\\'><=;|&(:' + # alternative would be exteneded Testdir.{run(),_run(),popen()} to be able + # to handle a keyword argument env that replaces os.environ in popen or + # extends the copy, advantage: could not forget to restore + monkeypatch.setenv('_ARGCOMPLETE', "1") + monkeypatch.setenv('_ARGCOMPLETE_IFS',"\x0b") + monkeypatch.setenv('COMP_WORDBREAKS', ' \\t\\n"\\\'><=;|&(:') arg = '--fu' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) print dir(result), result.ret if result.ret == 255: @@ -202,7 +205,8 @@ os.mkdir('test_argcomplete.d') arg = 'test_argc' - os.environ['COMP_LINE'] = "py.test " + arg - os.environ['COMP_POINT'] = str(len(os.environ['COMP_LINE'])) + monkeypatch.setenv('COMP_LINE', "py.test " + arg) + monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) + # restore environment Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 11:36:13 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 09:36:13 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add changelog entry for fixed issue 335. Message-ID: <20130801093613.13696.36406@app13.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/602f56106877/ Changeset: 602f56106877 User: hpk42 Date: 2013-08-01 11:36:05 Summary: add changelog entry for fixed issue 335. Affected #: 1 file diff -r 82586cb1b93aeb43f2582cbf1cdf615a708287b9 -r 602f56106877324409723f162f0e0e79c37a43d1 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- fix issue335: document py.code.ExceptionInfo() object returned + from pytest.raises(), thanks Matthieu Agopian. + - remove implicit distribute_setup support from setup.py. - integrate tab-completion on options through use of "argcomplete". Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 12:12:15 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 10:12:15 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix Mathieu's name. Message-ID: <20130801101215.3914.42205@app05.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/57c2d802af51/ Changeset: 57c2d802af51 User: hpk42 Date: 2013-08-01 12:12:09 Summary: fix Mathieu's name. Affected #: 1 file diff -r 602f56106877324409723f162f0e0e79c37a43d1 -r 57c2d802af5130311aba74643efbf92738df8960 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ ----------------------------------- - fix issue335: document py.code.ExceptionInfo() object returned - from pytest.raises(), thanks Matthieu Agopian. + from pytest.raises(), thanks Mathieu Agopian. - remove implicit distribute_setup support from setup.py. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Aug 1 12:37:13 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 01 Aug 2013 10:37:13 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#27 (master - c4ad24e) Message-ID: <51fa3a595d430_2470594292372@8aeee4ec-1149-4a7d-ba72-77425042e7c5.mail> Build Update for hpk42/pytest ------------------------------------- Build: #27 Status: Still Failing Duration: 4 minutes and 23 seconds Commit: c4ad24e (master) Author: holger krekel Message: fix Mathieu's name. View the changeset: https://github.com/hpk42/pytest/compare/e568fefd54c4...c4ad24e2d095 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9730030 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 1 14:24:32 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 12:24:32 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix some py33 issues introduced with rev 2985 Message-ID: <20130801122432.27424.7751@app10.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/962999e40560/ Changeset: 962999e40560 Branch: argcomplete User: hpk42 Date: 2013-08-01 14:24:25 Summary: fix some py33 issues introduced with rev 2985 Affected #: 2 files diff -r 5ac465ea2d438ae71524197ecfd5a8f4ce2d4d90 -r 962999e405607cd5173e900bcb732301dab1dd0f _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -4,7 +4,7 @@ import sys, os from _pytest.core import PluginManager import pytest -from _argcomplete import try_argcomplete, filescompleter +from _pytest._argcomplete import try_argcomplete, filescompleter # enable after some grace period for plugin writers TYPE_WARN = False @@ -142,7 +142,7 @@ 'int': int, 'string': str, } - + def __init__(self, *names, **attrs): """store parms in private vars for use in add_argument""" self._attrs = attrs @@ -188,7 +188,7 @@ FutureWarning, stacklevel=3) attrs['type'] = Argument._typ_map[typ] - # used in test_parseopt -> test_parse_defaultgetter + # used in test_parseopt -> test_parse_defaultgetter self.type = attrs['type'] else: self.type = typ @@ -227,7 +227,7 @@ #a = a.replace('%prog', '%(prog)s') self._attrs['help'] = a return self._attrs - + def _set_opt_strings(self, opts): """directly from optparse @@ -251,7 +251,7 @@ "must start with --, followed by non-dash" % opt, self) self._long_opts.append(opt) - + def __repr__(self): retval = 'Argument(' if self._short_opts: @@ -268,7 +268,7 @@ retval += ')' return retval - + class OptionGroup: def __init__(self, name, description="", parser=None): self.name = name @@ -320,7 +320,7 @@ getattr(args, Config._file_or_dir).extend(argv) return args - + class Conftest(object): """ the single place for accessing values and interacting towards conftest modules from py.test objects. @@ -440,7 +440,7 @@ class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ _file_or_dir = 'file_or_dir' - + def __init__(self, pluginmanager=None): #: access to command line option as attributes. #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead diff -r 5ac465ea2d438ae71524197ecfd5a8f4ce2d4d90 -r 962999e405607cd5173e900bcb732301dab1dd0f testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -196,7 +196,7 @@ monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) - print dir(result), result.ret + #print dir(result), result.ret if result.ret == 255: # argcomplete not found pytest.skip("argcomplete not available") Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 14:45:51 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 12:45:51 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: merge Message-ID: <20130801124551.7433.79925@app09.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/c402fa0d27e5/ Changeset: c402fa0d27e5 User: hpk42 Date: 2013-08-01 14:45:24 Summary: merge Affected #: 2 files diff -r 57c2d802af5130311aba74643efbf92738df8960 -r c402fa0d27e54e930deb9f210e7c30aa76c5f77b _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -4,7 +4,7 @@ import sys, os from _pytest.core import PluginManager import pytest -from _argcomplete import try_argcomplete, filescompleter +from _pytest._argcomplete import try_argcomplete, filescompleter # enable after some grace period for plugin writers TYPE_WARN = False @@ -142,7 +142,7 @@ 'int': int, 'string': str, } - + def __init__(self, *names, **attrs): """store parms in private vars for use in add_argument""" self._attrs = attrs @@ -188,7 +188,7 @@ FutureWarning, stacklevel=3) attrs['type'] = Argument._typ_map[typ] - # used in test_parseopt -> test_parse_defaultgetter + # used in test_parseopt -> test_parse_defaultgetter self.type = attrs['type'] else: self.type = typ @@ -227,7 +227,7 @@ #a = a.replace('%prog', '%(prog)s') self._attrs['help'] = a return self._attrs - + def _set_opt_strings(self, opts): """directly from optparse @@ -251,7 +251,7 @@ "must start with --, followed by non-dash" % opt, self) self._long_opts.append(opt) - + def __repr__(self): retval = 'Argument(' if self._short_opts: @@ -268,7 +268,7 @@ retval += ')' return retval - + class OptionGroup: def __init__(self, name, description="", parser=None): self.name = name @@ -320,7 +320,7 @@ getattr(args, Config._file_or_dir).extend(argv) return args - + class Conftest(object): """ the single place for accessing values and interacting towards conftest modules from py.test objects. @@ -440,7 +440,7 @@ class Config(object): """ access to configuration values, pluginmanager and plugin hooks. """ _file_or_dir = 'file_or_dir' - + def __init__(self, pluginmanager=None): #: access to command line option as attributes. #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead diff -r 57c2d802af5130311aba74643efbf92738df8960 -r c402fa0d27e54e930deb9f210e7c30aa76c5f77b testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -196,7 +196,7 @@ monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) - print dir(result), result.ret + #print dir(result), result.ret if result.ret == 255: # argcomplete not found pytest.skip("argcomplete not available") Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 14:53:31 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 12:53:31 -0000 Subject: [Pytest-commit] commit/pytest: magopian: refs #279: sequence assertions can also deal with (Mutable)Sequence instances Message-ID: <20130801125331.26542.80229@app03.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/85e374c50722/ Changeset: 85e374c50722 User: magopian Date: 2013-08-01 14:48:34 Summary: refs #279: sequence assertions can also deal with (Mutable)Sequence instances Affected #: 2 files diff -r c402fa0d27e54e930deb9f210e7c30aa76c5f77b -r 85e374c5072248cae6bab63ecf9e6cd9fdebf2a5 _pytest/assertion/util.py --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -1,6 +1,10 @@ """Utilities for assertion debugging""" import py +try: + from collections.abc import Sequence +except ImportError: + from collections import Sequence BuiltinAssertionError = py.builtin.builtins.AssertionError @@ -91,7 +95,8 @@ right_repr = py.io.saferepr(right, maxsize=width-len(left_repr)) summary = '%s %s %s' % (left_repr, op, right_repr) - issequence = lambda x: isinstance(x, (list, tuple)) + issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) + and not isinstance(x, basestring)) istext = lambda x: isinstance(x, basestring) isdict = lambda x: isinstance(x, dict) isset = lambda x: isinstance(x, (set, frozenset)) @@ -198,7 +203,7 @@ common = set(left).intersection(set(right)) same = dict((k, left[k]) for k in common if left[k] == right[k]) if same and not verbose: - explanation += ['Hiding %s identical items, use -v to show' % + explanation += ['Omitting %s identical items, use -v to show' % len(same)] elif same: explanation += ['Common items:'] diff -r c402fa0d27e54e930deb9f210e7c30aa76c5f77b -r 85e374c5072248cae6bab63ecf9e6cd9fdebf2a5 testing/test_assertion.py --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -3,6 +3,11 @@ import py, pytest import _pytest.assertion as plugin from _pytest.assertion import reinterpret, util +try: + from collections.abc import MutableSequence +except ImportError: + from collections import MutableSequence + needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)") @@ -95,13 +100,48 @@ expl = callequal({'a': 0}, {'a': 1}) assert len(expl) > 1 + def test_dict_omitting(self): + lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}) + assert lines[1].startswith('Omitting 1 identical item') + assert 'Common items' not in lines + for line in lines[1:]: + assert 'b' not in line + + def test_dict_omitting_verbose(self): + lines = callequal({'a': 0, 'b': 1}, {'a': 1, 'b': 1}, verbose=True) + assert lines[1].startswith('Common items:') + assert 'Omitting' not in lines[1] + assert lines[2] == "{'b': 1}" + def test_set(self): expl = callequal(set([0, 1]), set([0, 2])) assert len(expl) > 1 def test_frozenzet(self): expl = callequal(frozenset([0, 1]), set([0, 2])) - print (expl) + assert len(expl) > 1 + + def test_Sequence(self): + class TestSequence(MutableSequence): # works with a Sequence subclass + def __init__(self, iterable): + self.elements = list(iterable) + + def __getitem__(self, item): + return self.elements[item] + + def __len__(self): + return len(self.elements) + + def __setitem__(self, item, value): + pass + + def __delitem__(self, item): + pass + + def insert(self, item, index): + pass + + expl = callequal(TestSequence([0, 1]), list([0, 2])) assert len(expl) > 1 def test_list_tuples(self): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 15:39:06 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 13:39:06 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix collection imports for python2.5 Message-ID: <20130801133906.343.91561@app02.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/03f54633875f/ Changeset: 03f54633875f User: hpk42 Date: 2013-08-01 15:38:03 Summary: fix collection imports for python2.5 Affected #: 3 files diff -r 85e374c5072248cae6bab63ecf9e6cd9fdebf2a5 -r 03f54633875fb0717c70ee9d8308aa501667d7e0 _pytest/assertion/util.py --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -4,7 +4,11 @@ try: from collections.abc import Sequence except ImportError: - from collections import Sequence + try: + from collections import Sequence + except ImportError: + Sequence = list + BuiltinAssertionError = py.builtin.builtins.AssertionError diff -r 85e374c5072248cae6bab63ecf9e6cd9fdebf2a5 -r 03f54633875fb0717c70ee9d8308aa501667d7e0 testing/conftest.py --- a/testing/conftest.py +++ b/testing/conftest.py @@ -65,7 +65,7 @@ for val in l: metafunc.addcall(funcargs={name: val}) elif 'anypython' in metafunc.fixturenames: - for name in ('python2.4', 'python2.5', 'python2.6', + for name in ('python2.5', 'python2.6', 'python2.7', 'python3.2', "python3.3", 'pypy', 'jython'): metafunc.addcall(id=name, param=name) diff -r 85e374c5072248cae6bab63ecf9e6cd9fdebf2a5 -r 03f54633875fb0717c70ee9d8308aa501667d7e0 testing/test_assertion.py --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -3,12 +3,6 @@ import py, pytest import _pytest.assertion as plugin from _pytest.assertion import reinterpret, util -try: - from collections.abc import MutableSequence -except ImportError: - from collections import MutableSequence - - needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)") @@ -122,6 +116,14 @@ assert len(expl) > 1 def test_Sequence(self): + col = py.builtin._tryimport( + "collections.abc", + "collections", + "sys") + if not hasattr(col, "MutableSequence"): + pytest.skip("cannot import MutableSequence") + MutableSequence = col.MutableSequence + class TestSequence(MutableSequence): # works with a Sequence subclass def __init__(self, iterable): self.elements = list(iterable) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 15:44:29 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 13:44:29 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue305 - ignore any problems in writing a pyc file, but print out a trace. Message-ID: <20130801134429.32178.72491@app09.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/daa1e4c25b57/ Changeset: daa1e4c25b57 User: hpk42 Date: 2013-08-01 15:43:42 Summary: fix issue305 - ignore any problems in writing a pyc file, but print out a trace. Affected #: 3 files diff -r 03f54633875fb0717c70ee9d8308aa501667d7e0 -r daa1e4c25b578fdfa98a122922ea13bf80c8592a CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,8 @@ - remove implicit distribute_setup support from setup.py. +- fix issue305: ignore any problems when writing pyc files. + - integrate tab-completion on options through use of "argcomplete". Thanks Anthon van der Neut for the PR. diff -r 03f54633875fb0717c70ee9d8308aa501667d7e0 -r daa1e4c25b578fdfa98a122922ea13bf80c8592a _pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -156,7 +156,7 @@ raise return sys.modules[name] -def _write_pyc(co, source_path, pyc): +def _write_pyc(state, co, source_path, pyc): # Technically, we don't have to have the same pyc format as # (C)Python, since these "pycs" should never be seen by builtin # import. However, there's little reason deviate, and I hope @@ -167,15 +167,11 @@ fp = open(pyc, "wb") except IOError: err = sys.exc_info()[1].errno - if err in [errno.ENOENT, errno.ENOTDIR]: - # This happens when we get a EEXIST in find_module creating the - # __pycache__ directory and __pycache__ is by some non-dir node. - return False - elif err == errno.EACCES: - # The directory is read-only; this can happen for example when - # running the tests in a package installed as root - return False - raise + state.trace("error writing pyc file at %s: errno=%s" %(pyc, err)) + # we ignore any failure to write the cache file + # there are many reasons, permission-denied, __pycache__ being a + # file etc. + return False try: fp.write(imp.get_magic()) fp.write(struct.pack(" 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/74838a59928d/ Changeset: 74838a59928d User: flub Date: 2013-08-01 16:02:58 Summary: Close issue 279: improved assertrepr_compare Affected #: 1 file diff -r daa1e4c25b578fdfa98a122922ea13bf80c8592a -r 74838a59928dba3d97af1d0214840a1c1556258c CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- fix issue279: improve object comparisons on assertion failure + for standard datatypes and recognise collections.abc. Thanks to + Brianna Laugher and Mathieu Agopian. + - fix issue335: document py.code.ExceptionInfo() object returned from pytest.raises(), thanks Mathieu Agopian. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Aug 1 16:14:59 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 01 Aug 2013 14:14:59 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#28 (master - 9c7f046) Message-ID: <51fa6d62c15c0_210b5aa3454d@0a12d6ac-2d92-4712-aa24-df0f68b86bd1.mail> Build Update for hpk42/pytest ------------------------------------- Build: #28 Status: Still Failing Duration: 8 minutes and 50 seconds Commit: 9c7f046 (master) Author: Floris Bruynooghe Message: Close issue 279: improved assertrepr_compare View the changeset: https://github.com/hpk42/pytest/compare/c4ad24e2d095...9c7f046e0961 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9736764 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 1 16:33:52 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 14:33:52 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130801143352.2185.51962@app09.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/d32edaabee63/ Changeset: d32edaabee63 Branch: opt-drop-non-hyphened-long-options User: Anthon van der Neut Date: 2013-08-01 16:21:33 Summary: drop help for long options if longer versions with hyphens are available Affected #: 2 files diff -r 74838a59928dba3d97af1d0214840a1c1556258c -r d32edaabee634a6751782af51da6beeb83deff1d _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -277,7 +277,13 @@ self.parser = parser def addoption(self, *optnames, **attrs): - """ add an option to this group. """ + """ add an option to this group. + + if a shortened version of a long option is specified it will + be suppressed in the help. addoption('--twowords', '--two-words') + results in help showing '--two-words' only, but --twowords gets + accepted **and** the automatic destination is in args.twowords + """ option = Argument(*optnames, **attrs) self._addoption_instance(option, shortupper=False) @@ -299,7 +305,7 @@ def __init__(self, parser): self._parser = parser py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage, - add_help=False) + add_help=False, formatter_class=DropShorterLongHelpFormatter) def format_epilog(self, formatter): hints = self._parser.hints @@ -320,6 +326,67 @@ getattr(args, Config._file_or_dir).extend(argv) return args +# #pylib 2013-07-31 +# (12:05:53) anthon: hynek: can you get me a list of preferred py.test +# long-options with '-' inserted at the right places? +# (12:08:29) hynek: anthon, hpk: generally I'd love the following, decide +# yourself which you agree and which not: +# (12:10:51) hynek: --exit-on-first --full-trace --junit-xml --junit-prefix +# --result-log --collect-only --conf-cut-dir --trace-config +# --no-magic +# (12:18:21) hpk: hynek,anthon: makes sense to me. +# (13:40:30) hpk: hynek: let's not change names, rather only deal with +# hyphens for now +# (13:40:50) hynek: then --exit-first *shrug* + +class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter): + """shorten help for long options that differ only in extra hyphens + + - collapse **long** options that are the same except for extra hyphens + - special action attribute map_long_option allows surpressing additional + long options + - shortcut if there are only two options and one of them is a short one + - cache result on action object as this is called at least 2 times + """ + def _format_action_invocation(self, action): + orgstr = py.std.argparse.HelpFormatter._format_action_invocation(self, action) + if orgstr and orgstr[0] != '-': # only optional arguments + return orgstr + res = getattr(action, '_formatted_action_invocation', None) + if res: + return res + options = orgstr.split(', ') + if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2): + # a shortcut for '-h, --help' or '--abc', '-a' + action._formatted_action_invocation = orgstr + return orgstr + return_list = [] + option_map = getattr(action, 'map_long_option', {}) + if option_map is None: + option_map = {} + short_long = {} + for option in options: + if len(option) == 2 or option[2] == ' ': + continue + if not option.startswith('--'): + raise ArgumentError('long optional argument without "--": [%s]' + % (option), self) + xxoption = option[2:] + if xxoption.split()[0] not in option_map: + shortened = xxoption.replace('-', '') + if shortened not in short_long or \ + len(short_long[shortened]) < len(xxoption): + short_long[shortened] = xxoption + # now short_long has been filled out to the longest with dashes + # **and** we keep the right option ordering from add_argument + for option in options: # + if len(option) == 2 or option[2] == ' ': + return_list.append(option) + if option[2:] == short_long.get(option.replace('-', '')): + return_list.append(option) + action._formatted_action_invocation = ', '.join(return_list) + return action._formatted_action_invocation + class Conftest(object): """ the single place for accessing values and interacting diff -r 74838a59928dba3d97af1d0214840a1c1556258c -r d32edaabee634a6751782af51da6beeb83deff1d testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -3,6 +3,10 @@ from _pytest import config as parseopt from textwrap import dedent + at pytest.fixture +def parser(): + return parseopt.Parser() + class TestParser: def test_no_help_by_default(self, capsys): parser = parseopt.Parser(usage="xyz") @@ -10,7 +14,7 @@ out, err = capsys.readouterr() assert err.find("error: unrecognized arguments") != -1 - def test_argument(self): + def test_argument(self, parser): with pytest.raises(parseopt.ArgumentError): # need a short or long option argument = parseopt.Argument() @@ -25,7 +29,7 @@ argument = parseopt.Argument('-t', '--test', dest='abc') assert argument.dest == 'abc' - def test_argument_type(self): + def test_argument_type(self, parser): argument = parseopt.Argument('-t', dest='abc', type='int') assert argument.type is int argument = parseopt.Argument('-t', dest='abc', type='string') @@ -46,22 +50,19 @@ assert res['default'] == 42 assert res['dest'] == 'abc' - def test_group_add_and_get(self): - parser = parseopt.Parser() + def test_group_add_and_get(self, parser): group = parser.getgroup("hello", description="desc") assert group.name == "hello" assert group.description == "desc" - def test_getgroup_simple(self): - parser = parseopt.Parser() + def test_getgroup_simple(self, parser): group = parser.getgroup("hello", description="desc") assert group.name == "hello" assert group.description == "desc" group2 = parser.getgroup("hello") assert group2 is group - def test_group_ordering(self): - parser = parseopt.Parser() + def test_group_ordering(self, parser): group0 = parser.getgroup("1") group1 = parser.getgroup("2") group1 = parser.getgroup("3", after="1") @@ -75,8 +76,7 @@ assert len(group.options) == 1 assert isinstance(group.options[0], parseopt.Argument) - def test_group_shortopt_lowercase(self): - parser = parseopt.Parser() + def test_group_shortopt_lowercase(self, parser): group = parser.getgroup("hello") pytest.raises(ValueError, """ group.addoption("-x", action="store_true") @@ -85,27 +85,23 @@ group._addoption("-x", action="store_true") assert len(group.options) == 1 - def test_parser_addoption(self): - parser = parseopt.Parser() + def test_parser_addoption(self, parser): group = parser.getgroup("custom options") assert len(group.options) == 0 group.addoption("--option1", action="store_true") assert len(group.options) == 1 - def test_parse(self): - parser = parseopt.Parser() + def test_parse(self, parser): parser.addoption("--hello", dest="hello", action="store") args = parser.parse(['--hello', 'world']) assert args.hello == "world" assert not getattr(args, parseopt.Config._file_or_dir) - def test_parse2(self): - parser = parseopt.Parser() + def test_parse2(self, parser): args = parser.parse([py.path.local()]) assert getattr(args, parseopt.Config._file_or_dir)[0] == py.path.local() - def test_parse_will_set_default(self): - parser = parseopt.Parser() + def test_parse_will_set_default(self, parser): parser.addoption("--hello", dest="hello", default="x", action="store") option = parser.parse([]) assert option.hello == "x" @@ -113,8 +109,7 @@ args = parser.parse_setoption([], option) assert option.hello == "x" - def test_parse_setoption(self): - parser = parseopt.Parser() + def test_parse_setoption(self, parser): parser.addoption("--hello", dest="hello", action="store") parser.addoption("--world", dest="world", default=42) class A: pass @@ -124,14 +119,12 @@ assert option.world == 42 assert not args - def test_parse_special_destination(self): - parser = parseopt.Parser() + def test_parse_special_destination(self, parser): x = parser.addoption("--ultimate-answer", type=int) args = parser.parse(['--ultimate-answer', '42']) assert args.ultimate_answer == 42 - def test_parse_split_positional_arguments(self): - parser = parseopt.Parser() + def test_parse_split_positional_arguments(self, parser): parser.addoption("-R", action='store_true') parser.addoption("-S", action='store_false') args = parser.parse(['-R', '4', '2', '-S']) @@ -162,6 +155,80 @@ assert option.this == 42 assert option.no is False + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_helper(self): + parser = py.std.argparse.ArgumentParser(formatter_class=parseopt.DropShorterLongHelpFormatter) + parser.add_argument('-t', '--twoword', '--duo', '--two-word', '--two', + help='foo').map_long_option = {'two': 'two-word'} + # throws error on --deux only! + parser.add_argument('-d', '--deuxmots', '--deux-mots', + action='store_true', help='foo').map_long_option = {'deux': 'deux-mots'} + parser.add_argument('-s', action='store_true', help='single short') + parser.add_argument('--abc', '-a', + action='store_true', help='bar') + parser.add_argument('--klm', '-k', '--kl-m', + action='store_true', help='bar') + parser.add_argument('-P', '--pq-r', '-p', '--pqr', + action='store_true', help='bar') + parser.add_argument('--zwei-wort', '--zweiwort', '--zweiwort', + action='store_true', help='bar') + parser.add_argument('-x', '--exit-on-first', '--exitfirst', + action='store_true', help='spam').map_long_option = {'exitfirst': 'exit-on-first'} + parser.add_argument('files_and_dirs', nargs='*') + args = parser.parse_args(['-k', '--duo', 'hallo', '--exitfirst']) + assert args.twoword == 'hallo' + assert args.klm is True + assert args.zwei_wort is False + assert args.exit_on_first is True + assert args.s is False + args = parser.parse_args(['--deux-mots']) + with pytest.raises(AttributeError): + assert args.deux_mots is True + assert args.deuxmots is True + args = parser.parse_args(['file', 'dir']) + assert '|'.join(args.files_and_dirs) == 'file|dir' + + def test_drop_short_0(self, parser): + parser.addoption('--funcarg', '--func-arg', action='store_true') + parser.addoption('--abc-def', '--abc-def', action='store_true') + parser.addoption('--klm-hij', action='store_true') + args = parser.parse(['--funcarg', '--k']) + assert args.funcarg is True + assert args.abc_def is False + assert args.klm_hij is True + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_2(self, parser): + parser.addoption('--func-arg', '--doit', action='store_true') + args = parser.parse(['--doit']) + assert args.func_arg is True + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_3(self, parser): + parser.addoption('--func-arg', '--funcarg', '--doit', action='store_true') + args = parser.parse(['abcd']) + assert args.func_arg is False + assert args.file_or_dir == ['abcd'] + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_help0(self, parser, capsys): + parser.addoption('--func-args', '--doit', help = 'foo', + action='store_true') + parser.parse([]) + help = parser.optparser.format_help() + assert '--func-args, --doit foo' in help + + # testing would be more helpful with all help generated + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_help1(self, parser, capsys): + group = parser.getgroup("general") + group.addoption('--doit', '--func-args', action='store_true', help='foo') + group._addoption("-h", "--help", action="store_true", dest="help", + help="show help message and configuration info") + parser.parse(['-h']) + help = parser.optparser.format_help() + assert '-doit, --func-args foo' in help + @pytest.mark.skipif("sys.version_info < (2,5)") def test_addoption_parser_epilog(testdir): testdir.makeconftest(""" @@ -173,7 +240,7 @@ #assert result.ret != 0 result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) - at pytest.mark.skipif("sys.version_info < (2,5)") + at pytest.mark.skipif("sys.version_info < (2,6)") def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): pytest.skip("bash not available") @@ -196,17 +263,22 @@ monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) - #print dir(result), result.ret if result.ret == 255: # argcomplete not found pytest.skip("argcomplete not available") else: - result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) - + #print 'type ---------------', result.stdout, result.stdout.lines + if py.std.sys.version_info < (2,7): + result.stdout.lines = result.stdout.lines[0].split('\x0b') + result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) + else: + result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) + if py.std.sys.version_info < (2,7): + return os.mkdir('test_argcomplete.d') arg = 'test_argc' monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) - # restore environment + https://bitbucket.org/hpk42/pytest/commits/09aa99de1dec/ Changeset: 09aa99de1dec Branch: opt-drop-non-hyphened-long-options User: Anthon van der Neut Date: 2013-08-01 16:27:06 Summary: removed two superfluous parser arguments Affected #: 1 file diff -r d32edaabee634a6751782af51da6beeb83deff1d -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -14,7 +14,7 @@ out, err = capsys.readouterr() assert err.find("error: unrecognized arguments") != -1 - def test_argument(self, parser): + def test_argument(self): with pytest.raises(parseopt.ArgumentError): # need a short or long option argument = parseopt.Argument() @@ -29,7 +29,7 @@ argument = parseopt.Argument('-t', '--test', dest='abc') assert argument.dest == 'abc' - def test_argument_type(self, parser): + def test_argument_type(self): argument = parseopt.Argument('-t', dest='abc', type='int') assert argument.type is int argument = parseopt.Argument('-t', dest='abc', type='string') https://bitbucket.org/hpk42/pytest/commits/f904134a2cf7/ Changeset: f904134a2cf7 User: hpk42 Date: 2013-08-01 16:33:50 Summary: Merged in anthon_van_der_neut/pytest/opt-drop-non-hyphened-long-options (pull request #56) drop help for long options if longer versions with hyphens are available Affected #: 2 files diff -r 74838a59928dba3d97af1d0214840a1c1556258c -r f904134a2cf7b54738b82b2193ae03063fc5943a _pytest/config.py --- a/_pytest/config.py +++ b/_pytest/config.py @@ -277,7 +277,13 @@ self.parser = parser def addoption(self, *optnames, **attrs): - """ add an option to this group. """ + """ add an option to this group. + + if a shortened version of a long option is specified it will + be suppressed in the help. addoption('--twowords', '--two-words') + results in help showing '--two-words' only, but --twowords gets + accepted **and** the automatic destination is in args.twowords + """ option = Argument(*optnames, **attrs) self._addoption_instance(option, shortupper=False) @@ -299,7 +305,7 @@ def __init__(self, parser): self._parser = parser py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage, - add_help=False) + add_help=False, formatter_class=DropShorterLongHelpFormatter) def format_epilog(self, formatter): hints = self._parser.hints @@ -320,6 +326,67 @@ getattr(args, Config._file_or_dir).extend(argv) return args +# #pylib 2013-07-31 +# (12:05:53) anthon: hynek: can you get me a list of preferred py.test +# long-options with '-' inserted at the right places? +# (12:08:29) hynek: anthon, hpk: generally I'd love the following, decide +# yourself which you agree and which not: +# (12:10:51) hynek: --exit-on-first --full-trace --junit-xml --junit-prefix +# --result-log --collect-only --conf-cut-dir --trace-config +# --no-magic +# (12:18:21) hpk: hynek,anthon: makes sense to me. +# (13:40:30) hpk: hynek: let's not change names, rather only deal with +# hyphens for now +# (13:40:50) hynek: then --exit-first *shrug* + +class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter): + """shorten help for long options that differ only in extra hyphens + + - collapse **long** options that are the same except for extra hyphens + - special action attribute map_long_option allows surpressing additional + long options + - shortcut if there are only two options and one of them is a short one + - cache result on action object as this is called at least 2 times + """ + def _format_action_invocation(self, action): + orgstr = py.std.argparse.HelpFormatter._format_action_invocation(self, action) + if orgstr and orgstr[0] != '-': # only optional arguments + return orgstr + res = getattr(action, '_formatted_action_invocation', None) + if res: + return res + options = orgstr.split(', ') + if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2): + # a shortcut for '-h, --help' or '--abc', '-a' + action._formatted_action_invocation = orgstr + return orgstr + return_list = [] + option_map = getattr(action, 'map_long_option', {}) + if option_map is None: + option_map = {} + short_long = {} + for option in options: + if len(option) == 2 or option[2] == ' ': + continue + if not option.startswith('--'): + raise ArgumentError('long optional argument without "--": [%s]' + % (option), self) + xxoption = option[2:] + if xxoption.split()[0] not in option_map: + shortened = xxoption.replace('-', '') + if shortened not in short_long or \ + len(short_long[shortened]) < len(xxoption): + short_long[shortened] = xxoption + # now short_long has been filled out to the longest with dashes + # **and** we keep the right option ordering from add_argument + for option in options: # + if len(option) == 2 or option[2] == ' ': + return_list.append(option) + if option[2:] == short_long.get(option.replace('-', '')): + return_list.append(option) + action._formatted_action_invocation = ', '.join(return_list) + return action._formatted_action_invocation + class Conftest(object): """ the single place for accessing values and interacting diff -r 74838a59928dba3d97af1d0214840a1c1556258c -r f904134a2cf7b54738b82b2193ae03063fc5943a testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -3,6 +3,10 @@ from _pytest import config as parseopt from textwrap import dedent + at pytest.fixture +def parser(): + return parseopt.Parser() + class TestParser: def test_no_help_by_default(self, capsys): parser = parseopt.Parser(usage="xyz") @@ -46,22 +50,19 @@ assert res['default'] == 42 assert res['dest'] == 'abc' - def test_group_add_and_get(self): - parser = parseopt.Parser() + def test_group_add_and_get(self, parser): group = parser.getgroup("hello", description="desc") assert group.name == "hello" assert group.description == "desc" - def test_getgroup_simple(self): - parser = parseopt.Parser() + def test_getgroup_simple(self, parser): group = parser.getgroup("hello", description="desc") assert group.name == "hello" assert group.description == "desc" group2 = parser.getgroup("hello") assert group2 is group - def test_group_ordering(self): - parser = parseopt.Parser() + def test_group_ordering(self, parser): group0 = parser.getgroup("1") group1 = parser.getgroup("2") group1 = parser.getgroup("3", after="1") @@ -75,8 +76,7 @@ assert len(group.options) == 1 assert isinstance(group.options[0], parseopt.Argument) - def test_group_shortopt_lowercase(self): - parser = parseopt.Parser() + def test_group_shortopt_lowercase(self, parser): group = parser.getgroup("hello") pytest.raises(ValueError, """ group.addoption("-x", action="store_true") @@ -85,27 +85,23 @@ group._addoption("-x", action="store_true") assert len(group.options) == 1 - def test_parser_addoption(self): - parser = parseopt.Parser() + def test_parser_addoption(self, parser): group = parser.getgroup("custom options") assert len(group.options) == 0 group.addoption("--option1", action="store_true") assert len(group.options) == 1 - def test_parse(self): - parser = parseopt.Parser() + def test_parse(self, parser): parser.addoption("--hello", dest="hello", action="store") args = parser.parse(['--hello', 'world']) assert args.hello == "world" assert not getattr(args, parseopt.Config._file_or_dir) - def test_parse2(self): - parser = parseopt.Parser() + def test_parse2(self, parser): args = parser.parse([py.path.local()]) assert getattr(args, parseopt.Config._file_or_dir)[0] == py.path.local() - def test_parse_will_set_default(self): - parser = parseopt.Parser() + def test_parse_will_set_default(self, parser): parser.addoption("--hello", dest="hello", default="x", action="store") option = parser.parse([]) assert option.hello == "x" @@ -113,8 +109,7 @@ args = parser.parse_setoption([], option) assert option.hello == "x" - def test_parse_setoption(self): - parser = parseopt.Parser() + def test_parse_setoption(self, parser): parser.addoption("--hello", dest="hello", action="store") parser.addoption("--world", dest="world", default=42) class A: pass @@ -124,14 +119,12 @@ assert option.world == 42 assert not args - def test_parse_special_destination(self): - parser = parseopt.Parser() + def test_parse_special_destination(self, parser): x = parser.addoption("--ultimate-answer", type=int) args = parser.parse(['--ultimate-answer', '42']) assert args.ultimate_answer == 42 - def test_parse_split_positional_arguments(self): - parser = parseopt.Parser() + def test_parse_split_positional_arguments(self, parser): parser.addoption("-R", action='store_true') parser.addoption("-S", action='store_false') args = parser.parse(['-R', '4', '2', '-S']) @@ -162,6 +155,80 @@ assert option.this == 42 assert option.no is False + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_helper(self): + parser = py.std.argparse.ArgumentParser(formatter_class=parseopt.DropShorterLongHelpFormatter) + parser.add_argument('-t', '--twoword', '--duo', '--two-word', '--two', + help='foo').map_long_option = {'two': 'two-word'} + # throws error on --deux only! + parser.add_argument('-d', '--deuxmots', '--deux-mots', + action='store_true', help='foo').map_long_option = {'deux': 'deux-mots'} + parser.add_argument('-s', action='store_true', help='single short') + parser.add_argument('--abc', '-a', + action='store_true', help='bar') + parser.add_argument('--klm', '-k', '--kl-m', + action='store_true', help='bar') + parser.add_argument('-P', '--pq-r', '-p', '--pqr', + action='store_true', help='bar') + parser.add_argument('--zwei-wort', '--zweiwort', '--zweiwort', + action='store_true', help='bar') + parser.add_argument('-x', '--exit-on-first', '--exitfirst', + action='store_true', help='spam').map_long_option = {'exitfirst': 'exit-on-first'} + parser.add_argument('files_and_dirs', nargs='*') + args = parser.parse_args(['-k', '--duo', 'hallo', '--exitfirst']) + assert args.twoword == 'hallo' + assert args.klm is True + assert args.zwei_wort is False + assert args.exit_on_first is True + assert args.s is False + args = parser.parse_args(['--deux-mots']) + with pytest.raises(AttributeError): + assert args.deux_mots is True + assert args.deuxmots is True + args = parser.parse_args(['file', 'dir']) + assert '|'.join(args.files_and_dirs) == 'file|dir' + + def test_drop_short_0(self, parser): + parser.addoption('--funcarg', '--func-arg', action='store_true') + parser.addoption('--abc-def', '--abc-def', action='store_true') + parser.addoption('--klm-hij', action='store_true') + args = parser.parse(['--funcarg', '--k']) + assert args.funcarg is True + assert args.abc_def is False + assert args.klm_hij is True + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_2(self, parser): + parser.addoption('--func-arg', '--doit', action='store_true') + args = parser.parse(['--doit']) + assert args.func_arg is True + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_3(self, parser): + parser.addoption('--func-arg', '--funcarg', '--doit', action='store_true') + args = parser.parse(['abcd']) + assert args.func_arg is False + assert args.file_or_dir == ['abcd'] + + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_help0(self, parser, capsys): + parser.addoption('--func-args', '--doit', help = 'foo', + action='store_true') + parser.parse([]) + help = parser.optparser.format_help() + assert '--func-args, --doit foo' in help + + # testing would be more helpful with all help generated + @pytest.mark.skipif("sys.version_info < (2,5)") + def test_drop_short_help1(self, parser, capsys): + group = parser.getgroup("general") + group.addoption('--doit', '--func-args', action='store_true', help='foo') + group._addoption("-h", "--help", action="store_true", dest="help", + help="show help message and configuration info") + parser.parse(['-h']) + help = parser.optparser.format_help() + assert '-doit, --func-args foo' in help + @pytest.mark.skipif("sys.version_info < (2,5)") def test_addoption_parser_epilog(testdir): testdir.makeconftest(""" @@ -173,7 +240,7 @@ #assert result.ret != 0 result.stdout.fnmatch_lines(["hint: hello world", "hint: from me too"]) - at pytest.mark.skipif("sys.version_info < (2,5)") + at pytest.mark.skipif("sys.version_info < (2,6)") def test_argcomplete(testdir, monkeypatch): if not py.path.local.sysfind('bash'): pytest.skip("bash not available") @@ -196,17 +263,22 @@ monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len("py.test " + arg))) result = testdir.run('bash', str(script), arg) - #print dir(result), result.ret if result.ret == 255: # argcomplete not found pytest.skip("argcomplete not available") else: - result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) - + #print 'type ---------------', result.stdout, result.stdout.lines + if py.std.sys.version_info < (2,7): + result.stdout.lines = result.stdout.lines[0].split('\x0b') + result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) + else: + result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) + if py.std.sys.version_info < (2,7): + return os.mkdir('test_argcomplete.d') arg = 'test_argc' monkeypatch.setenv('COMP_LINE', "py.test " + arg) monkeypatch.setenv('COMP_POINT', str(len('py.test ' + arg))) result = testdir.run('bash', str(script), arg) result.stdout.fnmatch_lines(["test_argcomplete", "test_argcomplete.d/"]) - # restore environment + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 17:04:22 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 15:04:22 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130801150422.21637.42632@app12.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/8aa6fa3dd62d/ Changeset: 8aa6fa3dd62d Branch: opt-drop-non-hyphened-long-options User: Anthon van der Neut Date: 2013-08-01 16:49:26 Summary: changes to addoption() for hyphenated long-options Affected #: 7 files diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/assertion/__init__.py --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -19,8 +19,8 @@ to provide assert expression information. """) group.addoption('--no-assert', action="store_true", default=False, dest="noassert", help="DEPRECATED equivalent to --assert=plain") - group.addoption('--nomagic', action="store_true", default=False, - dest="nomagic", help="DEPRECATED equivalent to --assert=plain") + group.addoption('--nomagic', '--no-magic', action="store_true", + default=False, help="DEPRECATED equivalent to --assert=plain") class AssertionState: """State for the assertion plugin.""" diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -13,8 +13,8 @@ group._addoption('-p', action="append", dest="plugins", default = [], metavar="name", help="early-load given plugin (multi-allowed).") - group.addoption('--traceconfig', - action="store_true", dest="traceconfig", default=False, + group.addoption('--traceconfig', '--trace-config', + action="store_true", default=False, help="trace considerations of conftest.py files."), group.addoption('--debug', action="store_true", dest="debug", default=False, diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -62,10 +62,10 @@ def pytest_addoption(parser): group = parser.getgroup("terminal reporting") - group.addoption('--junitxml', action="store", dest="xmlpath", - metavar="path", default=None, + group.addoption('--junitxml', '--junit-xml', action="store", + dest="xmlpath", metavar="path", default=None, help="create junit-xml style report file at given path.") - group.addoption('--junitprefix', action="store", dest="junitprefix", + group.addoption('--junitprefix', '--junit-prefix', action="store", metavar="str", default=None, help="prepend prefix to classnames in junit-xml output") diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -41,13 +41,14 @@ help="run pytest in strict mode, warnings become errors.") group = parser.getgroup("collect", "collection") - group.addoption('--collectonly', - action="store_true", dest="collectonly", + group.addoption('--collectonly', '--collect-only', action="store_true", help="only collect tests, don't execute them."), group.addoption('--pyargs', action="store_true", help="try to interpret all arguments as python packages.") group.addoption("--ignore", action="append", metavar="path", help="ignore path during collection (multi-allowed).") + # when changing this to --conf-cut-dir, config.py Conftest.setinitial + # needs upgrading as well group.addoption('--confcutdir', dest="confcutdir", default=None, metavar="dir", help="only load conftest.py's relative to specified dir.") diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/resultlog.py --- a/_pytest/resultlog.py +++ b/_pytest/resultlog.py @@ -6,7 +6,7 @@ def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "resultlog plugin options") - group.addoption('--resultlog', action="store", dest="resultlog", + group.addoption('--resultlog', '--result-log', action="store", metavar="path", default=None, help="path for machine-readable result log.") diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -27,8 +27,8 @@ action="store", dest="tbstyle", default='long', choices=['long', 'short', 'no', 'line', 'native'], help="traceback print mode (long/short/line/native/no).") - group._addoption('--fulltrace', - action="store_true", dest="fulltrace", default=False, + group._addoption('--fulltrace', '--full-trace', + action="store_true", default=False, help="don't cut any tracebacks (default is to cut).") def pytest_configure(config): diff -r 09aa99de1dec81cbab70a4e2648a941a5fb02b18 -r 8aa6fa3dd62d7584484f1820bd58c1a8a8965f6e testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -267,7 +267,6 @@ # argcomplete not found pytest.skip("argcomplete not available") else: - #print 'type ---------------', result.stdout, result.stdout.lines if py.std.sys.version_info < (2,7): result.stdout.lines = result.stdout.lines[0].split('\x0b') result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) https://bitbucket.org/hpk42/pytest/commits/e12f3f5b03ce/ Changeset: e12f3f5b03ce User: hpk42 Date: 2013-08-01 17:04:18 Summary: Merged in anthon_van_der_neut/pytest/opt-drop-non-hyphened-long-options (pull request #57) changes to addoption() for hyphenated long-options Affected #: 7 files diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/assertion/__init__.py --- a/_pytest/assertion/__init__.py +++ b/_pytest/assertion/__init__.py @@ -19,8 +19,8 @@ to provide assert expression information. """) group.addoption('--no-assert', action="store_true", default=False, dest="noassert", help="DEPRECATED equivalent to --assert=plain") - group.addoption('--nomagic', action="store_true", default=False, - dest="nomagic", help="DEPRECATED equivalent to --assert=plain") + group.addoption('--nomagic', '--no-magic', action="store_true", + default=False, help="DEPRECATED equivalent to --assert=plain") class AssertionState: """State for the assertion plugin.""" diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/helpconfig.py --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -13,8 +13,8 @@ group._addoption('-p', action="append", dest="plugins", default = [], metavar="name", help="early-load given plugin (multi-allowed).") - group.addoption('--traceconfig', - action="store_true", dest="traceconfig", default=False, + group.addoption('--traceconfig', '--trace-config', + action="store_true", default=False, help="trace considerations of conftest.py files."), group.addoption('--debug', action="store_true", dest="debug", default=False, diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/junitxml.py --- a/_pytest/junitxml.py +++ b/_pytest/junitxml.py @@ -62,10 +62,10 @@ def pytest_addoption(parser): group = parser.getgroup("terminal reporting") - group.addoption('--junitxml', action="store", dest="xmlpath", - metavar="path", default=None, + group.addoption('--junitxml', '--junit-xml', action="store", + dest="xmlpath", metavar="path", default=None, help="create junit-xml style report file at given path.") - group.addoption('--junitprefix', action="store", dest="junitprefix", + group.addoption('--junitprefix', '--junit-prefix', action="store", metavar="str", default=None, help="prepend prefix to classnames in junit-xml output") diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -41,13 +41,14 @@ help="run pytest in strict mode, warnings become errors.") group = parser.getgroup("collect", "collection") - group.addoption('--collectonly', - action="store_true", dest="collectonly", + group.addoption('--collectonly', '--collect-only', action="store_true", help="only collect tests, don't execute them."), group.addoption('--pyargs', action="store_true", help="try to interpret all arguments as python packages.") group.addoption("--ignore", action="append", metavar="path", help="ignore path during collection (multi-allowed).") + # when changing this to --conf-cut-dir, config.py Conftest.setinitial + # needs upgrading as well group.addoption('--confcutdir', dest="confcutdir", default=None, metavar="dir", help="only load conftest.py's relative to specified dir.") diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/resultlog.py --- a/_pytest/resultlog.py +++ b/_pytest/resultlog.py @@ -6,7 +6,7 @@ def pytest_addoption(parser): group = parser.getgroup("terminal reporting", "resultlog plugin options") - group.addoption('--resultlog', action="store", dest="resultlog", + group.addoption('--resultlog', '--result-log', action="store", metavar="path", default=None, help="path for machine-readable result log.") diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -27,8 +27,8 @@ action="store", dest="tbstyle", default='long', choices=['long', 'short', 'no', 'line', 'native'], help="traceback print mode (long/short/line/native/no).") - group._addoption('--fulltrace', - action="store_true", dest="fulltrace", default=False, + group._addoption('--fulltrace', '--full-trace', + action="store_true", default=False, help="don't cut any tracebacks (default is to cut).") def pytest_configure(config): diff -r f904134a2cf7b54738b82b2193ae03063fc5943a -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 testing/test_parseopt.py --- a/testing/test_parseopt.py +++ b/testing/test_parseopt.py @@ -267,7 +267,6 @@ # argcomplete not found pytest.skip("argcomplete not available") else: - #print 'type ---------------', result.stdout, result.stdout.lines if py.std.sys.version_info < (2,7): result.stdout.lines = result.stdout.lines[0].split('\x0b') result.stdout.fnmatch_lines(["--funcargs", "--fulltrace"]) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 17:36:26 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 15:36:26 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add changelog entry for anthon's hynek-fication of options, Message-ID: <20130801153626.20990.51274@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/a5240a6c897a/ Changeset: a5240a6c897a User: hpk42 Date: 2013-08-01 17:32:19 Summary: add changelog entry for anthon's hynek-fication of options, and change the docs and tests to use the new style. Affected #: 19 files diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,12 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- change to use hyphen-separated long options but keep the old spelling + backward compatible. py.test -h will only show the hyphenated version, + for example "--collect-only" but "--collectonly" will remain valid as well + (for backward-compat reasons). Many thanks to Anthon van der Neut for + the implementation and to Hynek Schlawack for pushing us. + - fix issue279: improve object comparisons on assertion failure for standard datatypes and recognise collections.abc. Thanks to Brianna Laugher and Mathieu Agopian. diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/en/example/nonpython.txt --- a/doc/en/example/nonpython.txt +++ b/doc/en/example/nonpython.txt @@ -72,7 +72,7 @@ While developing your custom test collection and execution it's also interesting to just look at the collection tree:: - nonpython $ py.test --collectonly + nonpython $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 2 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/en/example/parametrize.txt --- a/doc/en/example/parametrize.txt +++ b/doc/en/example/parametrize.txt @@ -114,7 +114,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function:: - $ py.test --collectonly test_scenarios.py + $ py.test --collect-only test_scenarios.py =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 4 items @@ -178,7 +178,7 @@ Let's first see how it looks like at collection time:: - $ py.test test_backends.py --collectonly + $ py.test test_backends.py --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 2 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/en/example/pythoncollection.py --- a/doc/en/example/pythoncollection.py +++ b/doc/en/example/pythoncollection.py @@ -1,5 +1,5 @@ -# run this with $ py.test --collectonly test_collectonly.py +# run this with $ py.test --collect-only test_collectonly.py # def test_function(): pass diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/en/example/pythoncollection.txt --- a/doc/en/example/pythoncollection.txt +++ b/doc/en/example/pythoncollection.txt @@ -41,7 +41,7 @@ then the test collection looks like this:: - $ py.test --collectonly + $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 2 items @@ -80,7 +80,7 @@ You can always peek at the collection tree without running tests like this:: - . $ py.test --collectonly pythoncollection.py + . $ py.test --collect-only pythoncollection.py =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 3 items @@ -133,7 +133,7 @@ then a pytest run on python2 will find the one test when run with a python2 interpreters and will leave out the setup.py file:: - $ py.test --collectonly + $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.3 -- pytest-2.3.5 collected 1 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/en/funcarg_compare.txt --- a/doc/en/funcarg_compare.txt +++ b/doc/en/funcarg_compare.txt @@ -157,7 +157,7 @@ that are never needed because it only co-ordinates the test run activities of the slave processes. -2. if you only perform a collection (with "--collectonly") +2. if you only perform a collection (with "--collect-only") resource-setup will still be executed. 3. If a pytest_sessionstart is contained in some subdirectories @@ -182,7 +182,7 @@ pytest-2.3 takes care to discover fixture/funcarg factories at collection time. This is more efficient especially for large test suites. -Moreover, a call to "py.test --collectonly" should be able to in the future +Moreover, a call to "py.test --collect-only" should be able to in the future show a lot of setup-information and thus presents a nice method to get an overview of fixture management in your project. diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/ja/example/nonpython.txt --- a/doc/ja/example/nonpython.txt +++ b/doc/ja/example/nonpython.txt @@ -101,7 +101,7 @@ ??????????????????????????????????????????????????:: - nonpython $ py.test --collectonly + nonpython $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/ja/example/parametrize.txt --- a/doc/ja/example/parametrize.txt +++ b/doc/ja/example/parametrize.txt @@ -218,7 +218,7 @@ ?????? (?????) ??????????????????? 'advanced' ? 'basic' ??????????:: - $ py.test --collectonly test_scenarios.py + $ py.test --collect-only test_scenarios.py =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items @@ -287,7 +287,7 @@ ???????????????????????????????:: - $ py.test test_backends.py --collectonly + $ py.test test_backends.py --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/ja/example/pythoncollection.py --- a/doc/ja/example/pythoncollection.py +++ b/doc/ja/example/pythoncollection.py @@ -1,5 +1,5 @@ -# run this with $ py.test --collectonly test_collectonly.py +# run this with $ py.test --collect-only test_collectonly.py # def test_function(): pass diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/ja/example/pythoncollection.txt --- a/doc/ja/example/pythoncollection.txt +++ b/doc/ja/example/pythoncollection.txt @@ -68,7 +68,7 @@ ???????????????????:: - $ py.test --collectonly + $ py.test --collect-only =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 2 items @@ -127,7 +127,7 @@ ???????????????????????????????:: - . $ py.test --collectonly pythoncollection.py + . $ py.test --collect-only pythoncollection.py =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 3 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 doc/ja/funcargs.txt --- a/doc/ja/funcargs.txt +++ b/doc/ja/funcargs.txt @@ -273,7 +273,7 @@ ????????? ``numiter`` ??? ``9`` ??????????????? ``pytest_generate_tests(metafunc)`` ????????????????????????????????????????????????????????????????????????????????????:: - $ py.test --collectonly test_example.py + $ py.test --collect-only test_example.py =========================== test session starts ============================ platform linux2 -- Python 2.7.1 -- pytest-2.2.4 collecting ... collected 10 items diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 testing/acceptance_test.py --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -151,7 +151,7 @@ pass """) p = testdir.makepyfile("def test_hello(): pass") - result = testdir.runpytest(p, "--collectonly") + result = testdir.runpytest(p, "--collect-only") result.stdout.fnmatch_lines([ "*MyFile*test_issue88*", "*Module*test_issue88*", diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 testing/python/collect.py --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -414,7 +414,7 @@ """) testdir.makepyfile("def test_some(): pass") testdir.makepyfile(test_xyz="def test_func(): pass") - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "* """) diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 testing/test_collection.py --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -97,7 +97,7 @@ for x in tmpdir.visit("test_*.py"): x.write("def test_hello(): pass") - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") s = result.stdout.str() assert "test_notfound" not in s assert "test_found" in s @@ -252,7 +252,7 @@ """) sub = testdir.mkdir("sub") p = testdir.makepyfile("def test_x(): pass") - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*MyModule*", "*test_x*" @@ -282,7 +282,7 @@ p = testdir.makepyfile("def test_x(): pass") p.copy(sub1.join(p.basename)) p.copy(sub2.join(p.basename)) - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*MyModule1*", "*MyModule2*", diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 testing/test_session.py --- a/testing/test_session.py +++ b/testing/test_session.py @@ -179,7 +179,7 @@ test_three="xxxdsadsadsadsa", __init__="" ) - reprec = testdir.inline_run('--collectonly', p.dirpath()) + reprec = testdir.inline_run('--collect-only', p.dirpath()) itemstarted = reprec.getcalls("pytest_itemcollected") assert len(itemstarted) == 3 @@ -238,5 +238,5 @@ assert l[0] == os.getcwd() """) - res = testdir.runpytest("--collectonly") + res = testdir.runpytest("--collect-only") assert res.ret == 0 diff -r e12f3f5b03ce7a92a06b9e4837a0c3bfa15294e1 -r a5240a6c897a70ff55dc91d05e3f756af2004881 testing/test_terminal.py --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -188,7 +188,7 @@ def test_func(): pass """) - result = testdir.runpytest("--collectonly",) + result = testdir.runpytest("--collect-only",) result.stdout.fnmatch_lines([ "", " ", @@ -199,7 +199,7 @@ import pytest pytest.skip("hello") """) - result = testdir.runpytest("--collectonly", "-rs") + result = testdir.runpytest("--collect-only", "-rs") result.stdout.fnmatch_lines([ "SKIP*hello*", "*1 skip*", @@ -207,7 +207,7 @@ def test_collectonly_failed_module(self, testdir): testdir.makepyfile("""raise ValueError(0)""") - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*raise ValueError*", "*1 error*", @@ -218,7 +218,7 @@ def pytest_collectstart(collector): assert 0, "urgs" """) - result = testdir.runpytest("--collectonly") + result = testdir.runpytest("--collect-only") result.stdout.fnmatch_lines([ "*INTERNAL*args*" ]) @@ -232,7 +232,7 @@ def test_method(self): pass """) - result = testdir.runpytest("--collectonly", p) + result = testdir.runpytest("--collect-only", p) stderr = result.stderr.str().strip() #assert stderr.startswith("inserting into sys.path") assert result.ret == 0 @@ -246,7 +246,7 @@ def test_collectonly_error(self, testdir): p = testdir.makepyfile("import Errlkjqweqwe") - result = testdir.runpytest("--collectonly", p) + result = testdir.runpytest("--collect-only", p) stderr = result.stderr.str().strip() assert result.ret == 1 result.stdout.fnmatch_lines(py.code.Source(""" @@ -261,7 +261,7 @@ failure in parseargs will cause session not to have the items attribute """ - result = testdir.runpytest("--collectonly", "uhm_missing_path") + result = testdir.runpytest("--collect-only", "uhm_missing_path") assert result.ret == 4 result.stderr.fnmatch_lines([ '*ERROR: file not found*', @@ -269,14 +269,14 @@ def test_collectonly_quiet(self, testdir): testdir.makepyfile("def test_foo(): pass") - result = testdir.runpytest("--collectonly", "-q") + result = testdir.runpytest("--collect-only", "-q") result.stdout.fnmatch_lines([ '*test_foo*', ]) def test_collectonly_more_quiet(self, testdir): testdir.makepyfile(test_fun="def test_foo(): pass") - result = testdir.runpytest("--collectonly", "-qq") + result = testdir.runpytest("--collect-only", "-qq") result.stdout.fnmatch_lines([ '*test_fun.py: 1*', ]) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 19:58:38 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 17:58:38 -0000 Subject: [Pytest-commit] commit/pytest: flub: Fix issue 336: autouse fixtures in plugins work again Message-ID: <20130801175838.4328.61222@app13.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/34084c396adc/ Changeset: 34084c396adc User: flub Date: 2013-08-01 19:58:28 Summary: Fix issue 336: autouse fixtures in plugins work again When an autouse fixture in a plugin was encountered None was stored as nodeid where it used to be ''. This broke the lookup of autouse fixtures later on. This also adds another test for the normal fixture ordering which was slightly wrong: a fixture without location was always added at the front of the fixture list rather then at the end of the fixtures without location but before the fixtures with location. Affected #: 2 files diff -r a5240a6c897a70ff55dc91d05e3f756af2004881 -r 34084c396adc9a79f43dfe7eadffb7f1f2ce7a7e _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1626,18 +1626,18 @@ unittest=unittest) faclist = self._arg2fixturedefs.setdefault(name, []) if not fixturedef.has_location: - # All Nones are at the front so this inserts the - # current fixturedef after the existing fixturedefs - # from external plugins but before the fixturedefs - # provided in conftests. - i = faclist.count(None) + # All fixturedefs with no location are at the front + # so this inserts the current fixturedef after the + # existing fixturedefs from external plugins but + # before the fixturedefs provided in conftests. + i = len([f for f in faclist if not f.has_location]) else: i = len(faclist) # append faclist.insert(i, fixturedef) if marker.autouse: autousenames.append(name) if autousenames: - self._nodeid_and_autousenames.append((nodeid, autousenames)) + self._nodeid_and_autousenames.append((nodeid or '', autousenames)) def getfixturedefs(self, argname, nodeid): try: diff -r a5240a6c897a70ff55dc91d05e3f756af2004881 -r 34084c396adc9a79f43dfe7eadffb7f1f2ce7a7e testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -173,7 +173,7 @@ result = testdir.runpytest(testfile) result.stdout.fnmatch_lines(["*1 passed*"]) - def test_extend_fixture_conftest_plugin(request, testdir): + def test_extend_fixture_conftest_plugin(self, testdir): testdir.makepyfile(testplugin=""" import pytest @@ -198,6 +198,52 @@ result = testdir.runpytest('-s') assert result.ret == 0 + def test_extend_fixture_plugin_plugin(self, testdir): + # Two plugins should extend each order in loading order + testdir.makepyfile(testplugin0=""" + import pytest + + @pytest.fixture + def foo(): + return 7 + """) + testdir.makepyfile(testplugin1=""" + import pytest + + @pytest.fixture + def foo(foo): + return foo + 7 + """) + testdir.syspathinsert() + testdir.makepyfile(""" + pytest_plugins = ['testplugin0', 'testplugin1'] + + def test_foo(foo): + assert foo == 14 + """) + result = testdir.runpytest() + assert result.ret == 0 + + def test_autouse_fixture_plugin(self, testdir): + # A fixture from a plugin has no baseid set, which screwed up + # the autouse fixture handling. + testdir.makepyfile(testplugin=""" + import pytest + + @pytest.fixture(autouse=True) + def foo(request): + request.function.foo = 7 + """) + testdir.syspathinsert() + testdir.makepyfile(""" + pytest_plugins = 'testplugin' + + def test_foo(request): + assert request.function.foo == 7 + """) + result = testdir.runpytest() + assert result.ret == 0 + def test_funcarg_lookup_error(self, testdir): p = testdir.makepyfile(""" def test_lookup_error(unknown): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 20:04:13 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 18:04:13 -0000 Subject: [Pytest-commit] commit/pytest: flub: mention fix for issue 336 in changelog Message-ID: <20130801180413.14024.66985@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/ceb62a876e9d/ Changeset: ceb62a876e9d User: flub Date: 2013-08-01 20:03:53 Summary: mention fix for issue 336 in changelog Affected #: 1 file diff -r 34084c396adc9a79f43dfe7eadffb7f1f2ce7a7e -r ceb62a876e9d62fdf2d60417c28c18a87726a437 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- fix issue336: autouse fixture in plugins should work again. + - change to use hyphen-separated long options but keep the old spelling backward compatible. py.test -h will only show the hyphenated version, for example "--collect-only" but "--collectonly" will remain valid as well Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 22:56:48 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 20:56:48 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130801205648.28568.10361@app06.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/6509bce52d28/ Changeset: 6509bce52d28 User: RonnyPfannschmidt Date: 2013-08-01 22:11:18 Summary: fix issue317: assertion rewriter support for the is_package method Affected #: 3 files diff -r a5240a6c897a70ff55dc91d05e3f756af2004881 -r 6509bce52d28f04b413a42429d38187602a13ed2 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,8 @@ for standard datatypes and recognise collections.abc. Thanks to Brianna Laugher and Mathieu Agopian. +- fix issue317: assertion rewriter support for the is_package method + - fix issue335: document py.code.ExceptionInfo() object returned from pytest.raises(), thanks Mathieu Agopian. diff -r a5240a6c897a70ff55dc91d05e3f756af2004881 -r 6509bce52d28f04b413a42429d38187602a13ed2 _pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -150,12 +150,25 @@ mod.__file__ = co.co_filename # Normally, this attribute is 3.2+. mod.__cached__ = pyc + mod.__loader__ = self py.builtin.exec_(co, mod.__dict__) except: del sys.modules[name] raise return sys.modules[name] + + + def is_package(self, name): + try: + fd, fn, desc = imp.find_module(name) + except ImportError: + return False + if fd is not None: + fd.close() + tp = desc[2] + return tp == imp.PKG_DIRECTORY + def _write_pyc(state, co, source_path, pyc): # Technically, we don't have to have the same pyc format as # (C)Python, since these "pycs" should never be seen by builtin diff -r a5240a6c897a70ff55dc91d05e3f756af2004881 -r 6509bce52d28f04b413a42429d38187602a13ed2 testing/test_assertrewrite.py --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -412,6 +412,36 @@ testdir.tmpdir.join("test_newlines.py").write(b, "wb") assert testdir.runpytest().ret == 0 + +class TestAssertionRewriteHookDetails(object): + def test_loader_is_package_false_for_module(self, testdir): + testdir.makepyfile(test_fun=""" + def test_loader(): + assert not __loader__.is_package(__name__) + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "* 1 passed*", + ]) + + def test_loader_is_package_true_for_package(self, testdir): + testdir.makepyfile(test_fun=""" + def test_loader(): + assert not __loader__.is_package(__name__) + + def test_fun(): + assert __loader__.is_package('fun') + + def test_missing(): + assert not __loader__.is_package('pytest_not_there') + """) + pkg = testdir.mkpydir('fun') + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + '* 3 passed*', + ]) + + @pytest.mark.skipif("sys.version_info[0] >= 3") def test_assume_ascii(self, testdir): content = "u'\xe2\x99\xa5'" https://bitbucket.org/hpk42/pytest/commits/9125613a1821/ Changeset: 9125613a1821 User: RonnyPfannschmidt Date: 2013-08-01 22:55:16 Summary: merge Affected #: 3 files diff -r 6509bce52d28f04b413a42429d38187602a13ed2 -r 9125613a1821649a71162cc7f3635d63d3be3e4b CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- fix issue336: autouse fixture in plugins should work again. + - change to use hyphen-separated long options but keep the old spelling backward compatible. py.test -h will only show the hyphenated version, for example "--collect-only" but "--collectonly" will remain valid as well diff -r 6509bce52d28f04b413a42429d38187602a13ed2 -r 9125613a1821649a71162cc7f3635d63d3be3e4b _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1626,18 +1626,18 @@ unittest=unittest) faclist = self._arg2fixturedefs.setdefault(name, []) if not fixturedef.has_location: - # All Nones are at the front so this inserts the - # current fixturedef after the existing fixturedefs - # from external plugins but before the fixturedefs - # provided in conftests. - i = faclist.count(None) + # All fixturedefs with no location are at the front + # so this inserts the current fixturedef after the + # existing fixturedefs from external plugins but + # before the fixturedefs provided in conftests. + i = len([f for f in faclist if not f.has_location]) else: i = len(faclist) # append faclist.insert(i, fixturedef) if marker.autouse: autousenames.append(name) if autousenames: - self._nodeid_and_autousenames.append((nodeid, autousenames)) + self._nodeid_and_autousenames.append((nodeid or '', autousenames)) def getfixturedefs(self, argname, nodeid): try: diff -r 6509bce52d28f04b413a42429d38187602a13ed2 -r 9125613a1821649a71162cc7f3635d63d3be3e4b testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -173,7 +173,7 @@ result = testdir.runpytest(testfile) result.stdout.fnmatch_lines(["*1 passed*"]) - def test_extend_fixture_conftest_plugin(request, testdir): + def test_extend_fixture_conftest_plugin(self, testdir): testdir.makepyfile(testplugin=""" import pytest @@ -198,6 +198,52 @@ result = testdir.runpytest('-s') assert result.ret == 0 + def test_extend_fixture_plugin_plugin(self, testdir): + # Two plugins should extend each order in loading order + testdir.makepyfile(testplugin0=""" + import pytest + + @pytest.fixture + def foo(): + return 7 + """) + testdir.makepyfile(testplugin1=""" + import pytest + + @pytest.fixture + def foo(foo): + return foo + 7 + """) + testdir.syspathinsert() + testdir.makepyfile(""" + pytest_plugins = ['testplugin0', 'testplugin1'] + + def test_foo(foo): + assert foo == 14 + """) + result = testdir.runpytest() + assert result.ret == 0 + + def test_autouse_fixture_plugin(self, testdir): + # A fixture from a plugin has no baseid set, which screwed up + # the autouse fixture handling. + testdir.makepyfile(testplugin=""" + import pytest + + @pytest.fixture(autouse=True) + def foo(request): + request.function.foo = 7 + """) + testdir.syspathinsert() + testdir.makepyfile(""" + pytest_plugins = 'testplugin' + + def test_foo(request): + assert request.function.foo == 7 + """) + result = testdir.runpytest() + assert result.ret == 0 + def test_funcarg_lookup_error(self, testdir): p = testdir.makepyfile(""" def test_lookup_error(unknown): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 23:09:36 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 21:09:36 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130801210936.23465.10030@app04.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/289f91475450/ Changeset: 289f91475450 Branch: doctest-fixtures User: RonnyPfannschmidt Date: 2013-08-01 23:07:25 Summary: close merged branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/1a26880c7a2a/ Changeset: 1a26880c7a2a Branch: ctheune/typo-1372873724648 User: RonnyPfannschmidt Date: 2013-08-01 23:07:50 Summary: close merged branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/de6ebd15864c/ Changeset: de6ebd15864c Branch: travis-integration User: RonnyPfannschmidt Date: 2013-08-01 23:08:13 Summary: close merged branch Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 23:11:09 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 21:11:09 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130801211109.18650.85846@app10.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/bd6f4d858f28/ Changeset: bd6f4d858f28 Branch: 329-skipif-requires-expression-as-a-string User: RonnyPfannschmidt Date: 2013-08-01 23:09:34 Summary: close merged branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/d4a87f02f77d/ Changeset: d4a87f02f77d Branch: argparse User: RonnyPfannschmidt Date: 2013-08-01 23:09:45 Summary: close merged branch Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 1 23:55:31 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 21:55:31 -0000 Subject: [Pytest-commit] commit/pytest: magopian: refs #322: setUpClass and tearDownClass as autouse fixture and finalizer Message-ID: <20130801215531.30160.95094@app01.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/4f2b83a6082c/ Changeset: 4f2b83a6082c User: magopian Date: 2013-08-01 23:48:40 Summary: refs #322: setUpClass and tearDownClass as autouse fixture and finalizer Affected #: 4 files diff -r 9125613a1821649a71162cc7f3635d63d3be3e4b -r 4f2b83a6082cffe3ddec003703480611b9f5062b _pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -11,6 +11,12 @@ from py.builtin import print_ from _pytest.core import HookRelay + +def get_public_names(l): + """Only return names from iterator l without a leading underscore.""" + return [x for x in l if x[0] != "_"] + + def pytest_addoption(parser): group = parser.getgroup("pylib") group.addoption('--no-tools-on-path', diff -r 9125613a1821649a71162cc7f3635d63d3be3e4b -r 4f2b83a6082cffe3ddec003703480611b9f5062b _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -5,19 +5,38 @@ # for transfering markers from _pytest.python import transfer_markers -def pytest_pycollect_makeitem(collector, name, obj): + +def is_unittest(obj): + """Is obj a subclass of unittest.TestCase?""" unittest = sys.modules.get('unittest') if unittest is None: - return # nobody can have derived unittest.TestCase + return # nobody can have derived unittest.TestCase try: - isunit = issubclass(obj, unittest.TestCase) + return issubclass(obj, unittest.TestCase) except KeyboardInterrupt: raise - except Exception: - pass - else: - if isunit: - return UnitTestCase(name, parent=collector) + except: + return False + + + at pytest.fixture(scope='class', autouse=True) +def _xunit_setUpClass(request): + """Add support for unittest.TestCase setUpClass and tearDownClass.""" + if not is_unittest(request.cls): + return # only support setUpClass / tearDownClass for unittest.TestCase + if getattr(request.cls, '__unittest_skip__', False): + return # skipped + setup = getattr(request.cls, 'setUpClass', None) + teardown = getattr(request.cls, 'tearDownClass', None) + setup() + if teardown is not None: + request.addfinalizer(teardown) + + +def pytest_pycollect_makeitem(collector, name, obj): + if is_unittest(obj): + return UnitTestCase(name, parent=collector) + class UnitTestCase(pytest.Class): nofuncargs = True # marker for fixturemanger.getfixtureinfo() @@ -45,21 +64,7 @@ if ut is None or runtest != ut.TestCase.runTest: yield TestCaseFunction('runTest', parent=self) - def setup(self): - if getattr(self.obj, '__unittest_skip__', False): - return - meth = getattr(self.obj, 'setUpClass', None) - if meth is not None: - meth() - super(UnitTestCase, self).setup() - def teardown(self): - if getattr(self.obj, '__unittest_skip__', False): - return - meth = getattr(self.obj, 'tearDownClass', None) - if meth is not None: - meth() - super(UnitTestCase, self).teardown() class TestCaseFunction(pytest.Function): _excinfo = None diff -r 9125613a1821649a71162cc7f3635d63d3be3e4b -r 4f2b83a6082cffe3ddec003703480611b9f5062b testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1,6 +1,8 @@ import pytest, py, sys from _pytest import python as funcargs from _pytest.python import FixtureLookupError +from _pytest.pytester import get_public_names + def test_getfuncargnames(): def f(): pass @@ -50,7 +52,7 @@ """) funcargs.fillfixtures(item) del item.funcargs["request"] - assert len(item.funcargs) == 2 + assert len(get_public_names(item.funcargs)) == 2 assert item.funcargs['some'] == "test_func" assert item.funcargs['other'] == 42 @@ -334,7 +336,7 @@ assert val2 == 2 pytest._fillfuncargs(item) assert item.funcargs["something"] == 1 - assert len(item.funcargs) == 2 + assert len(get_public_names(item.funcargs)) == 2 assert "request" in item.funcargs #assert item.funcargs == {'something': 1, "other": 2} @@ -412,6 +414,7 @@ def test_request_fixturenames(self, testdir): testdir.makepyfile(""" import pytest + from _pytest.pytester import get_public_names @pytest.fixture() def arg1(): pass @@ -422,7 +425,7 @@ def sarg(tmpdir): pass def test_function(request, farg): - assert set(request.fixturenames) == \ + assert set(get_public_names(request.fixturenames)) == \ set(["tmpdir", "sarg", "arg1", "request", "farg"]) """) reprec = testdir.inline_run() @@ -831,6 +834,8 @@ l = reprec.getfailedcollections() assert len(l) == 1 + @pytest.mark.xfail(reason="unclear if it should be supported at all, " + "currently broken") def test_request_can_be_overridden(self, testdir): testdir.makepyfile(""" import pytest @@ -995,9 +1000,10 @@ def test_parsefactories_conftest(self, testdir): testdir.makepyfile(""" + from _pytest.pytester import get_public_names def test_check_setup(item, fm): autousenames = fm._getautousenames(item.nodeid) - assert len(autousenames) == 2 + assert len(get_public_names(autousenames)) == 2 assert "perfunction2" in autousenames assert "perfunction" in autousenames """) diff -r 9125613a1821649a71162cc7f3635d63d3be3e4b -r 4f2b83a6082cffe3ddec003703480611b9f5062b testing/test_unittest.py --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -118,7 +118,7 @@ assert passed == 2 assert passed + skipped + failed == 2 - at pytest.mark.skipif("sys.version_info < (3,1)") + at pytest.mark.skipif("sys.version_info < (2,7)") def test_unittest_skip_issue148(testdir): testpath = testdir.makepyfile(""" import unittest @@ -586,3 +586,53 @@ """) result = testdir.runpytest() result.stdout.fnmatch_lines("*3 passed*") + + +def test_non_unittest_no_setupclass_support(testdir): + testpath = testdir.makepyfile(""" + class TestFoo: + x = 0 + + @classmethod + def setUpClass(cls): + cls.x = 1 + + def test_method1(self): + assert self.x == 0 + + @classmethod + def tearDownClass(cls): + cls.x = 1 + + def test_not_teareddown(): + assert TestFoo.x == 0 + + """) + reprec = testdir.inline_run(testpath) + reprec.assertoutcome(passed=2) + + +def test_no_teardown_if_setupclass_failed(testdir): + testpath = testdir.makepyfile(""" + import unittest + + class MyTestCase(unittest.TestCase): + x = 0 + + @classmethod + def setUpClass(cls): + cls.x = 1 + assert False + + def test_func1(self): + cls.x = 10 + + @classmethod + def tearDownClass(cls): + cls.x = 100 + + def test_notTornDown(): + assert MyTestCase.x == 1 + """) + reprec = testdir.inline_run(testpath) + reprec.assertoutcome(passed=1, failed=1) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Aug 2 00:02:40 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 01 Aug 2013 22:02:40 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix issue322: tearDownClass is not run if setUpClass failed. Thanks Message-ID: <20130801220240.7584.12180@app11.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/44f1eaaf106f/ Changeset: 44f1eaaf106f User: hpk42 Date: 2013-08-02 00:02:28 Summary: fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for fixing. The patch moves handling setUpClass into a new autofixture. (XXX impl-decide if rather adding addfinalizer() API to node's would have a similar effect) Affected #: 2 files diff -r 4f2b83a6082cffe3ddec003703480611b9f5062b -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- fix issue322: tearDownClass is not run if setUpClass failed. Thanks + Mathieu Agopian for fixing. The patch moves handling setUpClass + into a new autofixture. (XXX impl-decide if rather adding addfinalizer() + API to node's would have a similar effect) + - fix issue336: autouse fixture in plugins should work again. - change to use hyphen-separated long options but keep the old spelling diff -r 4f2b83a6082cffe3ddec003703480611b9f5062b -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -28,7 +28,8 @@ return # skipped setup = getattr(request.cls, 'setUpClass', None) teardown = getattr(request.cls, 'tearDownClass', None) - setup() + if setup is not None: + setup() if teardown is not None: request.addfinalizer(teardown) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Fri Aug 2 09:11:52 2013 From: notifications at travis-ci.org (Travis CI) Date: Fri, 02 Aug 2013 07:11:52 +0000 Subject: [Pytest-commit] [Failed] bubenkoff/pytest#8 (py25-tox-fix - 65f91cc) Message-ID: <51fb5bb76e5a0_22099c247319@0a12d6ac-2d92-4712-aa24-df0f68b86bd1.mail> Build Update for bubenkoff/pytest ------------------------------------- Build: #8 Status: Failed Duration: 4 minutes and 39 seconds Commit: 65f91cc (py25-tox-fix) Author: Anatoly Bubenkov Message: py25 test env fixes View the changeset: https://github.com/bubenkoff/pytest/commit/65f91cceb2e6 View the full build log and details: https://travis-ci.org/bubenkoff/pytest/builds/9764853 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Fri Aug 2 09:52:54 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 02 Aug 2013 07:52:54 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: ref #322 cleanup all teardown calling to only happen when setup succeeded. Message-ID: <20130802075254.30505.2563@app05.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/a36faafd111e/ Changeset: a36faafd111e User: hpk42 Date: 2013-08-02 09:52:40 Summary: ref #322 cleanup all teardown calling to only happen when setup succeeded. don't use autouse fixtures for now because it would cause a proliferation and overhead for the execution of every test. Rather introduce a node.addfinalizer(fin) to attach a finalizer to the respective node and call it from node.setup() functions if the setup phase succeeded (i.e. there is no setup function or it finished successfully) Affected #: 10 files diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,10 @@ ----------------------------------- - fix issue322: tearDownClass is not run if setUpClass failed. Thanks - Mathieu Agopian for fixing. The patch moves handling setUpClass - into a new autofixture. (XXX impl-decide if rather adding addfinalizer() - API to node's would have a similar effect) + Mathieu Agopian for the initial fix. Also make all of pytest/nose finalizer + mimick the same generic behaviour: if a setupX exists and fails, + don't run teardownX. This also introduces a new method "node.addfinalizer()" + helper which can only be called during the setup phase of a node. - fix issue336: autouse fixture in plugins should work again. diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 _pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.4.0.dev8' +__version__ = '2.4.0.dev10' diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -41,7 +41,7 @@ help="run pytest in strict mode, warnings become errors.") group = parser.getgroup("collect", "collection") - group.addoption('--collectonly', '--collect-only', action="store_true", + group.addoption('--collectonly', '--collect-only', action="store_true", help="only collect tests, don't execute them."), group.addoption('--pyargs', action="store_true", help="try to interpret all arguments as python packages.") @@ -326,6 +326,14 @@ def getplugins(self): return self.config._getmatchingplugins(self.fspath) + def addfinalizer(self, fin): + """ register a function to be called when this node is finalized. + + This method can only be called when this node is active + in a setup chain, for example during self.setup(). + """ + self.session._setupstate.addfinalizer(fin, self) + def getparent(self, cls): current = self while current and not isinstance(current, cls): diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -384,19 +384,19 @@ setup_module(self.obj) else: setup_module() - - def teardown(self): - teardown_module = xunitsetup(self.obj, 'tearDownModule') - if teardown_module is None: - teardown_module = xunitsetup(self.obj, 'teardown_module') - if teardown_module is not None: + fin = getattr(self.obj, 'tearDownModule', None) + if fin is None: + fin = getattr(self.obj, 'teardown_module', None) + if fin is not None: #XXX: nose compat hack, move to nose plugin # if it takes a positional arg, its probably a py.test style one # so we pass the current module object - if inspect.getargspec(teardown_module)[0]: - teardown_module(self.obj) + if inspect.getargspec(fin)[0]: + finalizer = lambda: fin(self.obj) else: - teardown_module() + finalizer = fin + self.addfinalizer(finalizer) + class Class(PyCollector): """ Collector for test methods. """ @@ -415,12 +415,11 @@ setup_class = getattr(setup_class, '__func__', setup_class) setup_class(self.obj) - def teardown(self): - teardown_class = xunitsetup(self.obj, 'teardown_class') - if teardown_class is not None: - teardown_class = getattr(teardown_class, 'im_func', teardown_class) - teardown_class = getattr(teardown_class, '__func__', teardown_class) - teardown_class(self.obj) + fin_class = getattr(self.obj, 'teardown_class', None) + if fin_class is not None: + fin_class = getattr(fin_class, 'im_func', fin_class) + fin_class = getattr(fin_class, '__func__', fin_class) + self.addfinalizer(lambda: fin_class(self.obj)) class Instance(PyCollector): def _getobj(self): @@ -449,23 +448,17 @@ else: obj = self.parent.obj if inspect.ismethod(self.obj): - name = 'setup_method' + setup_name = 'setup_method' + teardown_name = 'teardown_method' else: - name = 'setup_function' - setup_func_or_method = xunitsetup(obj, name) + setup_name = 'setup_function' + teardown_name = 'teardown_function' + setup_func_or_method = xunitsetup(obj, setup_name) if setup_func_or_method is not None: setup_func_or_method(self.obj) - - def teardown(self): - """ perform teardown for this test function. """ - if inspect.ismethod(self.obj): - name = 'teardown_method' - else: - name = 'teardown_function' - obj = self.parent.obj - teardown_func_or_meth = xunitsetup(obj, name) - if teardown_func_or_meth is not None: - teardown_func_or_meth(self.obj) + fin = getattr(obj, teardown_name, None) + if fin is not None: + self.addfinalizer(lambda: fin(self.obj)) def _prunetraceback(self, excinfo): if hasattr(self, '_obj') and not self.config.option.fulltrace: diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -19,21 +19,6 @@ return False - at pytest.fixture(scope='class', autouse=True) -def _xunit_setUpClass(request): - """Add support for unittest.TestCase setUpClass and tearDownClass.""" - if not is_unittest(request.cls): - return # only support setUpClass / tearDownClass for unittest.TestCase - if getattr(request.cls, '__unittest_skip__', False): - return # skipped - setup = getattr(request.cls, 'setUpClass', None) - teardown = getattr(request.cls, 'tearDownClass', None) - if setup is not None: - setup() - if teardown is not None: - request.addfinalizer(teardown) - - def pytest_pycollect_makeitem(collector, name, obj): if is_unittest(obj): return UnitTestCase(name, parent=collector) @@ -42,6 +27,18 @@ class UnitTestCase(pytest.Class): nofuncargs = True # marker for fixturemanger.getfixtureinfo() # to declare that our children do not support funcargs + # + def setup(self): + cls = self.obj + if getattr(cls, '__unittest_skip__', False): + return # skipped + setup = getattr(cls, 'setUpClass', None) + if setup is not None: + setup() + teardown = getattr(cls, 'tearDownClass', None) + if teardown is not None: + self.addfinalizer(teardown) + super(UnitTestCase, self).setup() def collect(self): self.session._fixturemanager.parsefactories(self, unittest=True) diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 doc/en/xunit_setup.txt --- a/doc/en/xunit_setup.txt +++ b/doc/en/xunit_setup.txt @@ -13,8 +13,15 @@ supported you may also use pytest's more powerful :ref:`fixture mechanism ` which leverages the concept of dependency injection, allowing for a more modular and more scalable approach for managing test state, -especially for larger projects and for functional testing. It is safe -to mix both fixture mechanisms. +especially for larger projects and for functional testing. You can +mix both fixture mechanisms in the same file but unittest-based +test methods cannot receive fixture arguments. + +.. note:: + + As of pytest-2.4, teardownX functions are not called if + setupX existed and failed/was skipped. This harmonizes + behaviour across all major python testing tools. Module level setup/teardown -------------------------------------- diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 setup.py --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.4.0.dev8', + version='2.4.0.dev10', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 testing/python/fixture.py --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -834,8 +834,6 @@ l = reprec.getfailedcollections() assert len(l) == 1 - @pytest.mark.xfail(reason="unclear if it should be supported at all, " - "currently broken") def test_request_can_be_overridden(self, testdir): testdir.makepyfile(""" import pytest diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 testing/test_runner_xunit.py --- a/testing/test_runner_xunit.py +++ b/testing/test_runner_xunit.py @@ -32,6 +32,39 @@ rep = reprec.matchreport("test_module") assert rep.passed +def test_module_setup_failure_no_teardown(testdir): + reprec = testdir.inline_runsource(""" + l = [] + def setup_module(module): + l.append(1) + 0/0 + + def test_nothing(): + pass + + def teardown_module(module): + l.append(2) + """) + reprec.assertoutcome(failed=1) + calls = reprec.getcalls("pytest_runtest_setup") + assert calls[0].item.module.l == [1] + +def test_setup_function_failure_no_teardown(testdir): + reprec = testdir.inline_runsource(""" + modlevel = [] + def setup_function(function): + modlevel.append(1) + 0/0 + + def teardown_function(module): + modlevel.append(2) + + def test_func(): + pass + """) + calls = reprec.getcalls("pytest_runtest_setup") + assert calls[0].item.module.modlevel == [1] + def test_class_setup(testdir): reprec = testdir.inline_runsource(""" class TestSimpleClassSetup: @@ -55,6 +88,23 @@ """) reprec.assertoutcome(passed=1+2+1) +def test_class_setup_failure_no_teardown(testdir): + reprec = testdir.inline_runsource(""" + class TestSimpleClassSetup: + clslevel = [] + def setup_class(cls): + 0/0 + + def teardown_class(cls): + cls.clslevel.append(1) + + def test_classlevel(self): + pass + + def test_cleanup(): + assert not TestSimpleClassSetup.clslevel + """) + reprec.assertoutcome(failed=1, passed=1) def test_method_setup(testdir): reprec = testdir.inline_runsource(""" @@ -72,6 +122,25 @@ """) reprec.assertoutcome(passed=2) +def test_method_setup_failure_no_teardown(testdir): + reprec = testdir.inline_runsource(""" + class TestMethodSetup: + clslevel = [] + def setup_method(self, method): + self.clslevel.append(1) + 0/0 + + def teardown_method(self, method): + self.clslevel.append(2) + + def test_method(self): + pass + + def test_cleanup(): + assert TestMethodSetup.clslevel == [1] + """) + reprec.assertoutcome(failed=1, passed=1) + def test_method_generator_setup(testdir): reprec = testdir.inline_runsource(""" class TestSetupTeardownOnInstance: @@ -134,23 +203,7 @@ """) reprec.assertoutcome(passed=2, failed=0) -def test_failing_setup_calls_teardown(testdir): - p = testdir.makepyfile(""" - def setup_module(mod): - raise ValueError(42) - def test_function(): - assert 0 - def teardown_module(mod): - raise ValueError(43) - """) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines([ - "*42*", - "*43*", - "*2 error*" - ]) - -def test_setup_that_skips_calledagain_and_teardown(testdir): +def test_setup_that_skips_calledagain(testdir): p = testdir.makepyfile(""" import pytest def setup_module(mod): @@ -159,14 +212,9 @@ pass def test_function2(): pass - def teardown_module(mod): - raise ValueError(43) """) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines([ - "*ValueError*43*", - "*2 skipped*1 error*", - ]) + reprec = testdir.inline_run(p) + reprec.assertoutcome(skipped=2) def test_setup_fails_again_on_all_tests(testdir): p = testdir.makepyfile(""" @@ -177,14 +225,9 @@ pass def test_function2(): pass - def teardown_module(mod): - raise ValueError(43) """) - result = testdir.runpytest(p) - result.stdout.fnmatch_lines([ - "*3 error*" - ]) - assert "passed" not in result.stdout.str() + reprec = testdir.inline_run(p) + reprec.assertoutcome(failed=2) def test_setup_funcarg_setup_when_outer_scope_fails(testdir): p = testdir.makepyfile(""" @@ -207,6 +250,3 @@ "*2 error*" ]) assert "xyz43" not in result.stdout.str() - - - diff -r 44f1eaaf106f677b20f1c0fb6220fe198d9164ed -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 testing/test_unittest.py --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -65,7 +65,7 @@ rep = reprec.matchreport("test_both", when="teardown") assert rep.failed and '42' in str(rep.longrepr) -def test_unittest_style_setup_teardown(testdir): +def test_setUpModule(testdir): testpath = testdir.makepyfile(""" l = [] @@ -86,6 +86,23 @@ "*2 passed*", ]) +def test_setUpModule_failing_no_teardown(testdir): + testpath = testdir.makepyfile(""" + l = [] + + def setUpModule(): + 0/0 + + def tearDownModule(): + l.append(1) + + def test_hello(): + pass + """) + reprec = testdir.inline_run(testpath) + reprec.assertoutcome(passed=0, failed=1) + call = reprec.getcalls("pytest_runtest_setup")[0] + assert not call.item.module.l def test_new_instances(testdir): testpath = testdir.makepyfile(""" @@ -636,3 +653,4 @@ """) reprec = testdir.inline_run(testpath) reprec.assertoutcome(passed=1, failed=1) + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Fri Aug 2 09:40:59 2013 From: notifications at travis-ci.org (Travis CI) Date: Fri, 02 Aug 2013 07:40:59 +0000 Subject: [Pytest-commit] [Fixed] bubenkoff/pytest#9 (py25-tox-fix - 0d0c2c6) Message-ID: <51fb628b48ff8_249be5e2519a5@0a12d6ac-2d92-4712-aa24-df0f68b86bd1.mail> Build Update for bubenkoff/pytest ------------------------------------- Build: #9 Status: Fixed Duration: 4 minutes and 30 seconds Commit: 0d0c2c6 (py25-tox-fix) Author: Anatoly Bubenkov Message: correct skip condition for autocomplete View the changeset: https://github.com/bubenkoff/pytest/compare/65f91cceb2e6...0d0c2c650fab View the full build log and details: https://travis-ci.org/bubenkoff/pytest/builds/9765330 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From notifications at travis-ci.org Fri Aug 2 09:11:58 2013 From: notifications at travis-ci.org (Travis CI) Date: Fri, 02 Aug 2013 07:11:58 +0000 Subject: [Pytest-commit] [Failed] bubenkoff/pytest#7 (master - 9c7f046) Message-ID: <51fb5bbde3c88_27f154e247594@0a12d6ac-2d92-4712-aa24-df0f68b86bd1.mail> Build Update for bubenkoff/pytest ------------------------------------- Build: #7 Status: Failed Duration: 5 minutes and 4 seconds Commit: 9c7f046 (master) Author: Floris Bruynooghe Message: Close issue 279: improved assertrepr_compare View the changeset: https://github.com/bubenkoff/pytest/compare/14a19c88d819...9c7f046e0961 View the full build log and details: https://travis-ci.org/bubenkoff/pytest/builds/9764851 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From notifications at travis-ci.org Fri Aug 2 10:05:13 2013 From: notifications at travis-ci.org (Travis CI) Date: Fri, 02 Aug 2013 08:05:13 +0000 Subject: [Pytest-commit] [Fixed] hpk42/pytest#31 (master - 694aa90) Message-ID: <51fb683984d00_249be5e257576@0a12d6ac-2d92-4712-aa24-df0f68b86bd1.mail> Build Update for hpk42/pytest ------------------------------------- Build: #31 Status: Fixed Duration: 5 minutes and 39 seconds Commit: 694aa90 (master) Author: holger krekel Message: ref #322 cleanup all teardown calling to only happen when setup succeeded. don't use autouse fixtures for now because it would cause a proliferation and overhead for the execution of every test. Rather introduce a node.addfinalizer(fin) to attach a finalizer to the respective node and call it from node.setup() functions if the setup phase succeeded (i.e. there is no setup function or it finished successfully) View the changeset: https://github.com/hpk42/pytest/compare/9c7f046e0961...694aa9030a31 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/9765822 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From issues-reply at bitbucket.org Sun Aug 4 09:32:11 2013 From: issues-reply at bitbucket.org (anthon_van_der_neut) Date: Sun, 04 Aug 2013 07:32:11 -0000 Subject: [Pytest-commit] Issue #108: tox should explicitly provide python executable when creating virtualenvs (hpk42/tox) Message-ID: <20130804073211.21835.1755@app05.ash-private.bitbucket.org> New issue 108: tox should explicitly provide python executable when creating virtualenvs https://bitbucket.org/hpk42/tox/issue/108/tox-should-explicitly-provide-python anthon_van_der_neut: tox should not rely on "/path_to/pythonX.Y /path1_to/virtualenv.py pyXY" to create a virtualenv with pyXY/bin/python to be of version X.Y.*. If you have specified a default python version for virtualenv, .e.g in the [config](http://www.virtualenv.org/en/latest/#environment-variables-and-configuration-files), the version specified there will of course be taken. tox should use /path_to/pythonX.Y /path1_to/virtualenv.py --python /path_to/pythonX.Y pyXY The worse part is that if the default environment runs the test correctly, you really have to look carefully at the **beginning** of the output to see what test run passed. From issues-reply at bitbucket.org Mon Aug 5 11:17:59 2013 From: issues-reply at bitbucket.org (anthon_van_der_neut) Date: Mon, 05 Aug 2013 09:17:59 -0000 Subject: [Pytest-commit] Issue #109: tox should not silently ignore multiple -e options (hpk42/tox) Message-ID: <20130805091759.14550.33666@app02.ash-private.bitbucket.org> New issue 109: tox should not silently ignore multiple -e options https://bitbucket.org/hpk42/tox/issue/109/tox-should-not-silently-ignore-multiple-e anthon_van_der_neut: When you invoke "tox -e py26 --notest" and want to rerun taht py27, one would expect that just adding " -e py27" at the end of the previous command would work. But that silently ingores "-e py26" and you have to do "tox -e py26,py27 --notest" (which to me is not a natural commandline invocation YMMV) Tox should not silently ignore all but the last "-e" option and: - give out a warning on the correct combination syntax - add the -e options together. The three ways of handling this (silent, warning, add together) could be set in $HOME/.tox/tox.ini, if backwards compatibility is required with silently ignoring as default. From issues-reply at bitbucket.org Mon Aug 5 21:43:21 2013 From: issues-reply at bitbucket.org (Allison Kaptur) Date: Mon, 05 Aug 2013 19:43:21 -0000 Subject: [Pytest-commit] Issue #110: typo in front page (hpk42/tox) Message-ID: <20130805194321.8425.15953@app04.ash-private.bitbucket.org> New issue 110: typo in front page https://bitbucket.org/hpk42/tox/issue/110/typo-in-front-page Allison Kaptur: The page at http://tox.readthedocs.org/en/latest/ reads "Tox as is a generic virtualenv management and test command line tool ..." Looks like "as is" is a typo, and I'm not quite sure what you mean to say instead. From commits-noreply at bitbucket.org Tue Aug 6 07:47:07 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 06 Aug 2013 05:47:07 -0000 Subject: [Pytest-commit] commit/tox: 2 new changesets Message-ID: <20130806054707.14740.83216@app06.ash-private.bitbucket.org> 2 new commits in tox: https://bitbucket.org/hpk42/tox/commits/8b3d45f5023e/ Changeset: 8b3d45f5023e User: hpk42 Date: 2013-08-05 13:27:06 Summary: fix sphinx building and checks, move bitbucket to use https urls Affected #: 9 files diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/announce/release-1.0.txt --- a/doc/announce/release-1.0.txt +++ b/doc/announce/release-1.0.txt @@ -22,7 +22,7 @@ Note that code hosting and issue tracking has moved from Google to Bitbucket: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox The 1.0 release includes contributions and is based on feedback and work from Chris Rose, Ronny Pfannschmidt, Jannis Leidel, Jakob Kaplan-Moss, diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/announce/release-1.1.txt --- a/doc/announce/release-1.1.txt +++ b/doc/announce/release-1.1.txt @@ -24,7 +24,7 @@ Note that code hosting and issue tracking has moved from Google to Bitbucket: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox The 1.0 release includes contributions and is based on feedback and work from Chris Rose, Ronny Pfannschmidt, Jannis Leidel, Jakob Kaplan-Moss, diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/announce/release-1.2.txt --- a/doc/announce/release-1.2.txt +++ b/doc/announce/release-1.2.txt @@ -24,7 +24,7 @@ code hosting and issue tracking on bitbucket: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox best, Holger Krekel diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/announce/release-1.3.txt --- a/doc/announce/release-1.3.txt +++ b/doc/announce/release-1.3.txt @@ -21,7 +21,7 @@ code hosting and issue tracking on bitbucket: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox best, Holger Krekel diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/announce/release-1.4.txt --- a/doc/announce/release-1.4.txt +++ b/doc/announce/release-1.4.txt @@ -23,7 +23,7 @@ code hosting and issue tracking on bitbucket: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox What is tox? ---------------- diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/check_sphinx.py --- a/doc/check_sphinx.py +++ b/doc/check_sphinx.py @@ -4,7 +4,7 @@ doctrees = tmpdir.join("doctrees") htmldir = tmpdir.join("html") subprocess.check_call([ - "sphinx-build", "-W", "-bhtml", + "sphinx-build", "-bhtml", "-d", str(doctrees), ".", str(htmldir)]) def test_linkcheck(tmpdir): diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/conf.py --- a/doc/conf.py +++ b/doc/conf.py @@ -261,3 +261,7 @@ app.add_description_unit('confval', 'confval', objname='configuration value', indextemplate='pair: %s; configuration value') + + +linkcheck_timeout = 30 +linkcheck_ignore = [r'http://holgerkrekel.net'] diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/example/general.txt --- a/doc/example/general.txt +++ b/doc/example/general.txt @@ -122,7 +122,7 @@ If you want to use this with Jenkins_, also checkout the :ref:`jenkins artifact example`. -.. _verlib: http://bitbucket.org/tarek/distutilsversion/ +.. _verlib: https://bitbucket.org/tarek/distutilsversion/ basepython defaults, overriding ++++++++++++++++++++++++++++++++++++++++++ diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 8b3d45f5023ee72841823e15685426fb9898178a doc/install.txt --- a/doc/install.txt +++ b/doc/install.txt @@ -12,7 +12,7 @@ **License**: MIT license -**hg repository**: http://bitbucket.org/hpk42/tox +**hg repository**: https://bitbucket.org/hpk42/tox Installation with pip/easy_install -------------------------------------- @@ -29,7 +29,7 @@ Consult the Bitbucket page to get a checkout of the mercurial repository: - http://bitbucket.org/hpk42/tox + https://bitbucket.org/hpk42/tox and then install in your environment with something like:: https://bitbucket.org/hpk42/tox/commits/d699ef58d43c/ Changeset: d699ef58d43c User: hpk42 Date: 2013-08-06 07:47:01 Summary: introduce --reportjson=PATH option to write out test run information (version 1). Affected #: 14 files diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,12 +1,17 @@ -1.5.1.dev +1.6.0.dev ----------------- +- add --result-json option to write out detailed per-venv information + into a json report file to be used by upstream tools. + - add new config options ``usedevelop`` and ``skipsdist`` as well as a command line option ``--develop`` to install the package-under-test in develop mode. thanks Monty Tailor for the PR. - always unset PYTHONDONTWRITEBYTE because newer setuptools doesn't like it +- if a HOMEDIR cannot be determined, use the toxinidir. + 1.5.0 ----------------- diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 doc/example/result.txt --- /dev/null +++ b/doc/example/result.txt @@ -0,0 +1,44 @@ + +Writing a json result file +-------------------------------------------------------- + +.. versionadded: 1.6 + +You can instruct tox to write a json-report file via:: + + tox --result-json=PATH + +This will create a json-formatted result file using this schema:: + + { + "testenvs": { + "py27": { + "python": { + "executable": "/home/hpk/p/tox/.tox/py27/bin/python", + "version": "2.7.3 (default, Aug 1 2012, 05:14:39) \n[GCC 4.6.3]", + "version_info": [ 2, 7, 3, "final", 0 ] + }, + "test": [ + { + "output": "...", + "command": [ + "/home/hpk/p/tox/.tox/py27/bin/py.test", + "--instafail", + "--junitxml=/home/hpk/p/tox/.tox/py27/log/junit-py27.xml", + "tests/test_config.py" + ], + "retcode": "0" + } + ], + "setup": [] + } + }, + "platform": "linux2", + "installpkg": { + "basename": "tox-1.6.0.dev1.zip", + "sha256": "b6982dde5789a167c4c35af0d34ef72176d0575955f5331ad04aee9f23af4326", + "md5": "27ead99fd7fa39ee7614cede6bf175a6" + }, + "toxversion": "1.6.0.dev1", + "reportversion": "1" + } diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 setup.py --- a/setup.py +++ b/setup.py @@ -21,12 +21,14 @@ install_requires = ['virtualenv>=1.9.1', 'py>=1.4.15', ] if version < (2, 7) or (3, 0) <= version <= (3, 1): install_requires += ['argparse'] + if version < (2,6): + install_requires += ["simplejson"] setup( name='tox', description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.5.1.dev2', + version='1.6.0.dev2', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tests/test_result.py --- /dev/null +++ b/tests/test_result.py @@ -0,0 +1,51 @@ +import sys +import py +from tox.result import ResultLog +import tox +import pytest + + at pytest.fixture +def pkg(tmpdir): + p = tmpdir.join("hello-1.0.tar.gz") + p.write("whatever") + return p + +def test_set_header(pkg): + replog = ResultLog() + d = replog.dict + replog.set_header(installpkg=pkg) + assert replog.dict == d + assert replog.dict["reportversion"] == "1" + assert replog.dict["toxversion"] == tox.__version__ + assert replog.dict["platform"] == sys.platform + assert replog.dict["host"] == py.std.socket.getfqdn() + assert replog.dict["installpkg"] == {"basename": "hello-1.0.tar.gz", + "md5": pkg.computehash("md5"), + "sha256": pkg.computehash("sha256")} + data = replog.dumps_json() + replog2 = ResultLog.loads_json(data) + assert replog2.dict == replog.dict + +def test_addenv_setpython(pkg): + replog = ResultLog() + replog.set_header(installpkg=pkg) + envlog = replog.get_envlog("py26") + envlog.set_python_info(py.path.local(sys.executable)) + assert envlog.dict["python"]["version_info"] == list(sys.version_info) + assert envlog.dict["python"]["version"] == sys.version + assert envlog.dict["python"]["executable"] == sys.executable + +def test_get_commandlog(pkg): + replog = ResultLog() + replog.set_header(installpkg=pkg) + envlog = replog.get_envlog("py26") + assert "setup" not in envlog.dict + setuplog = envlog.get_commandlog("setup") + setuplog.add_command(["virtualenv", "..."], "venv created", 0) + assert setuplog.list == [{"command": ["virtualenv", "..."], + "output": "venv created", + "retcode": "0"}] + assert envlog.dict["setup"] + setuplog2 = replog.get_envlog("py26").get_commandlog("setup") + assert setuplog2.list == setuplog.list + diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -264,14 +264,15 @@ args = " ".join(l[0].args) assert "-i ABC" in args -def test_install_recreate(newmocksession): +def test_install_recreate(newmocksession, tmpdir): + pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession(['--recreate'], """ [testenv] deps=xyz """) venv = mocksession.getenv('python') venv.update() - mocksession.installpkg(venv, "xz") + mocksession.installpkg(venv, pkg) mocksession.report.expect("verbosity0", "*create*") venv.update() mocksession.report.expect("verbosity0", "*recreate*") @@ -426,14 +427,15 @@ assert path == xyz2 assert md5 == path.computehash() - def test_python_recreation(self, newconfig, mocksession): + def test_python_recreation(self, tmpdir, newconfig, mocksession): + pkg = tmpdir.ensure("package.tar.gz") config = newconfig([], "") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) cconfig = venv._getliveconfig() venv.update() assert not venv.path_config.check() - mocksession.installpkg(venv, "sdist.zip") + mocksession.installpkg(venv, pkg) assert venv.path_config.check() assert mocksession._pcalls args1 = map(str, mocksession._pcalls[0].args) @@ -519,7 +521,8 @@ assert 'PIP_RESPECT_VIRTUALENV' not in os.environ assert 'PIP_REQUIRE_VIRTUALENV' not in os.environ -def test_setenv_added_to_pcall(mocksession, newconfig): +def test_setenv_added_to_pcall(tmpdir, mocksession, newconfig): + pkg = tmpdir.ensure("package.tar.gz") config = newconfig([], """ [testenv:python] commands=python -V @@ -530,7 +533,7 @@ venv = VirtualEnv(config.envconfigs['python'], session=mocksession) # import pdb; pdb.set_trace() - mocksession.installpkg(venv, "xyz") + mocksession.installpkg(venv, pkg) venv.test() l = mocksession._pcalls @@ -545,21 +548,23 @@ for e in os.environ: assert e in env -def test_installpkg_no_upgrade(newmocksession): +def test_installpkg_no_upgrade(tmpdir, newmocksession): + pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession([], "") venv = mocksession.getenv('python') venv.just_created = True venv.envconfig.envdir.ensure(dir=1) - mocksession.installpkg(venv, "whatever") + mocksession.installpkg(venv, pkg) l = mocksession._pcalls assert len(l) == 1 assert '-U' not in l[0].args -def test_installpkg_upgrade(newmocksession): +def test_installpkg_upgrade(newmocksession, tmpdir): + pkg = tmpdir.ensure("package.tar.gz") mocksession = newmocksession([], "") venv = mocksession.getenv('python') assert not hasattr(venv, 'just_created') - mocksession.installpkg(venv, "whatever") + mocksession.installpkg(venv, pkg) l = mocksession._pcalls assert len(l) == 1 assert '-U' in l[0].args diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -263,7 +263,7 @@ [tox] skipsdist=True [testenv] - commands=echo done + commands=python -c "print('done')" ''' }) result = cmd.run("tox", ) @@ -308,55 +308,64 @@ "*InvocationError*", ]) -def test_test_simple(cmd, initproj): - initproj("example123-0.5", filedefs={ - 'tests': {'test_hello.py': """ - def test_hello(pytestconfig): - pass - """, - }, - 'tox.ini': ''' - [testenv] - changedir=tests - commands= - py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml [] - deps=pytest - ''' - }) - result = cmd.run("tox") - assert not result.ret - result.stdout.fnmatch_lines([ - "*junit-python.xml*", - "*1 passed*", - ]) - result = cmd.run("tox", "-epython", ) - assert not result.ret - result.stdout.fnmatch_lines([ - "*1 passed*", - "*summary*", - "*python: commands succeeded" - ]) - # see that things work with a different CWD - old = cmd.tmpdir.chdir() - result = cmd.run("tox", "-c", "example123/tox.ini") - assert not result.ret - result.stdout.fnmatch_lines([ - "*1 passed*", - "*summary*", - "*python: commands succeeded" - ]) - old.chdir() - # see that tests can also fail and retcode is correct - testfile = py.path.local("tests").join("test_hello.py") - assert testfile.check() - testfile.write("def test_fail(): assert 0") - result = cmd.run("tox", ) - assert result.ret - result.stdout.fnmatch_lines([ - "*1 failed*", - "*summary*", - "*python: *failed*", - ]) +class TestToxRun: + @pytest.fixture + def example123(self, initproj): + initproj("example123-0.5", filedefs={ + 'tests': {'test_hello.py': """ + def test_hello(pytestconfig): + pass + """, + }, + 'tox.ini': ''' + [testenv] + changedir=tests + commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml + deps=pytest + ''' + }) + + def test_toxuone_env(self, cmd, example123): + result = cmd.run("tox") + assert not result.ret + result.stdout.fnmatch_lines([ + "*junit-python.xml*", + "*1 passed*", + ]) + result = cmd.run("tox", "-epython", ) + assert not result.ret + result.stdout.fnmatch_lines([ + "*1 passed*", + "*summary*", + "*python: commands succeeded" + ]) + + def test_different_config_cwd(self, cmd, example123, monkeypatch): + # see that things work with a different CWD + monkeypatch.chdir(cmd.tmpdir) + result = cmd.run("tox", "-c", "example123/tox.ini") + assert not result.ret + result.stdout.fnmatch_lines([ + "*1 passed*", + "*summary*", + "*python: commands succeeded" + ]) + + def test_json(self, cmd, example123): + # see that tests can also fail and retcode is correct + testfile = py.path.local("tests").join("test_hello.py") + assert testfile.check() + testfile.write("def test_fail(): assert 0") + jsonpath = cmd.tmpdir.join("res.json") + result = cmd.run("tox", "--result-json", jsonpath) + assert result.ret == 1 + data = py.std.json.load(jsonpath.open("r")) + verify_json_report_format(data) + result.stdout.fnmatch_lines([ + "*1 failed*", + "*summary*", + "*python: *failed*", + ]) def test_develop(initproj, cmd): @@ -460,7 +469,7 @@ "*py25*reusing*", ]) -def test_env_PYTHONDONTWRITEBYTECODE(initproj, cmd, monkeypatch): +def test_PYC(initproj, cmd, monkeypatch): initproj("example123", filedefs={'tox.ini': ''}) monkeypatch.setenv("PYTHONDOWNWRITEBYTECODE", 1) result = cmd.run("tox", "-v", "--notest") @@ -544,16 +553,33 @@ sdist_path = session.sdist() assert sdist_path == p - at pytest.mark.xfail("sys.platform == 'win32'", reason="test needs better impl") +#@pytest.mark.xfail("sys.platform == 'win32'", reason="test needs better impl") def test_envsitepackagesdir(cmd, initproj): initproj("pkg512-0.0.5", filedefs={ 'tox.ini': """ [testenv] commands= - echo X:{envsitepackagesdir} + python -c "print('X:{envsitepackagesdir}')" """}) result = cmd.run("tox") assert result.ret == 0 result.stdout.fnmatch_lines(""" X:*site-packages* """) + +def verify_json_report_format(data, testenvs=True): + assert data["reportversion"] == "1" + assert data["toxversion"] == tox.__version__ + if testenvs: + for envname, envdata in data["testenvs"].items(): + for commandtype in ("setup", "test"): + if commandtype not in envdata: + continue + for command in envdata[commandtype]: + assert command["output"] + assert command["retcode"] + pyinfo = envdata["python"] + assert isinstance(pyinfo["version_info"], list) + assert pyinfo["version"] + assert pyinfo["executable"] + diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,14 @@ [tox] -envlist=py27,py26,py25,py32,py33,docs,pypy +envlist=py27,py26,py32,py33,docs,pypy [testenv:X] commands=echo {posargs} [testenv] -commands=py.test --instafail --junitxml={envlogdir}/junit-{envname}.xml {posargs} -deps=pytest==2.3.4 - pytest-instafail +commands=py.test --junitxml={envlogdir}/junit-{envname}.xml {posargs} +deps=pytest>=2.3.5 -[testenv:py25] +[testenv:py25] # requires virtualenv-1.9.1 setenvs = PIP_INSECURE=True diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.5.1.dev2' +__version__ = '1.6.0.dev2' class exception: class Error(Exception): diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -14,6 +14,7 @@ from tox._verlib import NormalizedVersion, IrrationalVersionError from tox._venv import VirtualEnv from tox._config import parseconfig +from tox.result import ResultLog from subprocess import STDOUT def now(): @@ -41,6 +42,10 @@ self.venvname = self.venv.name else: self.venvname = "GLOB" + cat = {"runtests": "test", "getenv": "setup"}.get(msg) + if cat: + envlog = session.resultlog.get_envlog(self.venvname) + self.commandlog = envlog.get_commandlog(cat) def __enter__(self): self.report.logaction_start(self) @@ -76,7 +81,8 @@ def popen(self, args, cwd=None, env=None, redirect=True, returnout=False): logged_command = "%s$ %s" %(cwd, " ".join(map(str, args))) f = outpath = None - if redirect: + resultjson = self.session.config.option.resultjson + if resultjson or redirect: f = self._initlogpath(self.id) f.write("actionid=%s\nmsg=%s\ncmdargs=%r\nenv=%s\n" %( self.id, self.msg, args, env)) @@ -89,7 +95,7 @@ cwd = py.path.local() popen = self._popen(args, cwd, env=env, stdout=f, stderr=STDOUT) popen.outpath = outpath - popen.args = args + popen.args = [str(x) for x in args] popen.cwd = cwd popen.action = self self._popenlist.append(popen) @@ -109,11 +115,18 @@ if outpath: self.report.error("invocation failed, logfile: %s" % outpath) - self.report.error(outpath.read()) + out = outpath.read() + self.report.error(out) + if hasattr(self, "commandlog"): + self.commandlog.add_command(popen.args, out, ret) raise tox.exception.InvocationError( "%s (see %s)" %(invoked, outpath), ret) else: raise tox.exception.InvocationError("%r" %(invoked, )) + if not out and outpath: + out = outpath.read() + if hasattr(self, "commandlog"): + self.commandlog.add_command(popen.args, out, ret) return out def _rewriteargs(self, cwd, args): @@ -233,6 +246,7 @@ def __init__(self, config, popen=subprocess.Popen, Report=Reporter): self.config = config self.popen = popen + self.resultlog = ResultLog() self.report = Report(self) self.make_emptydir(config.logdir) config.logdir.ensure(dir=1) @@ -319,14 +333,19 @@ action = self.newaction(venv, "getenv", venv.envconfig.envdir) with action: venv.status = 0 + envlog = self.resultlog.get_envlog(venv.name) try: status = venv.update(action=action) except tox.exception.InvocationError: status = sys.exc_info()[1] if status: + commandlog = envlog.get_commandlog("setup") + commandlog.add_command(["setup virtualenv"], str(status), 1) venv.status = status self.report.error(str(status)) return False + commandpath = venv.getcommandpath("python") + envlog.set_python_info(commandpath) return True def finishvenv(self, venv): @@ -346,6 +365,7 @@ return False def installpkg(self, venv, sdist_path): + self.resultlog.set_header(installpkg=sdist_path) action = self.newaction(venv, "installpkg", sdist_path) with action: try: @@ -425,6 +445,12 @@ status)) if not retcode: self.report.good(" congratulations :)") + + path = self.config.option.resultjson + if path: + path = py.path.local(path) + path.write(self.resultlog.dumps_json()) + self.report.line("wrote json report at: %s" % path) return retcode def showconfig(self): diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -90,11 +90,13 @@ help="skip invoking test commands.") parser.add_argument("--sdistonly", action="store_true", dest="sdistonly", help="only perform the sdist packaging activity.") + parser.add_argument("--installpkg", action="store", default=None, + metavar="PATH", + help="use specified package for installation into venv, instead of " + "creating an sdist.") parser.add_argument("--develop", action="store_true", dest="develop", - help="install package in the venv using setup.py develop using " + help="install package in the venv using 'setup.py develop' via " "'pip -e .'") - parser.add_argument("--installpkg", action="store", default=None, - help="use specified package for installation into venv") parser.add_argument('-i', action="append", dest="indexurl", metavar="URL", help="set indexserver url (if URL is of form name=url set the " @@ -102,6 +104,12 @@ parser.add_argument("-r", "--recreate", action="store_true", dest="recreate", help="force recreation of virtual environments") + parser.add_argument("--result-json", action="store", + dest="resultjson", metavar="PATH", + help="write a json file with detailed information about " + "all commands and results involved. This will turn off " + "pass-through output from running test commands which is " + "instead captured into the json result file.") parser.add_argument("args", nargs="*", help="additional arguments available to command positional substition") return parser @@ -193,6 +201,8 @@ raise ValueError("invalid context") config.homedir = py.path.local._gethomedir() + if config.homedir is None: + config.homedir = config.toxinidir # XXX good idea? reader.addsubstitions(toxinidir=config.toxinidir, homedir=config.homedir) config.toxworkdir = reader.getpath(toxsection, "toxworkdir", diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/_pytestplugin.py --- a/tox/_pytestplugin.py +++ b/tox/_pytestplugin.py @@ -8,6 +8,7 @@ from tox._config import parseconfig from tox._venv import VirtualEnv from tox._cmdline import Action +from tox.result import ResultLog def pytest_configure(): if 'TOXENV' in os.environ: @@ -118,6 +119,7 @@ def __init__(self): self._clearmocks() self.config = request.getfuncargvalue("newconfig")([], "") + self.resultlog = ResultLog() self._actions = [] def getenv(self, name): return VirtualEnv(self.config.envconfigs[name], session=self) @@ -164,6 +166,7 @@ def run(self, *argv): argv = [str(x) for x in argv] + assert py.path.local.sysfind(str(argv[0])), argv[0] p1 = self.tmpdir.join("stdout") p2 = self.tmpdir.join("stderr") print("%s$ %s" % (os.getcwd(), " ".join(argv))) diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -358,6 +358,7 @@ oldPATH = os.environ['PATH'] bindir = str(self.envconfig.envbindir) os.environ['PATH'] = os.pathsep.join([bindir, oldPATH]) + self.session.report.verbosity2("setting PATH=%s" % os.environ["PATH"]) return oldPATH def getdigest(path): diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 tox/result.py --- /dev/null +++ b/tox/result.py @@ -0,0 +1,75 @@ +import sys +import py +try: + import json +except ImportError: + import simplejson as json + +class ResultLog: + + def __init__(self, dict=None): + if dict is None: + dict = {} + self.dict = dict + + def set_header(self, installpkg): + from tox import __version__ as toxver + self.dict.update({"reportversion": "1", "toxversion": toxver}) + self.dict["platform"] = sys.platform + self.dict["host"] = py.std.socket.getfqdn() + self.dict["installpkg"] = dict( + md5=installpkg.computehash("md5"), + sha256=installpkg.computehash("sha256"), + basename=installpkg.basename, + ) + + def get_envlog(self, name): + testenvs = self.dict.setdefault("testenvs", {}) + d = testenvs.setdefault(name, {}) + return EnvLog(self, name, d) + + def dumps_json(self): + return json.dumps(self.dict, indent=2) + + @classmethod + def loads_json(cls, data): + return cls(json.loads(data)) + +class EnvLog: + def __init__(self, reportlog, name, dict): + self.reportlog = reportlog + self.name = name + self.dict = dict + + def set_python_info(self, pythonexecutable): + pythonexecutable = py.path.local(pythonexecutable) + out = pythonexecutable.sysexec("-c", + "import sys; " + "print (sys.executable);" + "print (list(sys.version_info)); " + "print (sys.version)") + lines = out.splitlines() + executable = lines.pop(0) + version_info = eval(lines.pop(0)) + version = "\n".join(lines) + self.dict["python"] = dict( + executable=executable, + version_info = version_info, + version = version) + + def get_commandlog(self, name): + l = self.dict.setdefault(name, []) + return CommandLog(self, l) + +class CommandLog: + def __init__(self, envlog, list): + self.envlog = envlog + self.list = list + + def add_command(self, argv, output, retcode): + d = {} + self.list.append(d) + d["command"] = argv + d["output"] = output + d["retcode"] = str(retcode) + return d diff -r 8b3d45f5023ee72841823e15685426fb9898178a -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 toxbootstrap.py --- a/toxbootstrap.py +++ b/toxbootstrap.py @@ -58,7 +58,7 @@ """ -__version__ = '1.5.1.dev2' +__version__ = '1.6.0.dev2' import sys import os Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 6 15:38:45 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 06 Aug 2013 13:38:45 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130806133845.23470.13498@app13.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/50fa30ff660b/ Changeset: 50fa30ff660b Branch: quiet-color-summary User: pelme Date: 2013-08-05 09:45:10 Summary: Added color to the quite mode summary. Also changed the output format slightly to match the output of the standard summary. Affected #: 1 file diff -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 -r 50fa30ff660b70f4f8d60be07c8f89930afd1140 _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -455,19 +455,17 @@ parts.append("%d %s" % (len(val), key)) line = ", ".join(parts) msg = "%s in %.2f seconds" % (line, session_duration) + + markup = {'bold': True} + if 'failed' in self.stats or 'error' in self.stats: + markup = {'red': True, 'bold': True} + else: + markup = {'green': True, 'bold': True} + if self.verbosity >= 0: - markup = dict(bold=True) - if 'failed' in self.stats or 'error' in self.stats: - markup['red'] = True - else: - markup['green'] = True self.write_sep("=", msg, **markup) if self.verbosity == -1: - if line: - self.write("%s, " % line) - self.write("time: %.2f seconds\n" % session_duration) - #else: - # self.write_line(msg, bold=True) + self.write_line(msg, **markup) def summary_deselected(self): if 'deselected' in self.stats: https://bitbucket.org/hpk42/pytest/commits/4433813f9fbb/ Changeset: 4433813f9fbb User: hpk42 Date: 2013-08-06 15:38:43 Summary: Merged in pelme/pytest/quiet-color-summary (pull request #61) Added color to the quite mode summary Affected #: 1 file diff -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 -r 4433813f9fbb5e8de742e554c74d2dcc748e6fb8 _pytest/terminal.py --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -455,19 +455,17 @@ parts.append("%d %s" % (len(val), key)) line = ", ".join(parts) msg = "%s in %.2f seconds" % (line, session_duration) + + markup = {'bold': True} + if 'failed' in self.stats or 'error' in self.stats: + markup = {'red': True, 'bold': True} + else: + markup = {'green': True, 'bold': True} + if self.verbosity >= 0: - markup = dict(bold=True) - if 'failed' in self.stats or 'error' in self.stats: - markup['red'] = True - else: - markup['green'] = True self.write_sep("=", msg, **markup) if self.verbosity == -1: - if line: - self.write("%s, " % line) - self.write("time: %.2f seconds\n" % session_duration) - #else: - # self.write_line(msg, bold=True) + self.write_line(msg, **markup) def summary_deselected(self): if 'deselected' in self.stats: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 6 15:41:56 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 06 Aug 2013 13:41:56 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130806134156.32482.65308@app09.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/df3294f56768/ Changeset: df3294f56768 User: Anthon van der Neut Date: 2013-08-06 15:33:27 Summary: argcomplete: FastFileCompleter that doesn't call bash in subprocess, strip prefix dir ``` timeit result for 10000 iterations of expanding '/d' (lowered the count in the code afterwards) # 2.7.5 3.3.2 # FilesCompleter 75.1109 69.2116 # FastFilesCompleter 0.7383 1.0760 ``` - does not display prefix dir (like bash, not like compgen), py.test /usr/ does not show /usr/bin/ but bin/ Affected #: 3 files diff -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 -r df3294f56768936740e6a6c96b9c7248d767f2c0 _pytest/_argcomplete.py --- a/_pytest/_argcomplete.py +++ b/_pytest/_argcomplete.py @@ -22,7 +22,19 @@ attributes as well. (If argcomplete is not installed, the function the attribute points to will not be used). ---- +SPEEDUP +======= +The generic argcomplete script for bash-completion +(/etc/bash_completion.d/python-argcomplete.sh ) +uses a python program to determine startup script generated by pip. +You can speed up completion somewhat by changing this script to include + # PYTHON_ARGCOMPLETE_OK +so the the python-argcomplete-check-easy-install-script does not +need to be called to find the entry point of the code and see if that is +marked with PYTHON_ARGCOMPLETE_OK + +INSTALL/DEBUGGING +================= To include this support in another application that has setup.py generated scripts: - add the line: @@ -44,11 +56,32 @@ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname which should throw a KeyError: 'COMPLINE' (which is properly set by the global argcomplete script). - """ import sys import os +from glob import glob + +class FastFilesCompleter: + 'Fast file completer class' + def __init__(self, directories=True): + self.directories = directories + + def __call__(self, prefix, **kwargs): + """only called on non option completions""" + if os.path.sep in prefix[1:]: # + prefix_dir = len(os.path.dirname(prefix) + os.path.sep) + else: + prefix_dir = 0 + completion = [] + if '*' not in prefix and '?' not in prefix: + prefix += '*' + for x in sorted(glob(prefix)): + if os.path.isdir(x): + x += '/' + # append stripping the prefix (like bash, not like compgen) + completion.append(x[prefix_dir:]) + return completion if os.environ.get('_ARGCOMPLETE'): # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format @@ -58,7 +91,7 @@ import argcomplete.completers except ImportError: sys.exit(-1) - filescompleter = argcomplete.completers.FilesCompleter() + filescompleter = FastFilesCompleter() def try_argcomplete(parser): argcomplete.autocomplete(parser) diff -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 -r df3294f56768936740e6a6c96b9c7248d767f2c0 bench/bench_argcomplete.py --- /dev/null +++ b/bench/bench_argcomplete.py @@ -0,0 +1,19 @@ + + +# 10000 iterations, just for relative comparison +# 2.7.5 3.3.2 +# FilesCompleter 75.1109 69.2116 +# FastFilesCompleter 0.7383 1.0760 + + +if __name__ == '__main__': + import sys + import timeit + from argcomplete.completers import FilesCompleter + from _pytest._argcomplete import FastFilesCompleter + count = 1000 # only a few seconds + setup = 'from __main__ import FastFilesCompleter\nfc = FastFilesCompleter()' + run = 'fc("/d")' + sys.stdout.write('%s\n' % (timeit.timeit(run, + setup=setup.replace('Fast', ''), number=count))) + sys.stdout.write('%s\n' % (timeit.timeit(run, setup=setup, number=count))) diff -r a36faafd111e3ef317b18f4fe86054bdfaaa4301 -r df3294f56768936740e6a6c96b9c7248d767f2c0 testing/test_argcomplete.py --- /dev/null +++ b/testing/test_argcomplete.py @@ -0,0 +1,92 @@ +from __future__ import with_statement +import py, pytest + +# test for _argcomplete but not specific for any application + +def equal_with_bash(prefix, ffc, fc, out=None): + res = ffc(prefix) + res_bash = set(fc(prefix)) + retval = set(res) == res_bash + if out: + out.write('equal_with_bash %s %s\n' % (retval, res)) + if not retval: + out.write(' python - bash: %s\n' % (set(res) - res_bash)) + out.write(' bash - python: %s\n' % (res_bash - set(res))) + return retval + +# copied from argcomplete.completers as import from there +# also pulls in argcomplete.__init__ which opens filedescriptor 9 +# this gives an IOError at the end of testrun +def _wrapcall(*args, **kargs): + try: + if py.std.sys.version_info > (2,7): + return py.std.subprocess.check_output(*args,**kargs).decode().splitlines() + if 'stdout' in kargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = py.std.subprocess.Popen( + stdout=py.std.subprocess.PIPE, *args, **kargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kargs.get("args") + if cmd is None: + cmd = args[0] + raise py.std.subprocess.CalledProcessError(retcode, cmd) + return output.decode().splitlines() + except py.std.subprocess.CalledProcessError: + return [] + +class FilesCompleter(object): + 'File completer class, optionally takes a list of allowed extensions' + def __init__(self,allowednames=(),directories=True): + # Fix if someone passes in a string instead of a list + if type(allowednames) is str: + allowednames = [allowednames] + + self.allowednames = [x.lstrip('*').lstrip('.') for x in allowednames] + self.directories = directories + + def __call__(self, prefix, **kwargs): + completion = [] + if self.allowednames: + if self.directories: + files = _wrapcall(['bash','-c', + "compgen -A directory -- '{p}'".format(p=prefix)]) + completion += [ f + '/' for f in files] + for x in self.allowednames: + completion += _wrapcall(['bash', '-c', + "compgen -A file -X '!*.{0}' -- '{p}'".format(x,p=prefix)]) + else: + completion += _wrapcall(['bash', '-c', + "compgen -A file -- '{p}'".format(p=prefix)]) + + anticomp = _wrapcall(['bash', '-c', + "compgen -A directory -- '{p}'".format(p=prefix)]) + + completion = list( set(completion) - set(anticomp)) + + if self.directories: + completion += [f + '/' for f in anticomp] + return completion + +# the following barfs with a syntax error on py2.5 +# @pytest.mark.skipif("sys.version_info < (2,6)") +class TestArgComplete: + @pytest.mark.skipif("sys.version_info < (2,6)") + def test_compare_with_compgen(self): + from _pytest._argcomplete import FastFilesCompleter + ffc = FastFilesCompleter() + fc = FilesCompleter() + for x in '/ /d /data qqq'.split(): + assert equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) + + @pytest.mark.skipif("sys.version_info < (2,6)") + def test_remove_dir_prefix(self): + """this is not compatible with compgen but it is with bash itself: + ls /usr/ + """ + from _pytest._argcomplete import FastFilesCompleter + ffc = FastFilesCompleter() + fc = FilesCompleter() + for x in '/usr/'.split(): + assert not equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) https://bitbucket.org/hpk42/pytest/commits/9c9044347a56/ Changeset: 9c9044347a56 User: hpk42 Date: 2013-08-06 15:41:54 Summary: Merged in anthon_van_der_neut/pytest_argcomplete (pull request #63) argcomplete: FastFileCompleter that doesn't call bash in subprocess, strip prefix dir Affected #: 3 files diff -r 4433813f9fbb5e8de742e554c74d2dcc748e6fb8 -r 9c9044347a5642b97bca9fba52d0dd14027dc287 _pytest/_argcomplete.py --- a/_pytest/_argcomplete.py +++ b/_pytest/_argcomplete.py @@ -22,7 +22,19 @@ attributes as well. (If argcomplete is not installed, the function the attribute points to will not be used). ---- +SPEEDUP +======= +The generic argcomplete script for bash-completion +(/etc/bash_completion.d/python-argcomplete.sh ) +uses a python program to determine startup script generated by pip. +You can speed up completion somewhat by changing this script to include + # PYTHON_ARGCOMPLETE_OK +so the the python-argcomplete-check-easy-install-script does not +need to be called to find the entry point of the code and see if that is +marked with PYTHON_ARGCOMPLETE_OK + +INSTALL/DEBUGGING +================= To include this support in another application that has setup.py generated scripts: - add the line: @@ -44,11 +56,32 @@ _ARGCOMPLETE=1 _ARC_DEBUG=1 appname which should throw a KeyError: 'COMPLINE' (which is properly set by the global argcomplete script). - """ import sys import os +from glob import glob + +class FastFilesCompleter: + 'Fast file completer class' + def __init__(self, directories=True): + self.directories = directories + + def __call__(self, prefix, **kwargs): + """only called on non option completions""" + if os.path.sep in prefix[1:]: # + prefix_dir = len(os.path.dirname(prefix) + os.path.sep) + else: + prefix_dir = 0 + completion = [] + if '*' not in prefix and '?' not in prefix: + prefix += '*' + for x in sorted(glob(prefix)): + if os.path.isdir(x): + x += '/' + # append stripping the prefix (like bash, not like compgen) + completion.append(x[prefix_dir:]) + return completion if os.environ.get('_ARGCOMPLETE'): # argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format @@ -58,7 +91,7 @@ import argcomplete.completers except ImportError: sys.exit(-1) - filescompleter = argcomplete.completers.FilesCompleter() + filescompleter = FastFilesCompleter() def try_argcomplete(parser): argcomplete.autocomplete(parser) diff -r 4433813f9fbb5e8de742e554c74d2dcc748e6fb8 -r 9c9044347a5642b97bca9fba52d0dd14027dc287 bench/bench_argcomplete.py --- /dev/null +++ b/bench/bench_argcomplete.py @@ -0,0 +1,19 @@ + + +# 10000 iterations, just for relative comparison +# 2.7.5 3.3.2 +# FilesCompleter 75.1109 69.2116 +# FastFilesCompleter 0.7383 1.0760 + + +if __name__ == '__main__': + import sys + import timeit + from argcomplete.completers import FilesCompleter + from _pytest._argcomplete import FastFilesCompleter + count = 1000 # only a few seconds + setup = 'from __main__ import FastFilesCompleter\nfc = FastFilesCompleter()' + run = 'fc("/d")' + sys.stdout.write('%s\n' % (timeit.timeit(run, + setup=setup.replace('Fast', ''), number=count))) + sys.stdout.write('%s\n' % (timeit.timeit(run, setup=setup, number=count))) diff -r 4433813f9fbb5e8de742e554c74d2dcc748e6fb8 -r 9c9044347a5642b97bca9fba52d0dd14027dc287 testing/test_argcomplete.py --- /dev/null +++ b/testing/test_argcomplete.py @@ -0,0 +1,92 @@ +from __future__ import with_statement +import py, pytest + +# test for _argcomplete but not specific for any application + +def equal_with_bash(prefix, ffc, fc, out=None): + res = ffc(prefix) + res_bash = set(fc(prefix)) + retval = set(res) == res_bash + if out: + out.write('equal_with_bash %s %s\n' % (retval, res)) + if not retval: + out.write(' python - bash: %s\n' % (set(res) - res_bash)) + out.write(' bash - python: %s\n' % (res_bash - set(res))) + return retval + +# copied from argcomplete.completers as import from there +# also pulls in argcomplete.__init__ which opens filedescriptor 9 +# this gives an IOError at the end of testrun +def _wrapcall(*args, **kargs): + try: + if py.std.sys.version_info > (2,7): + return py.std.subprocess.check_output(*args,**kargs).decode().splitlines() + if 'stdout' in kargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = py.std.subprocess.Popen( + stdout=py.std.subprocess.PIPE, *args, **kargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kargs.get("args") + if cmd is None: + cmd = args[0] + raise py.std.subprocess.CalledProcessError(retcode, cmd) + return output.decode().splitlines() + except py.std.subprocess.CalledProcessError: + return [] + +class FilesCompleter(object): + 'File completer class, optionally takes a list of allowed extensions' + def __init__(self,allowednames=(),directories=True): + # Fix if someone passes in a string instead of a list + if type(allowednames) is str: + allowednames = [allowednames] + + self.allowednames = [x.lstrip('*').lstrip('.') for x in allowednames] + self.directories = directories + + def __call__(self, prefix, **kwargs): + completion = [] + if self.allowednames: + if self.directories: + files = _wrapcall(['bash','-c', + "compgen -A directory -- '{p}'".format(p=prefix)]) + completion += [ f + '/' for f in files] + for x in self.allowednames: + completion += _wrapcall(['bash', '-c', + "compgen -A file -X '!*.{0}' -- '{p}'".format(x,p=prefix)]) + else: + completion += _wrapcall(['bash', '-c', + "compgen -A file -- '{p}'".format(p=prefix)]) + + anticomp = _wrapcall(['bash', '-c', + "compgen -A directory -- '{p}'".format(p=prefix)]) + + completion = list( set(completion) - set(anticomp)) + + if self.directories: + completion += [f + '/' for f in anticomp] + return completion + +# the following barfs with a syntax error on py2.5 +# @pytest.mark.skipif("sys.version_info < (2,6)") +class TestArgComplete: + @pytest.mark.skipif("sys.version_info < (2,6)") + def test_compare_with_compgen(self): + from _pytest._argcomplete import FastFilesCompleter + ffc = FastFilesCompleter() + fc = FilesCompleter() + for x in '/ /d /data qqq'.split(): + assert equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) + + @pytest.mark.skipif("sys.version_info < (2,6)") + def test_remove_dir_prefix(self): + """this is not compatible with compgen but it is with bash itself: + ls /usr/ + """ + from _pytest._argcomplete import FastFilesCompleter + ffc = FastFilesCompleter() + fc = FilesCompleter() + for x in '/usr/'.split(): + assert not equal_with_bash(x, ffc, fc, out=py.std.sys.stdout) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 6 15:58:31 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 06 Aug 2013 13:58:31 -0000 Subject: [Pytest-commit] commit/tox: hpk42: fix issue110 - typo in front page Message-ID: <20130806135831.26015.68788@app08.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/ac76a1851c8b/ Changeset: ac76a1851c8b User: hpk42 Date: 2013-08-06 15:58:23 Summary: fix issue110 - typo in front page Affected #: 1 file diff -r d699ef58d43c842a7b6399bbb390ba923c45bdd6 -r ac76a1851c8b72ffae3f47a209f23496197870d4 doc/index.txt --- a/doc/index.txt +++ b/doc/index.txt @@ -13,7 +13,7 @@ What is Tox? -------------------- -Tox as is a generic virtualenv_ management and test command line tool you can use for: +Tox is a generic virtualenv_ management and test command line tool you can use for: * checking your package installs correctly with different Python versions and interpreters Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 6 16:04:45 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 06 Aug 2013 14:04:45 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20130806140445.3236.52178@app04.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/705fcf417a23/ Changeset: 705fcf417a23 User: Anthon van der Neut Date: 2013-08-04 12:23:20 Summary: fix for #108 Affected #: 1 file diff -r fb612de381a79f8d7bff9cf2e0bc8fab42237efd -r 705fcf417a2378d39079859e40ac233256974cb0 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -191,6 +191,8 @@ args.append("--setuptools") if self.envconfig.sitepackages: args.append('--system-site-packages') + # add interpreter explicitly, to prevent using default (virtualenv.ini) + args.extend(['--python', config_interpreter]) #if sys.platform == "win32": # f, path, _ = py.std.imp.find_module("virtualenv") # f.close() https://bitbucket.org/hpk42/tox/commits/eb15ead41d33/ Changeset: eb15ead41d33 User: Anthon van der Neut Date: 2013-08-05 09:40:38 Summary: stringify config_interpreter Affected #: 1 file diff -r 705fcf417a2378d39079859e40ac233256974cb0 -r eb15ead41d337593a95b91127ce147fe1a23457c tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -192,7 +192,7 @@ if self.envconfig.sitepackages: args.append('--system-site-packages') # add interpreter explicitly, to prevent using default (virtualenv.ini) - args.extend(['--python', config_interpreter]) + args.extend(['--python', str(config_interpreter)]) #if sys.platform == "win32": # f, path, _ = py.std.imp.find_module("virtualenv") # f.close() https://bitbucket.org/hpk42/tox/commits/bfa0702aae24/ Changeset: bfa0702aae24 User: hpk42 Date: 2013-08-06 16:04:45 Summary: Merged in anthon_van_der_neut/tox (pull request #53) fix for #108 Affected #: 1 file diff -r ac76a1851c8b72ffae3f47a209f23496197870d4 -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -191,6 +191,8 @@ args.append("--setuptools") if self.envconfig.sitepackages: args.append('--system-site-packages') + # add interpreter explicitly, to prevent using default (virtualenv.ini) + args.extend(['--python', str(config_interpreter)]) #if sys.platform == "win32": # f, path, _ = py.std.imp.find_module("virtualenv") # f.close() Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 7 15:36:38 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 07 Aug 2013 13:36:38 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: a new monkeypatch.replace(target, value) call which derives the Message-ID: <20130807133638.16726.57621@app12.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/b4cd6235587f/ Changeset: b4cd6235587f User: hpk42 Date: 2013-08-07 15:35:27 Summary: a new monkeypatch.replace(target, value) call which derives the monkeypatch location from target (can be class/module/function or string which is taken as importable python path) examples: monkeypatch.replace(os.path.abspath, lambda x: "") monkeypatch.replace("requests.get", ...) Affected #: 4 files diff -r 9c9044347a5642b97bca9fba52d0dd14027dc287 -r b4cd6235587f2259678b618c1c5a429babe2a2c5 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,16 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- new monkeypatch.replace() to allow for more direct patching:: + + monkeypatch.replace(os.path.abspath, lambda x: "mocked") + + instead of: monkeypatch.setattr(os.path, "abspath", lambda x: "mocked") + + You can also avoid imports by specifying a python path string:: + + monkeypatch.replace("requests.get", ...) + - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose finalizer mimick the same generic behaviour: if a setupX exists and fails, @@ -98,6 +108,7 @@ - better parametrize error messages, thanks Brianna Laugher + known incompatibilities: - if calling --genscript from python2.7 or above, you only get a diff -r 9c9044347a5642b97bca9fba52d0dd14027dc287 -r b4cd6235587f2259678b618c1c5a429babe2a2c5 _pytest/monkeypatch.py --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -26,6 +26,47 @@ notset = object() +if sys.version_info < (3,0): + def derive_obj_and_name(obj): + name = obj.__name__ + real_obj = getattr(obj, "im_self", None) + if real_obj is None: + real_obj = getattr(obj, "im_class", None) + if real_obj is None: + real_obj = sys.modules[obj.__module__] + assert getattr(real_obj, name) == obj, \ + "could not derive object/name pair" + return name, real_obj + +else: + def derive_obj_and_name(obj): + name = obj.__name__ + real_obj = getattr(obj, "__self__", None) + if real_obj is None: + current = sys.modules[obj.__module__] + for name in obj.__qualname__.split("."): + real_obj = current + current = getattr(current, name) + assert getattr(real_obj, name) == obj, \ + "could not derive object/name pair" + return name, real_obj + +def derive_from_string(target): + rest = [] + while target: + try: + obj = __import__(target, None, None, "__doc__") + except ImportError: + if "." not in target: + raise + target, name = target.rsplit(".", 1) + rest.append(name) + else: + assert len(rest) >= 1 + while len(rest) != 1: + obj = getattr(obj, rest.pop()) + return rest[0], obj + class monkeypatch: """ object keeping a record of setattr/item/env/syspath changes. """ def __init__(self): @@ -33,9 +74,28 @@ self._setitem = [] self._cwd = None + def replace(self, target, value): + """ derive monkeypatching location from ``target`` and call + setattr(derived_obj, derived_name, value). + + This function can usually derive monkeypatch locations + for function, method or class targets. It also accepts + a string which is taken as a python path which is then + tried to be imported. For example the target "os.path.abspath" + will lead to a call to setattr(os.path, "abspath", value) + without the need to import "os.path" yourself. + """ + if isinstance(target, str): + name, obj = derive_from_string(target) + else: + name, obj = derive_obj_and_name(target) + return self.setattr(obj, name, value) + def setattr(self, obj, name, value, raising=True): """ set attribute ``name`` on ``obj`` to ``value``, by default - raise AttributeEror if the attribute did not exist. """ + raise AttributeEror if the attribute did not exist. + + """ oldval = getattr(obj, name, notset) if raising and oldval is notset: raise AttributeError("%r has no attribute %r" %(obj, name)) diff -r 9c9044347a5642b97bca9fba52d0dd14027dc287 -r b4cd6235587f2259678b618c1c5a429babe2a2c5 doc/en/monkeypatch.txt --- a/doc/en/monkeypatch.txt +++ b/doc/en/monkeypatch.txt @@ -29,7 +29,7 @@ def test_mytest(monkeypatch): def mockreturn(path): return '/abc' - monkeypatch.setattr(os.path, 'expanduser', mockreturn) + monkeypatch.setattr(os.path., 'expanduser', mockreturn) x = getssh() assert x == '/abc/.ssh' @@ -41,7 +41,7 @@ ----------------------------------------------------- .. autoclass:: monkeypatch - :members: setattr, delattr, setitem, delitem, setenv, delenv, syspath_prepend, chdir, undo + :members: setattr, replace, delattr, setitem, delitem, setenv, delenv, syspath_prepend, chdir, undo ``monkeypatch.setattr/delattr/delitem/delenv()`` all by default raise an Exception if the target does not exist. diff -r 9c9044347a5642b97bca9fba52d0dd14027dc287 -r b4cd6235587f2259678b618c1c5a429babe2a2c5 testing/test_monkeypatch.py --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -35,6 +35,38 @@ monkeypatch.undo() # double-undo makes no modification assert A.x == 5 +class TestDerived: + def f(self): + pass + + def test_class_function(self, monkeypatch): + monkeypatch.replace(TestDerived.f, lambda x: 42) + assert TestDerived().f() == 42 + + def test_instance_function(self, monkeypatch): + t = TestDerived() + monkeypatch.replace(t.f, lambda: 42) + assert t.f() == 42 + + def test_module_class(self, monkeypatch): + class New: + pass + monkeypatch.replace(TestDerived, New) + assert TestDerived == New + + def test_nested_module(self, monkeypatch): + monkeypatch.replace(os.path.abspath, lambda x: "hello") + assert os.path.abspath("123") == "hello" + + def test_string_expression(self, monkeypatch): + monkeypatch.replace("os.path.abspath", lambda x: "hello2") + assert os.path.abspath("123") == "hello2" + + def test_string_expression_class(self, monkeypatch): + monkeypatch.replace("_pytest.config.Config", 42) + import _pytest + assert _pytest.config.Config == 42 + def test_delattr(): class A: x = 1 Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 7 16:49:35 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 07 Aug 2013 14:49:35 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: monkeypatch.replace() now only accepts a string. Improved error handling and Message-ID: <20130807144935.8366.95880@app05.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/7f5dba9095f4/ Changeset: 7f5dba9095f4 User: hpk42 Date: 2013-08-07 16:49:29 Summary: monkeypatch.replace() now only accepts a string. Improved error handling and docs thanks to suggestions from flub, pelme, schmir, ronny. Affected #: 4 files diff -r b4cd6235587f2259678b618c1c5a429babe2a2c5 -r 7f5dba9095f4d77f06c46f19b4c7f4026e6182bd CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,15 +1,12 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- -- new monkeypatch.replace() to allow for more direct patching:: +- new monkeypatch.replace() to avoid imports and provide a shorter + invocation for patching out classes/functions from modules: - monkeypatch.replace(os.path.abspath, lambda x: "mocked") + monkeypatch.replace("requests.get", myfunc - instead of: monkeypatch.setattr(os.path, "abspath", lambda x: "mocked") - - You can also avoid imports by specifying a python path string:: - - monkeypatch.replace("requests.get", ...) + will replace the "get" function of the "requests" module with ``myfunc``. - fix issue322: tearDownClass is not run if setUpClass failed. Thanks Mathieu Agopian for the initial fix. Also make all of pytest/nose finalizer diff -r b4cd6235587f2259678b618c1c5a429babe2a2c5 -r 7f5dba9095f4d77f06c46f19b4c7f4026e6182bd _pytest/monkeypatch.py --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -1,6 +1,7 @@ """ monkeypatching and mocking functionality. """ import os, sys, inspect +import pytest def pytest_funcarg__monkeypatch(request): """The returned ``monkeypatch`` funcarg provides these @@ -26,47 +27,6 @@ notset = object() -if sys.version_info < (3,0): - def derive_obj_and_name(obj): - name = obj.__name__ - real_obj = getattr(obj, "im_self", None) - if real_obj is None: - real_obj = getattr(obj, "im_class", None) - if real_obj is None: - real_obj = sys.modules[obj.__module__] - assert getattr(real_obj, name) == obj, \ - "could not derive object/name pair" - return name, real_obj - -else: - def derive_obj_and_name(obj): - name = obj.__name__ - real_obj = getattr(obj, "__self__", None) - if real_obj is None: - current = sys.modules[obj.__module__] - for name in obj.__qualname__.split("."): - real_obj = current - current = getattr(current, name) - assert getattr(real_obj, name) == obj, \ - "could not derive object/name pair" - return name, real_obj - -def derive_from_string(target): - rest = [] - while target: - try: - obj = __import__(target, None, None, "__doc__") - except ImportError: - if "." not in target: - raise - target, name = target.rsplit(".", 1) - rest.append(name) - else: - assert len(rest) >= 1 - while len(rest) != 1: - obj = getattr(obj, rest.pop()) - return rest[0], obj - class monkeypatch: """ object keeping a record of setattr/item/env/syspath changes. """ def __init__(self): @@ -74,22 +34,45 @@ self._setitem = [] self._cwd = None - def replace(self, target, value): - """ derive monkeypatching location from ``target`` and call - setattr(derived_obj, derived_name, value). + def replace(self, import_path, value): + """ replace the object specified by a dotted ``import_path`` + with the given ``value``. - This function can usually derive monkeypatch locations - for function, method or class targets. It also accepts - a string which is taken as a python path which is then - tried to be imported. For example the target "os.path.abspath" - will lead to a call to setattr(os.path, "abspath", value) - without the need to import "os.path" yourself. + For example ``replace("os.path.abspath", value)`` will + trigger an ``import os.path`` and a subsequent + setattr(os.path, "abspath", value). Or to prevent + the requests library from performing requests you can call + ``replace("requests.sessions.Session.request", None)`` + which will lead to an import of ``requests.sessions`` and a call + to ``setattr(requests.sessions.Session, "request", None)``. """ - if isinstance(target, str): - name, obj = derive_from_string(target) - else: - name, obj = derive_obj_and_name(target) - return self.setattr(obj, name, value) + if not isinstance(import_path, str) or "." not in import_path: + raise TypeError("must be absolute import path string, not %r" % + (import_path,)) + rest = [] + target = import_path + while target: + try: + obj = __import__(target, None, None, "__doc__") + except ImportError: + if "." not in target: + __tracebackhide__ = True + pytest.fail("could not import any sub part: %s" % + import_path) + target, name = target.rsplit(".", 1) + rest.append(name) + else: + assert rest + try: + while len(rest) > 1: + attr = rest.pop() + obj = getattr(obj, attr) + attr = rest[0] + getattr(obj, attr) + except AttributeError: + __tracebackhide__ = True + pytest.fail("object %r has no attribute %r" % (obj, attr)) + return self.setattr(obj, attr, value) def setattr(self, obj, name, value, raising=True): """ set attribute ``name`` on ``obj`` to ``value``, by default diff -r b4cd6235587f2259678b618c1c5a429babe2a2c5 -r 7f5dba9095f4d77f06c46f19b4c7f4026e6182bd doc/en/monkeypatch.txt --- a/doc/en/monkeypatch.txt +++ b/doc/en/monkeypatch.txt @@ -29,7 +29,7 @@ def test_mytest(monkeypatch): def mockreturn(path): return '/abc' - monkeypatch.setattr(os.path., 'expanduser', mockreturn) + monkeypatch.setattr(os.path, 'expanduser', mockreturn) x = getssh() assert x == '/abc/.ssh' @@ -37,6 +37,23 @@ then calls into an function that calls it. After the test function finishes the ``os.path.expanduser`` modification will be undone. +example: preventing "requests" from remote operations +------------------------------------------------------ + +If you want to prevent the "requests" library from performing http +requests in all your tests, you can do:: + + # content of conftest.py + + import pytest + @pytest.fixture(autouse=True) + def no_requests(monkeypatch): + monkeypatch.replace("requests.session.Session.request", None) + +This autouse fixture will be executed for all test functions and it +will replace the method ``request.session.Session.request`` with the +value None so that any attempts to create http requests will fail. + Method reference of the monkeypatch function argument ----------------------------------------------------- diff -r b4cd6235587f2259678b618c1c5a429babe2a2c5 -r 7f5dba9095f4d77f06c46f19b4c7f4026e6182bd testing/test_monkeypatch.py --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -35,29 +35,7 @@ monkeypatch.undo() # double-undo makes no modification assert A.x == 5 -class TestDerived: - def f(self): - pass - - def test_class_function(self, monkeypatch): - monkeypatch.replace(TestDerived.f, lambda x: 42) - assert TestDerived().f() == 42 - - def test_instance_function(self, monkeypatch): - t = TestDerived() - monkeypatch.replace(t.f, lambda: 42) - assert t.f() == 42 - - def test_module_class(self, monkeypatch): - class New: - pass - monkeypatch.replace(TestDerived, New) - assert TestDerived == New - - def test_nested_module(self, monkeypatch): - monkeypatch.replace(os.path.abspath, lambda x: "hello") - assert os.path.abspath("123") == "hello" - +class TestReplace: def test_string_expression(self, monkeypatch): monkeypatch.replace("os.path.abspath", lambda x: "hello2") assert os.path.abspath("123") == "hello2" @@ -67,6 +45,17 @@ import _pytest assert _pytest.config.Config == 42 + def test_wrong_target(self, monkeypatch): + pytest.raises(TypeError, lambda: monkeypatch.replace(None, None)) + + def test_unknown_import(self, monkeypatch): + pytest.raises(pytest.fail.Exception, + lambda: monkeypatch.replace("unkn123.classx", None)) + + def test_unknown_attr(self, monkeypatch): + pytest.raises(pytest.fail.Exception, + lambda: monkeypatch.replace("os.path.qweqwe", None)) + def test_delattr(): class A: x = 1 Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 7 18:21:39 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 07 Aug 2013 16:21:39 -0000 Subject: [Pytest-commit] commit/tox: 2 new changesets Message-ID: <20130807162139.25563.46800@app04.ash-private.bitbucket.org> 2 new commits in tox: https://bitbucket.org/hpk42/tox/commits/77fe073adf32/ Changeset: 77fe073adf32 User: mgood Date: 2013-08-07 02:28:33 Summary: Make "usedevelop" a [testenv] setting instead of a [tox] setting Enables setting "usedevelop" per virtualenv. If "[tox]skipsdist" is not explicitly set, it default to True if all environments in the current envlist have develop = True. Affected #: 5 files diff -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -22,7 +22,6 @@ distshare=path # defaults to {homedir}/.tox/distshare envlist=ENVLIST # defaults to the list of all environments skipsdist=BOOL # defaults to false - usedevelop=BOOL # use python setup.py develop, defaults to false ``tox`` autodetects if it is running in a Jenkins_ context @@ -186,6 +185,14 @@ would be treated as relative to ``{toxinidir}``. **default**: ``{toxworkdir}/{envname}`` +.. confval:: usedevelop=BOOL + + .. versionadded:: 1.6 + + Install the current package in development mode with "setup.py develop" + instead of installing from the ``sdist`` package. + **default**: ``False`` + Substitutions --------------------- diff -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 doc/example/general.txt --- a/doc/example/general.txt +++ b/doc/example/general.txt @@ -166,7 +166,7 @@ Running setup.py develop is a common enough model that it has its own option:: - [tox] + [testenv] usedevelop=True And a corresponding command line option ``--develop``, which will set diff -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -377,7 +377,7 @@ def test_usedevelop(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ - [tox] + [testenv] usedevelop=True """}) result = cmd.run("tox", "-vv") @@ -392,9 +392,8 @@ """, }, 'tox.ini': ''' - [tox] + [testenv] usedevelop=True - [testenv] changedir=tests commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml [] diff -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -400,7 +400,12 @@ return sdist_path def subcommand_test(self): - if self.config.skipsdist: + skipsdist = self.config.skipsdist + # if skipsdist is not explicitly set, skip if develop == True + # for all venvs (either via usedevelop or --develop) + if skipsdist is None: + skipsdist = all(venv.envconfig.develop for venv in self.venvlist) + if skipsdist: self.report.info("skipping sdist step") sdist_path = None else: @@ -411,7 +416,7 @@ return for venv in self.venvlist: if self.setupenv(venv): - if self.config.usedevelop or self.config.option.develop: + if venv.envconfig.develop: self.developpkg(venv, self.config.setupdir) elif self.config.skipsdist: self.finishvenv(venv) @@ -462,7 +467,6 @@ self.report.keyvalue("setupdir: ", self.config.setupdir) self.report.keyvalue("distshare: ", self.config.distshare) self.report.keyvalue("skipsdist: ", self.config.skipsdist) - self.report.keyvalue("usedevelop: ", self.config.usedevelop) self.report.tw.line() for envconfig in self.config.envconfigs.values(): self.report.line("[testenv:%s]" % envconfig.envname, bold=True) @@ -479,6 +483,7 @@ self.report.line(" deps=%s" % envconfig.deps) self.report.line(" envdir= %s" % envconfig.envdir) self.report.line(" downloadcache=%s" % envconfig.downloadcache) + self.report.line(" usedevelop=%s" % envconfig.develop) def showenvs(self): for env in self.config.envlist: diff -r bfa0702aae2488ce8f7530e1e9d80b66de3d0256 -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -207,10 +207,12 @@ homedir=config.homedir) config.toxworkdir = reader.getpath(toxsection, "toxworkdir", "{toxinidir}/.tox") - config.usedevelop = reader.getbool(toxsection, "usedevelop", False) - config.skipsdist = reader.getbool(toxsection, "skipsdist", - config.usedevelop - or config.option.develop) + try: + config.skipsdist = reader.getbool(toxsection, "skipsdist") + except KeyError: + # default to None if not set so that we can check the "usedevelop" + # settings instead + config.skipsdist = None config.minversion = reader.getdefault(toxsection, "minversion", None) # determine indexserver dictionary @@ -272,7 +274,7 @@ vc.config = config reader = IniReader(self._cfg, fallbacksections=["testenv"]) reader.addsubstitions(**subs) - vc.develop = config.usedevelop or config.option.develop + vc.develop = reader.getbool(section, "usedevelop", config.option.develop) vc.envdir = reader.getpath(section, "envdir", "{toxworkdir}/%s" % name) vc.args_are_paths = reader.getbool(section, "args_are_paths", True) if reader.getdefault(section, "python", None): https://bitbucket.org/hpk42/tox/commits/d31aad39e16f/ Changeset: d31aad39e16f User: mgood Date: 2013-08-07 18:13:48 Summary: Compute skipsdist default at config parse time Affected #: 3 files diff -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 -r d31aad39e16f4e3b397a0b131834b50a1c265c48 tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -384,6 +384,24 @@ assert not result.ret assert "sdist-make" not in result.stdout.str() +def test_usedevelop_mixed(initproj, cmd): + initproj("example123", filedefs={'tox.ini': """ + [testenv:devenv] + usedevelop=True + [testenv:nondev] + usedevelop=False + """}) + + # running only 'devenv' should not do sdist + result = cmd.run("tox", "-vv", "-e", "devenv") + assert not result.ret + assert "sdist-make" not in result.stdout.str() + + # running all envs should do sdist + result = cmd.run("tox", "-vv") + assert not result.ret + assert "sdist-make" in result.stdout.str() + def test_test_usedevelop(cmd, initproj): initproj("example123-0.5", filedefs={ 'tests': {'test_hello.py': """ diff -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 -r d31aad39e16f4e3b397a0b131834b50a1c265c48 tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -400,12 +400,7 @@ return sdist_path def subcommand_test(self): - skipsdist = self.config.skipsdist - # if skipsdist is not explicitly set, skip if develop == True - # for all venvs (either via usedevelop or --develop) - if skipsdist is None: - skipsdist = all(venv.envconfig.develop for venv in self.venvlist) - if skipsdist: + if self.config.skipsdist: self.report.info("skipping sdist step") sdist_path = None else: diff -r 77fe073adf323caa25cae8c4ccbe4f8c0ff729a5 -r d31aad39e16f4e3b397a0b131834b50a1c265c48 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -207,12 +207,6 @@ homedir=config.homedir) config.toxworkdir = reader.getpath(toxsection, "toxworkdir", "{toxinidir}/.tox") - try: - config.skipsdist = reader.getbool(toxsection, "skipsdist") - except KeyError: - # default to None if not set so that we can check the "usedevelop" - # settings instead - config.skipsdist = None config.minversion = reader.getdefault(toxsection, "minversion", None) # determine indexserver dictionary @@ -269,6 +263,12 @@ config.envconfigs[name] = \ self._makeenvconfig(name, "_xz_9", reader._subs, config) + all_develop = all(name in config.envconfigs + and config.envconfigs[name].develop + for name in config.envlist) + + config.skipsdist = reader.getbool(toxsection, "skipsdist", all_develop) + def _makeenvconfig(self, name, section, subs, config): vc = VenvConfig(envname=name) vc.config = config Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Thu Aug 8 08:10:07 2013 From: issues-reply at bitbucket.org (Anthon van der Neut) Date: Thu, 08 Aug 2013 06:10:07 -0000 Subject: [Pytest-commit] Issue #111: tox cannot be started on itself with twice the same environment ( tox -e py27, py27) (hpk42/tox) Message-ID: <20130808061007.28654.98980@app10.ash-private.bitbucket.org> New issue 111: tox cannot be started on itself with twice the same environment ( tox -e py27,py27) https://bitbucket.org/hpk42/tox/issue/111/tox-cannot-be-started-on-itself-with-twice Anthon van der Neut: I am not sure it should run the same environment twice, but it should not throw an error: ``` $ tox -e py27,py27 GLOB sdist-make: /data1/src/tox.test/setup.py py27 recreate: /data1/src/tox.test/.tox/py27 py27 installdeps: pytest>=2.3.5 py27 inst: /data1/src/tox.test/.tox/dist/tox-1.6.0.dev2.zip py27 runtests: commands[0] | py.test --junitxml=/data1/src/tox.test/.tox/py27/log/junit-py27.xml ============================= test session starts ============================= platform linux2 -- Python 2.7.3 -- pytest-2.3.5 tox comes from: '/data1/src/tox.test/.tox/py27/local/lib/python2.7/site-packages/tox/__init__.pyc' collected 159 items tests/test_z_cmdline.py ................................. ---- generated xml file: /data1/src/tox.test/.tox/py27/log/junit-py27.xml ----- =================== 157 passed, 2 skipped in 79.87 seconds ==================== py27 inst: /data1/src/tox.test/.tox/dist/tox-1.6.0.dev2.zip Traceback (most recent call last): File "/usr/local/bin/tox", line 9, in load_entry_point('tox==1.6.0.dev2', 'console_scripts', 'tox')() File "/data1/src/tox.test/tox/_cmdline.py", line 26, in main retcode = Session(config).runcommand() File "/data1/src/tox.test/tox/_cmdline.py", line 301, in runcommand return self.subcommand_test() File "/data1/src/tox.test/tox/_cmdline.py", line 420, in subcommand_test self.runtestenv(venv) File "/data1/src/tox.test/tox/_cmdline.py", line 428, in runtestenv venv.test(redirect=redirect) File "/data1/src/tox.test/tox/_venv.py", line 328, in test message = "commands[%s] | %s" % (i, ' '.join(argv)) TypeError: sequence item 0: expected string, LocalPath found ``` This was tested on a fresh clone of tox: ``` changeset: 484:d31aad39e16f tag: tip user: Matt Good date: Wed Aug 07 09:13:48 2013 -0700 summary: Compute skipsdist default at config parse time ``` Responsible: anthon_van_der_neut From commits-noreply at bitbucket.org Thu Aug 8 08:36:34 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 08 Aug 2013 06:36:34 -0000 Subject: [Pytest-commit] commit/tox: 2 new changesets Message-ID: <20130808063634.26556.59957@app05.ash-private.bitbucket.org> 2 new commits in tox: https://bitbucket.org/hpk42/tox/commits/1d9e9ed68e53/ Changeset: 1d9e9ed68e53 User: mgood Date: 2013-08-07 18:42:20 Summary: Update devenv example docs with "usedevelop" setting Affected #: 1 file diff -r d31aad39e16f4e3b397a0b131834b50a1c265c48 -r 1d9e9ed68e53259adeb2b23a558b5dc56528567c doc/example/devenv.txt --- a/doc/example/devenv.txt +++ b/doc/example/devenv.txt @@ -14,11 +14,13 @@ Firstly, you need to prepare configuration for your development environment. In order to do that, we must define proper section at ``tox.ini`` file and tell at what directory environment should be created. Moreover, we need to specify -python version that should be picked:: +python version that should be picked, and that the package should be installed +with ``setup.py develop``:: [testenv:devenv] envdir = devenv basepython = python2.7 + usedevelop = True commands = deps = https://bitbucket.org/hpk42/tox/commits/c44e2c27e2e0/ Changeset: c44e2c27e2e0 User: mgood Date: 2013-08-07 18:46:40 Summary: Add "usedevelop" to the other "devenv" config example too Affected #: 1 file diff -r 1d9e9ed68e53259adeb2b23a558b5dc56528567c -r c44e2c27e2e09e71ab9270c15333baa1333502df doc/example/devenv.txt --- a/doc/example/devenv.txt +++ b/doc/example/devenv.txt @@ -47,13 +47,16 @@ Let's say we want our development environment sit at ``devenv`` and pull packages from ``requirements.txt`` file which we create at the same directory -as ``tox.ini`` file. We also want to speciy Python version to be 2.7. +as ``tox.ini`` file. We also want to speciy Python version to be 2.7, and use +``setup.py develop`` to work in development mode instead of building and +installing an ``sdist`` package. Here is example configuration for that:: [testenv:devenv] envdir = devenv basepython = python2.7 + usedevelop = True deps = commands = pip install -r requirements.txt Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 8 11:41:58 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 08 Aug 2013 09:41:58 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20130808094158.12540.49046@app06.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/babdb9c26786/ Changeset: babdb9c26786 User: Anthon van der Neut Date: 2013-08-08 09:41:18 Summary: dash_e: fixes #109 and #111 Behaviour of -e has not changed, but can be set by passing True or False as a parameter multi_dash_e to tox/_config.py: prepare_parse() This parameter should come from a user specifyable default value for backwards compatibility. Default should preferable be True after that is implemented. _split_env() was factored out of class parseini to enable testing The issue #111: error on specifying same env twice ("tox -e py27,py27") fixed. Multiple specifications of the same environment result in multiple invocation (this could also be selectable in a configuration file) Affected #: 3 files diff -r c44e2c27e2e09e71ab9270c15333baa1333502df -r babdb9c26786160c2cfbfdc9759e9fb86de5c0c9 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -7,6 +7,7 @@ import py from tox._config import IniReader, CommandParser from tox._config import parseconfig +from tox._config import prepare_parse, _split_env class TestVenvConfig: def test_config_parsing_minimal(self, tmpdir, newconfig): @@ -927,6 +928,42 @@ "*ERROR*tox.ini*not*found*", ]) + +class TestArgumentParser: + + def test_dash_e_silent1(self): + parser = prepare_parse('testpkg', None) + args = parser.parse_args('-e py26 -e py33'.split()) + envlist = _split_env(args.env) + assert envlist == ['py33'] + + def test_dash_e_silent2(self): + parser = prepare_parse('testpkg', None) + args = parser.parse_args('-e py26,py33'.split()) + envlist = _split_env(args.env) + assert envlist == ['py26', 'py33'] + + def test_dash_e_silent3(self): + parser = prepare_parse('testpkg', None) + args = parser.parse_args('-e py26,py26'.split()) + envlist = _split_env(args.env) + assert envlist == ['py26', 'py26'] + + def test_dash_e_warn(self, capsys): + parser = prepare_parse('testpkg', False) + args = parser.parse_args('-e py26,py32 -e py33'.split()) + envlist = _split_env(args.env) + out, err = capsys.readouterr() + assert 'WARNING: previous optional argument "-e py26' in out + assert envlist == ['py33'] + + def test_dash_e_combine(self): + parser = prepare_parse('testpkg', True) + args = parser.parse_args('-e py26,py25,py33 -e py33,py27'.split()) + envlist = _split_env(args.env) + assert envlist == ['py26', 'py25', 'py33', 'py33', 'py27'] + + class TestCommandParser: def test_command_parser_for_word(self): diff -r c44e2c27e2e09e71ab9270c15333baa1333502df -r babdb9c26786160c2cfbfdc9759e9fb86de5c0c9 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -66,7 +66,25 @@ else: setattr(namespace, self.dest, 0) -def prepare_parse(pkgname): +class CheckSingleStoreAction(argparse.Action): + """issue a warning when the store action is called multiple times""" + def __call__(self, parser, namespace, values, option_string=None): + if getattr(namespace, self.dest, None) is not None: + py.builtin.print_( + 'WARNING: previous optional argument "' + option_string + " " + + getattr(namespace, self.dest) + '" overwritten by "' + + option_string + " " + values + '"') + setattr(namespace, self.dest, values) + + +def prepare_parse(pkgname, multi_dash_e=None): + """setup ArgumentParser + + multi_dash_e: + None -> silently ignore all but last -e pyXY option (old behaviour + False -> take last -e pyXY option, but warn on sys.stdout + True -> concatenate + """ parser = argparse.ArgumentParser(description=__doc__,) #formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.pkgname = pkgname @@ -83,7 +101,13 @@ parser.add_argument("-c", action="store", default="tox.ini", dest="configfile", help="use the specified config file name.") - parser.add_argument("-e", action="store", dest="env", + if multi_dash_e is None: + dash_e_action = "store" + elif multi_dash_e is False: + dash_e_action = CheckSingleStoreAction + elif multi_dash_e is True: + dash_e_action = "append" + parser.add_argument("-e", action=dash_e_action, dest="env", metavar="envlist", help="work against specified environments (ALL selects all).") parser.add_argument("--notest", action="store_true", dest="notest", @@ -346,9 +370,21 @@ envlist = list(self.config.envconfigs) envlist.sort() else: - envlist = env.split(",") + envlist = _split_env(env) return envlist +def _split_env(env): + """if handed a list, action="append" was used for -e """ + envlist = [] + if not isinstance(env, list): + env = [env] + for to_split in env: + for single_env in to_split.split(","): + # "remove True or", if not allowing multiple same runs, update tests + if True or single_env not in envlist: + envlist.append(single_env) + return envlist + class DepConfig: def __init__(self, name, indexserver=None): self.name = name diff -r c44e2c27e2e09e71ab9270c15333baa1333502df -r babdb9c26786160c2cfbfdc9759e9fb86de5c0c9 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -325,7 +325,10 @@ self.session.make_emptydir(self.envconfig.envtmpdir) cwd = self.envconfig.changedir for i, argv in enumerate(self.envconfig.commands): - message = "commands[%s] | %s" % (i, ' '.join(argv)) + # have to make strings as _pcall changes argv[0] to a local() + # happens if the same environment is invoked twice + message = "commands[%s] | %s" % (i, ' '.join( + [str(x) for x in argv])) action.setactivity("runtests", message) try: self._pcall(argv, cwd=cwd, action=action, redirect=redirect) https://bitbucket.org/hpk42/tox/commits/96e1ba41e1c0/ Changeset: 96e1ba41e1c0 User: Anthon van der Neut Date: 2013-08-08 11:29:48 Summary: dash_e: fixes #109 and #111 Behaviour of -e has not changed, but can be set by passing True or False as a parameter multi_dash_e to tox/_config.py: prepare_parse() This parameter should come from a user specifyable default value for backwards compatibility. Default should preferable be True after that is implemented. _split_env() was factored out of class parseini to enable testing The issue #111: error on specifying same env twice ("tox -e py27,py27") fixed. Multiple specifications of the same environment result in multiple invocation (this could also be selectable in a configuration file) Affected #: 2 files diff -r babdb9c26786160c2cfbfdc9759e9fb86de5c0c9 -r 96e1ba41e1c080148fe8baf5c03ba27febd2a330 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -931,34 +931,26 @@ class TestArgumentParser: - def test_dash_e_silent1(self): - parser = prepare_parse('testpkg', None) - args = parser.parse_args('-e py26 -e py33'.split()) + def test_dash_e_single_1(self): + parser = prepare_parse('testpkg') + args = parser.parse_args('-e py26'.split()) envlist = _split_env(args.env) - assert envlist == ['py33'] + assert envlist == ['py26'] - def test_dash_e_silent2(self): - parser = prepare_parse('testpkg', None) + def test_dash_e_single_2(self): + parser = prepare_parse('testpkg') args = parser.parse_args('-e py26,py33'.split()) envlist = _split_env(args.env) assert envlist == ['py26', 'py33'] - def test_dash_e_silent3(self): - parser = prepare_parse('testpkg', None) + def test_dash_e_same(self): + parser = prepare_parse('testpkg') args = parser.parse_args('-e py26,py26'.split()) envlist = _split_env(args.env) assert envlist == ['py26', 'py26'] - def test_dash_e_warn(self, capsys): - parser = prepare_parse('testpkg', False) - args = parser.parse_args('-e py26,py32 -e py33'.split()) - envlist = _split_env(args.env) - out, err = capsys.readouterr() - assert 'WARNING: previous optional argument "-e py26' in out - assert envlist == ['py33'] - def test_dash_e_combine(self): - parser = prepare_parse('testpkg', True) + parser = prepare_parse('testpkg') args = parser.parse_args('-e py26,py25,py33 -e py33,py27'.split()) envlist = _split_env(args.env) assert envlist == ['py26', 'py25', 'py33', 'py33', 'py27'] diff -r babdb9c26786160c2cfbfdc9759e9fb86de5c0c9 -r 96e1ba41e1c080148fe8baf5c03ba27febd2a330 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -66,18 +66,7 @@ else: setattr(namespace, self.dest, 0) -class CheckSingleStoreAction(argparse.Action): - """issue a warning when the store action is called multiple times""" - def __call__(self, parser, namespace, values, option_string=None): - if getattr(namespace, self.dest, None) is not None: - py.builtin.print_( - 'WARNING: previous optional argument "' + option_string + " " + - getattr(namespace, self.dest) + '" overwritten by "' + - option_string + " " + values + '"') - setattr(namespace, self.dest, values) - - -def prepare_parse(pkgname, multi_dash_e=None): +def prepare_parse(pkgname): """setup ArgumentParser multi_dash_e: @@ -101,13 +90,7 @@ parser.add_argument("-c", action="store", default="tox.ini", dest="configfile", help="use the specified config file name.") - if multi_dash_e is None: - dash_e_action = "store" - elif multi_dash_e is False: - dash_e_action = CheckSingleStoreAction - elif multi_dash_e is True: - dash_e_action = "append" - parser.add_argument("-e", action=dash_e_action, dest="env", + parser.add_argument("-e", action="append", dest="env", metavar="envlist", help="work against specified environments (ALL selects all).") parser.add_argument("--notest", action="store_true", dest="notest", @@ -376,8 +359,6 @@ def _split_env(env): """if handed a list, action="append" was used for -e """ envlist = [] - if not isinstance(env, list): - env = [env] for to_split in env: for single_env in to_split.split(","): # "remove True or", if not allowing multiple same runs, update tests https://bitbucket.org/hpk42/tox/commits/abcc1ea8aee7/ Changeset: abcc1ea8aee7 User: Anthon van der Neut Date: 2013-08-08 11:32:15 Summary: dash_e: fixes #109 and #111 Behaviour of -e has not changed, but can be set by passing True or False as a parameter multi_dash_e to tox/_config.py: prepare_parse() This parameter should come from a user specifyable default value for backwards compatibility. Default should preferable be True after that is implemented. _split_env() was factored out of class parseini to enable testing The issue #111: error on specifying same env twice ("tox -e py27,py27") fixed. Multiple specifications of the same environment result in multiple invocation (this could also be selectable in a configuration file) Affected #: 1 file diff -r 96e1ba41e1c080148fe8baf5c03ba27febd2a330 -r abcc1ea8aee7aad33494dba87bee100f0467787d tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -67,13 +67,6 @@ setattr(namespace, self.dest, 0) def prepare_parse(pkgname): - """setup ArgumentParser - - multi_dash_e: - None -> silently ignore all but last -e pyXY option (old behaviour - False -> take last -e pyXY option, but warn on sys.stdout - True -> concatenate - """ parser = argparse.ArgumentParser(description=__doc__,) #formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.pkgname = pkgname Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 8 13:25:44 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 08 Aug 2013 11:25:44 -0000 Subject: [Pytest-commit] commit/tox: Anthon van der Neut: dash_e_all: fixes failing test caused by -e change Message-ID: <20130808112544.6641.34457@app04.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/580f5e65abd6/ Changeset: 580f5e65abd6 User: Anthon van der Neut Date: 2013-08-08 12:15:31 Summary: dash_e_all: fixes failing test caused by -e change Affected #: 1 file diff -r abcc1ea8aee7aad33494dba87bee100f0467787d -r 580f5e65abd6aeed9c608d59f888b02bae8ee22a tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -342,16 +342,17 @@ if not envlist: envlist = self.config.envconfigs.keys() return envlist - if env == "ALL": + envlist = _split_env(env) + if "ALL" in envlist: envlist = list(self.config.envconfigs) envlist.sort() - else: - envlist = _split_env(env) return envlist def _split_env(env): """if handed a list, action="append" was used for -e """ envlist = [] + if not isinstance(env, list): + env = [env] for to_split in env: for single_env in to_split.split(","): # "remove True or", if not allowing multiple same runs, update tests Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 8 13:27:15 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 08 Aug 2013 11:27:15 -0000 Subject: [Pytest-commit] commit/tox: hpk42: fix issue109 and fix issue111: multiple "-e" options are now combined Message-ID: <20130808112715.15150.41586@app11.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/3be5bca16f8b/ Changeset: 3be5bca16f8b User: hpk42 Date: 2013-08-08 13:27:01 Summary: fix issue109 and fix issue111: multiple "-e" options are now combined (previously the last one would win). Thanks Anthon van der Neut. Affected #: 1 file diff -r 580f5e65abd6aeed9c608d59f888b02bae8ee22a -r 3be5bca16f8b0c4394060b8e0377ef1883c518c7 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ 1.6.0.dev ----------------- +- fix issue109 and fix issue111: multiple "-e" options are now combined + (previously the last one would win). Thanks Anthon van der Neut. + - add --result-json option to write out detailed per-venv information into a json report file to be used by upstream tools. Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Thu Aug 8 20:50:45 2013 From: issues-reply at bitbucket.org (Peter Feiner) Date: Thu, 08 Aug 2013 18:50:45 -0000 Subject: [Pytest-commit] Issue #112: support setup.py scripts that build multiple packages (hpk42/tox) Message-ID: <20130808185045.11601.62603@app13.ash-private.bitbucket.org> New issue 112: support setup.py scripts that build multiple packages https://bitbucket.org/hpk42/tox/issue/112/support-setuppy-scripts-that-build Peter Feiner: I'd like to be able to use tox with setup.py scripts that build multiple packages (i.e., they make multiple setup() calls). The problem is that tox only installs the sdist zip archive from _one_ package into the venv instead of installing all of them. Here's a minimal example: ``` #!sh peter at gremlin ~/foobar % find . . ./tox.ini ./setup.py peter at gremlin ~/foobar % cat tox.ini [tox] envlist=py27 [testenv] whitelist_externals=true commands=true peter at gremlin ~/foobar % cat setup.py #!/usr/bin/env python from distutils.core import setup setup(name='foo', install_requires=['bar']) setup(name='bar') peter at gremlin ~/foobar % tox -v using tox.ini: /home/peter/foobar/tox.ini using tox-1.5.0 from /usr/local/lib/python2.7/dist-packages/tox/__init__.pyc GLOB sdist-make: /home/peter/foobar/setup.py /home/peter/foobar$ /usr/bin/python /home/peter/foobar/setup.py sdist --formats=zip --dist-dir /home/peter/foobar/.tox/dist >/home/peter/foobar/.tox/log/tox-0.log py27 create: /home/peter/foobar/.tox/py27 /home/peter/foobar/.tox$ /usr/bin/python2.7 /usr/local/lib/python2.7/dist-packages/virtualenv.py --setuptools py27 >/home/peter/foobar/.tox/py27/log/py27-0.log py27 inst: /home/peter/foobar/.tox/dist/foo-0.0.0.zip /home/peter/foobar/.tox/py27/log$ /home/peter/foobar/.tox/py27/bin/pip install /home/peter/foobar/.tox/dist/foo-0.0.0.zip >/home/peter/foobar/.tox/py27/log/py27-1.log ERROR: invocation failed, logfile: /home/peter/foobar/.tox/py27/log/py27-1.log ERROR: actionid=py27 msg=installpkg cmdargs=[local('/home/peter/foobar/.tox/py27/bin/pip'), 'install', '/home/peter/foobar/.tox/dist/foo-0.0.0.zip'] env={'PYTHONIOENCODING': 'utf_8', 'SSH_CLIENT': '192.168.1.207 59563 22', 'LOGNAME': 'peter', 'USER': 'peter', 'HOME': '/home/peter', 'PATH': '/home/peter/foobar/.tox/py27/bin:/home/peter/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games', 'LANG': 'en_US.UTF-8', 'TERM': 'xterm-256color', 'SHELL': '/bin/zsh', 'SHLVL': '1', 'PWD': '/home/peter/foobar', 'EDITOR': 'vim', 'OS_USERNAME': 'admin', 'OS_TENANT_NAME': 'admin', 'OS_PASSWORD': 'admin', '_': '/usr/local/bin/tox', 'SSH_CONNECTION': '192.168.1.207 59563 96.45.203.162 22', 'SSH_TTY': '/dev/pts/74', 'OLDPWD': '/home/peter', 'OS_AUTH_URL': 'http://192.168.16.3:5000/v2.0/', 'MAIL': '/var/mail/peter', 'LS_COLORS': 'rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:', 'PAGER': 'less'} Unpacking /home/peter/foobar/.tox/dist/foo-0.0.0.zip Running setup.py egg_info for package from file:///home/peter/foobar/.tox/dist/foo-0.0.0.zip Downloading/unpacking bar (from foo==0.0.0) Could not find any downloads that satisfy the requirement bar (from foo==0.0.0) Cleaning up... No distributions at all found for bar (from foo==0.0.0) Storing complete log in /home/peter/.pip/pip.log _______________________________________________________________________________________________________________________________________ summary _______________________________________________________________________________________________________________________________________ ERROR: py27: InvocationError: /home/peter/foobar/.tox/py27/bin/pip install /home/peter/foobar/.tox/dist/foo-0.0.0.zip (see /home/peter/foobar/.tox/py27/log/py27-1.log) ``` Here's a hacky patch to get the job done: ``` #!sh diff -r 3be5bca16f8b tox/_venv.py --- a/tox/_venv.py Thu Aug 08 13:27:01 2013 +0200 +++ b/tox/_venv.py Thu Aug 08 14:48:38 2013 -0400 @@ -245,7 +245,9 @@ else: action.setactivity("inst-nodeps", sdistpath) extraopts = ['-U', '--no-deps'] - self._install([sdistpath], extraopts=extraopts, action=action) + import glob + sdistpaths = glob.glob('%s/*.zip' % sdistpath.dirname) + self._install(sdistpaths, extraopts=extraopts, action=action) def install_deps(self, action=None): if action is None: ``` I could prepare a proper patch if there's interest. From commits-noreply at bitbucket.org Thu Aug 8 23:32:20 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 08 Aug 2013 21:32:20 -0000 Subject: [Pytest-commit] commit/pytest: 2 new changesets Message-ID: <20130808213220.18000.62447@app06.ash-private.bitbucket.org> 2 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/4c7963cdba24/ Changeset: 4c7963cdba24 User: hpk42 Date: 2013-08-08 13:18:46 Summary: remove automatic tox-testing of py25 Affected #: 1 file diff -r 7f5dba9095f4d77f06c46f19b4c7f4026e6182bd -r 4c7963cdba247ec1c77c43cb339c86dca8d6a461 tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] distshare={homedir}/.tox/distshare -envlist=py25,py26,py27,py27-nobyte,py32,py33,py27-xdist,trial +envlist=py26,py27,py27-nobyte,py32,py33,py27-xdist,trial [testenv] changedir=testing https://bitbucket.org/hpk42/pytest/commits/0b6a0bdf323c/ Changeset: 0b6a0bdf323c User: hpk42 Date: 2013-08-08 23:32:14 Summary: mention pytest_collection_modifyitems in plugin page Affected #: 1 file diff -r 4c7963cdba247ec1c77c43cb339c86dca8d6a461 -r 0b6a0bdf323c1ea00b9cac7e0e7c3527107038a1 doc/en/plugins.txt --- a/doc/en/plugins.txt +++ b/doc/en/plugins.txt @@ -339,6 +339,10 @@ .. autofunction:: pytest_pycollect_makeitem .. autofunction:: pytest_generate_tests +After collection is complete, you can modify the order of +items, delete or otherwise amend the test items: + +.. autofunction:: pytest_collection_modifyitems Reporting hooks ------------------------------ Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Aug 9 10:22:55 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 09 Aug 2013 08:22:55 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: add a note about how a lightweight but more powerful function-mocker could be done Message-ID: <20130809082255.9331.69063@app08.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/5260ac5bdfc0/ Changeset: 5260ac5bdfc0 User: hpk42 Date: 2013-08-09 10:22:49 Summary: add a note about how a lightweight but more powerful function-mocker could be done (compared to standard mock). Affected #: 1 file diff -r 0b6a0bdf323c1ea00b9cac7e0e7c3527107038a1 -r 5260ac5bdfc087a0e2612f4fea367d786bec42ba ISSUES.txt --- a/ISSUES.txt +++ b/ISSUES.txt @@ -1,5 +1,23 @@ +recorder = monkeypatch.function(".......") +------------------------------------------------------------- +tags: nice feature + +Like monkeypatch.replace but sets a mock-like call recorder: + + recorder = monkeypatch.function("os.path.abspath") + recorder.set_return("/hello") + os.path.abspath("hello") + call, = recorder.calls + assert call.args.path == "hello" + assert call.returned == "/hello" + ... + +Unlike mock, "args.path" acts on the parsed auto-spec'ed ``os.path.abspath`` +so it's independent from if the client side called "os.path.abspath(path=...)" +or "os.path.abspath('positional')". + refine parametrize API ------------------------------------------------------------- tags: critical feature Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 13 07:15:51 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 13 Aug 2013 05:15:51 -0000 Subject: [Pytest-commit] commit/tox: 9 new changesets Message-ID: <20130813051551.28231.77599@app05.ash-private.bitbucket.org> 9 new commits in tox: https://bitbucket.org/hpk42/tox/commits/4cdc267e9f82/ Changeset: 4cdc267e9f82 User: carljm Date: 2013-08-09 00:46:24 Summary: Add install_deps_command testenv option. Affected #: 2 files diff -r 3be5bca16f8b0c4394060b8e0377ef1883c518c7 -r 4cdc267e9f8290a19945c45d962a85f3d4f7d5f1 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -463,6 +463,14 @@ assert envconfig.changedir.basename == "abc" assert envconfig.changedir == config.setupdir.join("abc") + def test_install_deps_command(self, newconfig): + config = newconfig(""" + [testenv] + install_deps_command=pip install --pre {deps} + """) + envconfig = config.envconfigs['python'] + assert envconfig.install_deps_command == "pip install --pre {deps}" + def test_simple(tmpdir, newconfig): config = newconfig(""" [testenv:py24] diff -r 3be5bca16f8b0c4394060b8e0377ef1883c518c7 -r 4cdc267e9f8290a19945c45d962a85f3d4f7d5f1 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -331,6 +331,8 @@ downloadcache = reader.getdefault(section, "downloadcache") if downloadcache: vc.downloadcache = py.path.local(downloadcache) + vc.install_deps_command = reader.getdefault( + section, "install_deps_command", "pip @@@", replace=False) return vc def _getenvlist(self, reader, toxsection): https://bitbucket.org/hpk42/tox/commits/209de3d6baba/ Changeset: 209de3d6baba User: carljm Date: 2013-08-09 00:59:12 Summary: Config parser shlex-splits install_deps_command. Affected #: 2 files diff -r 4cdc267e9f8290a19945c45d962a85f3d4f7d5f1 -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -469,7 +469,8 @@ install_deps_command=pip install --pre {deps} """) envconfig = config.envconfigs['python'] - assert envconfig.install_deps_command == "pip install --pre {deps}" + assert envconfig.install_deps_argv == [ + 'pip', 'install', '--pre', '{deps}'] def test_simple(tmpdir, newconfig): config = newconfig(""" diff -r 4cdc267e9f8290a19945c45d962a85f3d4f7d5f1 -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -331,7 +331,7 @@ downloadcache = reader.getdefault(section, "downloadcache") if downloadcache: vc.downloadcache = py.path.local(downloadcache) - vc.install_deps_command = reader.getdefault( + vc.install_deps_argv = reader.getargv( section, "install_deps_command", "pip @@@", replace=False) return vc @@ -471,6 +471,12 @@ return shlex.split(new_command.strip()) + def getargv(self, section, name, default=None, replace=True): + command = self.getdefault( + section, name, default=default, replace=replace) + + return shlex.split(command.strip()) + def getbool(self, section, name, default=None): s = self.getdefault(section, name, default) if s is None: https://bitbucket.org/hpk42/tox/commits/16f82639efc6/ Changeset: 16f82639efc6 User: carljm Date: 2013-08-09 01:33:47 Summary: Use the install_command option for all installs. Affected #: 4 files diff -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 -r 16f82639efc66e312833a5eadbe9b07cc15b09ea tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -463,14 +463,20 @@ assert envconfig.changedir.basename == "abc" assert envconfig.changedir == config.setupdir.join("abc") - def test_install_deps_command(self, newconfig): + def test_install_command(self, newconfig): config = newconfig(""" [testenv] - install_deps_command=pip install --pre {deps} + install_command=pip install --pre {packages} """) envconfig = config.envconfigs['python'] - assert envconfig.install_deps_argv == [ - 'pip', 'install', '--pre', '{deps}'] + assert envconfig.install_command_argv == [ + 'pip', 'install', '--pre', '{packages}'] + + def test_install_command_must_contain_packages(self, newconfig): + py.test.raises(tox.exception.ConfigError, newconfig, """ + [testenv] + install_command=pip install + """) def test_simple(tmpdir, newconfig): config = newconfig(""" diff -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 -r 16f82639efc66e312833a5eadbe9b07cc15b09ea tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -512,12 +512,11 @@ monkeypatch.setattr(venv, '_pcall', lambda *args, **kwargs: 0/0) py.test.raises(ZeroDivisionError, "venv._install(list('123'))") py.test.raises(ZeroDivisionError, "venv.test()") - py.test.raises(ZeroDivisionError, "venv.easy_install(['qwe'])") - py.test.raises(ZeroDivisionError, "venv.pip_install(['qwe'])") + py.test.raises(ZeroDivisionError, "venv.run_install_command(['qwe'])") py.test.raises(ZeroDivisionError, "venv._pcall([1,2,3])") monkeypatch.setenv("PIP_RESPECT_VIRTUALENV", "1") monkeypatch.setenv("PIP_REQUIRE_VIRTUALENV", "1") - py.test.raises(ZeroDivisionError, "venv.pip_install(['qwe'])") + py.test.raises(ZeroDivisionError, "venv.run_install_command(['qwe'])") assert 'PIP_RESPECT_VIRTUALENV' not in os.environ assert 'PIP_REQUIRE_VIRTUALENV' not in os.environ @@ -570,13 +569,13 @@ assert '-U' in l[0].args assert '--no-deps' in l[0].args -def test_pip_install(newmocksession): +def test_run_install_command(newmocksession): mocksession = newmocksession([], "") venv = mocksession.getenv('python') venv.just_created = True venv.envconfig.envdir.ensure(dir=1) action = mocksession.newaction(venv, "hello") - venv.pip_install(args=["whatever"], action=action) + venv.run_install_command(args=["whatever"], action=action) l = mocksession._pcalls assert len(l) == 1 assert 'pip' in l[0].args[0] diff -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 -r 16f82639efc66e312833a5eadbe9b07cc15b09ea tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -331,8 +331,15 @@ downloadcache = reader.getdefault(section, "downloadcache") if downloadcache: vc.downloadcache = py.path.local(downloadcache) - vc.install_deps_argv = reader.getargv( - section, "install_deps_command", "pip @@@", replace=False) + vc.install_command_argv = reader.getargv( + section, + "install_command", + "pip install {opts} {packages}", + replace=False, + ) + if '{packages}' not in vc.install_command_argv: + raise tox.exception.ConfigError( + "'install_command' must contain '{packages}' substitution") return vc def _getenvlist(self, reader, toxsection): diff -r 209de3d6bababd1af01fe0ae8d2488fb0d3d4198 -r 16f82639efc66e312833a5eadbe9b07cc15b09ea tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -261,27 +261,26 @@ l = [] if indexserver: l += ["-i", indexserver] + if self.envconfig.downloadcache: + self.envconfig.downloadcache.ensure(dir=1) + l.append("--download-cache=%s" % self.envconfig.downloadcache) return l - def easy_install(self, args, indexserver=None): - argv = ["easy_install"] + self._commoninstallopts(indexserver) + args - self._pcall(argv, cwd=self.envconfig.envlogdir) - - def pip_install(self, args, indexserver=None, action=None): - argv = ["pip", "install"] + self._commoninstallopts(indexserver) + def run_install_command(self, args, indexserver=None, action=None): + argv = self.envconfig.install_command_argv[:] # use pip-script on win32 to avoid the executable locking - if sys.platform == "win32": + if argv[0] == "pip" and sys.platform == "win32": argv[0] = "pip-script.py" - if self.envconfig.downloadcache: - self.envconfig.downloadcache.ensure(dir=1) - argv.append("--download-cache=%s" % - self.envconfig.downloadcache) + i = argv.index('{packages}') + argv[i:i+1] = args + if '{opts}' in argv: + i = argv.index('{opts}') + argv[i:i+1] = self._commoninstallopts(indexserver) for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV'): try: del os.environ[x] except KeyError: pass - argv += args env = dict(PYTHONIOENCODING='utf_8') self._pcall(argv, cwd=self.envconfig.envlogdir, extraenv=env, action=action) @@ -307,7 +306,7 @@ extraopts = extraopts or [] for ixserver in l: args = d[ixserver] + extraopts - self.pip_install(args, ixserver.url, action) + self.run_install_command(args, ixserver.url, action) def _getenv(self): env = self.envconfig.setenv https://bitbucket.org/hpk42/tox/commits/b412f4665b54/ Changeset: b412f4665b54 User: carljm Date: 2013-08-09 01:43:47 Summary: Avoid adding --download-cache option to non-pip custom installers. Affected #: 2 files diff -r 16f82639efc66e312833a5eadbe9b07cc15b09ea -r b412f4665b54b1084824aa8065d374fb859ea589 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -585,6 +585,21 @@ assert 'PYTHONIOENCODING' in env assert env['PYTHONIOENCODING'] == 'utf_8' +def test_run_custom_install_command(newmocksession): + mocksession = newmocksession([], """ + [testenv] + install_command=easy_install {opts} {packages} + """) + venv = mocksession.getenv('python') + venv.just_created = True + venv.envconfig.envdir.ensure(dir=1) + action = mocksession.newaction(venv, "hello") + venv.run_install_command(args=["whatever"], action=action) + l = mocksession._pcalls + assert len(l) == 1 + assert 'easy_install' in l[0].args[0] + assert l[0].args[1:] == ['whatever'] + def test_command_relative_issue26(newmocksession, tmpdir, monkeypatch): mocksession = newmocksession([], """ [testenv] diff -r 16f82639efc66e312833a5eadbe9b07cc15b09ea -r b412f4665b54b1084824aa8065d374fb859ea589 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -257,25 +257,28 @@ "%s" % depinfo) self._install(deps, action=action) - def _commoninstallopts(self, indexserver): + def _installopts(self, indexserver, is_pip): l = [] if indexserver: l += ["-i", indexserver] - if self.envconfig.downloadcache: + if is_pip and self.envconfig.downloadcache: self.envconfig.downloadcache.ensure(dir=1) l.append("--download-cache=%s" % self.envconfig.downloadcache) return l def run_install_command(self, args, indexserver=None, action=None): argv = self.envconfig.install_command_argv[:] - # use pip-script on win32 to avoid the executable locking - if argv[0] == "pip" and sys.platform == "win32": - argv[0] = "pip-script.py" + is_pip = False + if argv[0] == "pip": + is_pip = True + # use pip-script on win32 to avoid the executable locking + if sys.platform == "win32": + argv[0] = "pip-script.py" i = argv.index('{packages}') argv[i:i+1] = args if '{opts}' in argv: i = argv.index('{opts}') - argv[i:i+1] = self._commoninstallopts(indexserver) + argv[i:i+1] = self._installopts(indexserver, is_pip) for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV'): try: del os.environ[x] https://bitbucket.org/hpk42/tox/commits/269dc66f1f5e/ Changeset: 269dc66f1f5e User: carljm Date: 2013-08-09 02:07:49 Summary: Add documentation for install_command option. Affected #: 1 file diff -r b412f4665b54b1084824aa8065d374fb859ea589 -r 269dc66f1f5e4d954854fb884731020758226f77 doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -76,6 +76,22 @@ For eventually performing a call to ``subprocess.Popen(args, ...)`` ``args`` are determined by splitting the whole command by whitespace. +.. confval:: install_command=ARGV + + .. versionadded:: 1.6 + + the command to be used for installing packages into the virtual + environment; both the sdist for the package under test and any + defined dependencies. Must contain the substitution key + ``{packages}`` which will be replaced by the packages to + install. May also contain the substitution key ``{opts}``, which + will be replaced by the ``-i`` option to specify index server + (according to :confval:`indexserver` and the ``:indexserver:dep`` + syntax of :confval:`deps`) and the ``--download-cache`` option, if + you've specified :confval:`downloadcache` and your + :confval:`install_command` begins with ``pip``. **default**: ``pip + install {opts} {packages}`` + .. confval:: whitelist_externals=MULTI-LINE-LIST each line specifies a command name (in glob-style pattern format) https://bitbucket.org/hpk42/tox/commits/15e7d325f4b6/ Changeset: 15e7d325f4b6 User: carljm Date: 2013-08-10 01:32:32 Summary: Add test for IniReader.getargv. Affected #: 1 file diff -r 269dc66f1f5e4d954854fb884731020758226f77 -r 15e7d325f4b682677756bb69ab61650e0c0a20b6 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -320,6 +320,16 @@ assert reader.getargvlist('section', 'key')[0] == expected + def test_getargv(self, newconfig): + config = newconfig(""" + [section] + key=some command "with quoting" + """) + reader = IniReader(config._cfg) + expected = ['some', 'command', 'with quoting'] + assert reader.getargv('section', 'key') == expected + + def test_getpath(self, tmpdir, newconfig): config = newconfig(""" [section] https://bitbucket.org/hpk42/tox/commits/c5bf99a270bb/ Changeset: c5bf99a270bb User: carljm Date: 2013-08-10 01:56:20 Summary: Don't pass --download-cache option to installer if downloadcache option is not in config. Affected #: 3 files diff -r 15e7d325f4b682677756bb69ab61650e0c0a20b6 -r c5bf99a270bb820b040f2090948dce3b27642569 tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -488,6 +488,30 @@ install_command=pip install """) + def test_downloadcache(self, newconfig, monkeypatch): + monkeypatch.delenv("PIP_DOWNLOAD_CACHE", raising=False) + config = newconfig(""" + [testenv] + downloadcache=/the/cache + """) + envconfig = config.envconfigs['python'] + assert envconfig.downloadcache == '/the/cache' + + def test_downloadcache_env_override(self, newconfig, monkeypatch): + monkeypatch.setenv("PIP_DOWNLOAD_CACHE", '/from/env') + config = newconfig(""" + [testenv] + downloadcache=/from/config + """) + envconfig = config.envconfigs['python'] + assert envconfig.downloadcache == '/from/env' + + def test_downloadcache_only_if_in_config(self, newconfig, tmpdir, monkeypatch): + monkeypatch.setenv("PIP_DOWNLOAD_CACHE", tmpdir) + config = newconfig('') + envconfig = config.envconfigs['python'] + assert not envconfig.downloadcache + def test_simple(tmpdir, newconfig): config = newconfig(""" [testenv:py24] diff -r 15e7d325f4b682677756bb69ab61650e0c0a20b6 -r c5bf99a270bb820b040f2090948dce3b27642569 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -208,10 +208,6 @@ assert l[1].cwd == venv.envconfig.envlogdir assert "pip" in str(args[0]) assert args[1] == "install" - if envdc: - assert venv.envconfig.downloadcache == tmpdir - else: - assert not venv.envconfig.downloadcache assert "dep1" in args assert "dep2" in args deps = list(filter(None, [x[1] for x in venv._getliveconfig().deps])) diff -r 15e7d325f4b682677756bb69ab61650e0c0a20b6 -r c5bf99a270bb820b040f2090948dce3b27642569 tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -326,10 +326,10 @@ vc.distribute = reader.getbool(section, "distribute", False) vc.sitepackages = reader.getbool(section, "sitepackages", False) vc.downloadcache = None - downloadcache = os.environ.get("PIP_DOWNLOAD_CACHE", None) - if not downloadcache: - downloadcache = reader.getdefault(section, "downloadcache") + downloadcache = reader.getdefault(section, "downloadcache") if downloadcache: + # env var, if present, takes precedence + downloadcache = os.environ.get("PIP_DOWNLOAD_CACHE", downloadcache) vc.downloadcache = py.path.local(downloadcache) vc.install_command_argv = reader.getargv( section, https://bitbucket.org/hpk42/tox/commits/136e0f1a8a93/ Changeset: 136e0f1a8a93 User: carljm Date: 2013-08-10 02:08:34 Summary: Add --download-cache if set in config; don't try to check installer. Affected #: 2 files diff -r c5bf99a270bb820b040f2090948dce3b27642569 -r 136e0f1a8a93cb52939fa37a746806e3d9a3daea doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -87,10 +87,14 @@ install. May also contain the substitution key ``{opts}``, which will be replaced by the ``-i`` option to specify index server (according to :confval:`indexserver` and the ``:indexserver:dep`` - syntax of :confval:`deps`) and the ``--download-cache`` option, if - you've specified :confval:`downloadcache` and your - :confval:`install_command` begins with ``pip``. **default**: ``pip - install {opts} {packages}`` + syntax of :confval:`deps`) and the ``--download-cache`` option (if + you've specified :confval:`downloadcache`). If your installer does + not support ``-i`` and ``--download-cache`` command-line options, + you should not use :confval:`indexserver` or + :confval:`downloadcache`, and/or your :confval:`install_command` + should not include the ``{opts}`` substitution key (in which case + those options will have no effect). + **default**: ``pip install {opts} {packages}`` .. confval:: whitelist_externals=MULTI-LINE-LIST @@ -133,9 +137,11 @@ .. confval:: downloadcache=path - (pip only) use this directory for caching downloads. This value - is overriden by the environment variable ``PIP_DOWNLOAD_CACHE`` - if it exists. + use this directory for caching downloads. This value is overriden + by the environment variable ``PIP_DOWNLOAD_CACHE`` if it exists. If + you specify a custom :confval:`install_command` that uses an + installer other than pip, your installer must support the + `--download-cache` command-line option. **default**: no download cache will be used. **note**: if creating multiple environments use of a download cache greatly speeds up the testing process. diff -r c5bf99a270bb820b040f2090948dce3b27642569 -r 136e0f1a8a93cb52939fa37a746806e3d9a3daea tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -257,28 +257,25 @@ "%s" % depinfo) self._install(deps, action=action) - def _installopts(self, indexserver, is_pip): + def _installopts(self, indexserver): l = [] if indexserver: l += ["-i", indexserver] - if is_pip and self.envconfig.downloadcache: + if self.envconfig.downloadcache: self.envconfig.downloadcache.ensure(dir=1) l.append("--download-cache=%s" % self.envconfig.downloadcache) return l def run_install_command(self, args, indexserver=None, action=None): argv = self.envconfig.install_command_argv[:] - is_pip = False - if argv[0] == "pip": - is_pip = True - # use pip-script on win32 to avoid the executable locking - if sys.platform == "win32": - argv[0] = "pip-script.py" + # use pip-script on win32 to avoid the executable locking + if argv[0] == "pip" and sys.platform == "win32": + argv[0] = "pip-script.py" i = argv.index('{packages}') argv[i:i+1] = args if '{opts}' in argv: i = argv.index('{opts}') - argv[i:i+1] = self._installopts(indexserver, is_pip) + argv[i:i+1] = self._installopts(indexserver) for x in ('PIP_RESPECT_VIRTUALENV', 'PIP_REQUIRE_VIRTUALENV'): try: del os.environ[x] https://bitbucket.org/hpk42/tox/commits/50d991641429/ Changeset: 50d991641429 User: carljm Date: 2013-08-10 02:12:46 Summary: Clarify that usedevelop uses pip's -e option. Affected #: 1 file diff -r 136e0f1a8a93cb52939fa37a746806e3d9a3daea -r 50d991641429bff80344b3c98d0ccad74e1a5015 doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -211,8 +211,11 @@ .. versionadded:: 1.6 - Install the current package in development mode with "setup.py develop" - instead of installing from the ``sdist`` package. + Install the current package in development mode with "setup.py + develop" instead of installing from the ``sdist`` package. (This + uses pip's `-e` option, so should be avoided if you've specified a + custom :confval:`install_command` that does not support ``-e``). + **default**: ``False`` Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 13 07:40:11 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 13 Aug 2013 05:40:11 -0000 Subject: [Pytest-commit] commit/tox: hpk42: remove toxbootstrap.py for now because it is broken. Message-ID: <20130813054011.355.48772@app01.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/d5fba83e994e/ Changeset: d5fba83e994e User: hpk42 Date: 2013-08-13 07:40:04 Summary: remove toxbootstrap.py for now because it is broken. add changelog entry for Carl wrt install_command Affected #: 5 files diff -r 50d991641429bff80344b3c98d0ccad74e1a5015 -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,12 @@ 1.6.0.dev ----------------- +- remove toxbootstrap.py for now because it is broken. + +- fix issue35: add new "install_command" testenv-option to configure the + installation command with options for dep/pkg install. Thanks Carl Meyer + for the PR and docs. + - fix issue109 and fix issue111: multiple "-e" options are now combined (previously the last one would win). Thanks Anthon van der Neut. diff -r 50d991641429bff80344b3c98d0ccad74e1a5015 -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 doc/example/jenkins.txt --- a/doc/example/jenkins.txt +++ b/doc/example/jenkins.txt @@ -39,7 +39,11 @@ **zero-installation** for slaves ------------------------------------------------------------- -.. versionadded:: 0.9 +.. note:: + + This feature is broken currently because "toxbootstrap.py" + has been removed. Please file an issue if you'd like to + see it back. If you manage many Jenkins slaves and want to use the latest officially released tox (or latest development version) and want to skip manually diff -r 50d991641429bff80344b3c98d0ccad74e1a5015 -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 setup.py --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.6.0.dev2', + version='1.6rc1', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r 50d991641429bff80344b3c98d0ccad74e1a5015 -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.6.0.dev2' +__version__ = '1.6rc1' class exception: class Error(Exception): diff -r 50d991641429bff80344b3c98d0ccad74e1a5015 -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 toxbootstrap.py --- a/toxbootstrap.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/env python -# The MIT License -# -# 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. -""" -tox-bootstrap -============= - -A bootstrap script to automatically install tox on machines that do not already -have it. This is especially useful when configuring a number of Jenkins slaves -quickly (see `zero installation for slaves ->` -in tox documentation); only Python needs to be pre-installed. - -Getting started ---------------- - -:: - - $ cd my_project/ - $ ls - . .. src/ doc/ setup.py tox.ini - $ curl https://bitbucket.org/hpk42/tox/raw/default/toxbootstrap.py - -Instead of running "tox", now you can just run "python toxbootstrap.py" which -will take care of installing tox (if not already installed into -``.tox/_toxinstall``):: - - $ python toxbootstrap.py - -Note that, when configuring Jenkins slaves, you need not add `toxbootstrap.py` to -your source tree; see the above linked Jenkins configuration example in tox -documentation. - -ToDo ----- - -1. Detect tox in ``$PATH`` (eg: ``C:\Python26\Scripts`` or - ``%APPDATA%\Python\Scripts``) - -2. Gracefully ignore PyPI xmlrpc downtime errors when checking for new release. - -""" - -__version__ = '1.6.0.dev2' - -import sys -import os -from os import path -import logging - -from subprocess import Popen, PIPE, check_call, CalledProcessError - -USETOXDEV=os.environ.get('USETOXDEV', False) -TENV='_toxinstall' - -PY3 = sys.version_info[0] == 3 - -if PY3: - from urllib.request import urlretrieve - import xmlrpc.client as xmlrpclib -else: - from urllib import urlretrieve - import xmlrpclib - -logging.basicConfig(level=logging.INFO) - - -# Last stable: 1.6 (now on github) -VIRTUALENVPY_URL = ('https://github.com/pypa/virtualenv/raw/master/virtualenv.py') - -def run(cmd, shell=True): - """Run the given command in shell""" - logging.info('Running command: %s', cmd) - check_call(cmd, shell=shell) - - -def crun(cmd, shell=True): - """Run the given command and return its output""" - logging.info('Running command (for output): %s', cmd) - p = Popen(cmd, stdout=PIPE, shell=shell) - stdout, stderr = p.communicate() - return stdout - - -def wget(url): - """Download the given file to current directory""" - logging.info('Downloading %s', url) - localpath = path.join(path.abspath(os.getcwd()), path.basename(url)) - urlretrieve(url, localpath) - - -def has_script(venv, name): - """Check if the virtualenv has the given script - - Looks for bin/$name (unix) or Scripts/$name.exe (windows) in the virtualenv - """ - if sys.platform == 'win32': - return any([path.exists(path.join(venv, 'Scripts', name)), - path.exists(path.join(venv, 'Scripts', name + '.exe'))]) - else: - return path.exists(path.join(venv, 'bin', name)) - -def activate_path(venv): - """Return the full path to the script virtualenv directory""" - if sys.platform == 'win32': - p = path.abspath(path.join(venv, 'Scripts')) - else: - p = path.abspath(path.join(venv, 'bin')) - assert path.exists(p), p - os.environ['PATH'] = p + os.pathsep + os.environ['PATH'] - logging.info("added to PATH: %s", p) - -def get_script_path(venv, name): - """Return the full path to the script in virtualenv directory""" - if sys.platform == 'win32': - p = path.join(venv, 'Scripts', name) - if not path.exists(p): - p = path.join(venv, 'Scripts', name + '.exe') - else: - p = path.join(venv, 'bin', name) - - if not path.exists(p): - raise NameError('cannot find a script named "%s"' % (name,)) - - return p - - -def get_tox_version(venv): - """Return the installed version of tox""" - py = get_script_path(venv, 'python') - s = 'import tox,sys; sys.stdout.write(str(tox.__version__))' - if sys.version_info[:2] >= (2, 6): - return crun('%s -s -c "%s"' % (py, s)) - else: - return crun('%s -c "%s"' % (py, s)) - - -def parse_simple_version(v): - """A simplified version of pkg_resources.parse_version - - This method can only parse simple versions like the ones with a set of - numbers separated by dots (eg: 1.2.3) - """ - return [int(c) for c in v.split('.')] - - -def pypi_get_latest_version(pkgname): - """Return the latest version of package from PyPI""" - pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi') - versions = pypi.package_releases('tox') - assert versions - versions.sort(key=parse_simple_version, reverse=True) - return versions[0] - -def ensuredir(p): - if not path.isdir(p): - os.makedirs(p) - -def cmdline(argv=None): - logging.info('toxbootstrap version %s', __version__) - currentdir = os.getcwd() - #os.chdir(path.abspath(path.dirname(__file__))) - ensuredir('.tox') - os.chdir('.tox') - - os.environ['PATH'] = os.path.abspath(TENV) + os.path.pathsep + os.environ['PATH'] - # create virtual environment - if not path.isdir(TENV) or not has_script(TENV, 'python') or \ - not has_script(TENV, 'pip'): - # get virtualenv.py - if not path.isfile('virtualenv.py'): - wget(VIRTUALENVPY_URL) - assert path.isfile('virtualenv.py') - - # XXX: we use --no-site-packages because: if tox is installed in global - # site-packages, then pip will not install it locally. ideal fix for - # this should be to first look for tox in the global scripts/ directory - run('%s virtualenv.py --no-site-packages --setuptools %s' % - (sys.executable, TENV)) - logging.info("removing virtualenv.py script after bootstrap venv creation") - for x in ('', 'o', 'c'): - try: - os.remove("virtualenv.py%s" % x) - except OSError: - pass - - assert has_script(TENV, 'python'), 'no python script' - assert has_script(TENV, 'pip'), 'no pip script' - activate_path(TENV) - - pip = get_script_path(TENV, 'pip') - - # install/upgrade tox itself - if USETOXDEV: - run('%s install -q -i http://pypi.testrun.org ' - '--upgrade %s tox' % (pip, cache)) - elif any([ - not has_script(TENV, 'tox'), - get_tox_version(TENV) != pypi_get_latest_version('tox')]): - run('%s install --upgrade --download-cache=_download tox' % (pip,)) - - toxversion = get_tox_version(TENV) - assert has_script(TENV, 'tox') - tox_script = path.abspath(get_script_path(TENV, 'tox')) - logging.info('tox is installed at %s version %s', tox_script, toxversion) - - #virtualenv = get_script_path(TENV, 'virtualenv') - #venv_version = crun('%s --version' % (virtualenv,)).strip() - #logging.info('virtualenv at %s version %s', virtualenv, venv_version) - - # XXX: virtualenv 1.5 is broken; replace it - #if venv_version == '1.5': - # logging.info( - # 'Replacing the unstable virtualenv-1.5 with the latest stable') - # run('%s uninstall -y virtualenv' % (pip,)) - # run('%s install virtualenv!=1.5' % (pip,)) - - # Now run the locally-installed tox - os.chdir(currentdir) - try: - run([tox_script] + (argv or []), shell=False) - except CalledProcessError: - _, e, _ = sys.exc_info() - logging.error('tox exited with error code %d', e.returncode) - sys.exit(e.returncode) - - -if __name__ == '__main__': - cmdline(sys.argv[1:]) Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 13 21:29:25 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 13 Aug 2013 19:29:25 -0000 Subject: [Pytest-commit] commit/tox: hpk42: also remove toxboostrap from manifest.in Message-ID: <20130813192925.5849.75393@app13.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/9e74e6ff0c03/ Changeset: 9e74e6ff0c03 User: hpk42 Date: 2013-08-13 21:29:20 Summary: also remove toxboostrap from manifest.in Affected #: 1 file diff -r d5fba83e994e7af7dc2b9daff3cac3a2baa24849 -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,6 +5,5 @@ include LICENSE include setup.py include tox.ini -include toxbootstrap.py graft doc graft tests Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Aug 13 23:34:44 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 13 Aug 2013 21:34:44 -0000 Subject: [Pytest-commit] commit/tox: hpk42: during installation of packages HOME is now set to a pseudo Message-ID: <20130813213444.2010.39135@app12.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/6aec60d13d3a/ Changeset: 6aec60d13d3a User: hpk42 Date: 2013-08-13 23:34:12 Summary: during installation of packages HOME is now set to a pseudo location (envtmpdir/pseudo-home). Also, if an index url was specified a .pydistutils.cfg file will be written so that index_url is set if a package contains a ``setup_requires``. Affected #: 5 files diff -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ 1.6.0.dev ----------------- +- during installation of dependencies HOME is set to a pseudo + location (envtmpdir/pseudo-home). If an index url was specified + a .pydistutils.cfg file will be written so that index_url + is set if a package contains a ``setup_requires``. + - remove toxbootstrap.py for now because it is broken. - fix issue35: add new "install_command" testenv-option to configure the diff -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 setup.py --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.6rc1', + version='1.6rc2', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -611,3 +611,16 @@ monkeypatch.setenv("PATH", str(tmpdir)) x4 = venv.getcommandpath("x", cwd=tmpdir) mocksession.report.expect("warning", "*test command found but not*") + +def test_hack_home_env(tmpdir): + from tox._venv import hack_home_env + env = hack_home_env(tmpdir, "http://index") + assert env["HOME"] == str(tmpdir) + assert env["PIP_INDEX_URL"] == "http://index" + assert "index_url = http://index" in \ + tmpdir.join(".pydistutils.cfg").read() + tmpdir.remove() + env = hack_home_env(tmpdir, None) + assert env["HOME"] == str(tmpdir) + assert not tmpdir.join(".pydistutils.cfg").check() + assert "PIP_INDEX_URL" not in env diff -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.6rc1' +__version__ = '1.6rc2' class exception: class Error(Exception): diff -r 9e74e6ff0c037ac8dc542f7bfefcc5928683b14e -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -266,7 +266,8 @@ l.append("--download-cache=%s" % self.envconfig.downloadcache) return l - def run_install_command(self, args, indexserver=None, action=None): + def run_install_command(self, args, indexserver=None, action=None, + extraenv=None): argv = self.envconfig.install_command_argv[:] # use pip-script on win32 to avoid the executable locking if argv[0] == "pip" and sys.platform == "win32": @@ -282,8 +283,10 @@ except KeyError: pass env = dict(PYTHONIOENCODING='utf_8') - self._pcall(argv, cwd=self.envconfig.envlogdir, extraenv=env, - action=action) + if extraenv is not None: + env.update(extraenv) + self._pcall(argv, cwd=self.envconfig.envlogdir, + extraenv=env, action=action) def _install(self, deps, extraopts=None, action=None): if not deps: @@ -305,8 +308,12 @@ extraopts = extraopts or [] for ixserver in l: + extraenv = hack_home_env( + homedir=self.envconfig.envtmpdir.join("pseudo-home"), + index_url = ixserver.url) args = d[ixserver] + extraopts - self.run_install_command(args, ixserver.url, action) + self.run_install_command(args, ixserver.url, action, + extraenv=extraenv) def _getenv(self): env = self.envconfig.setenv @@ -415,3 +422,22 @@ # Python launcher py.exe if m: locate_via_py(*m.groups()) + + +def hack_home_env(homedir, index_url): + # XXX HACK (this could also live with tox itself, consider) + # if tox uses pip on a package that requires setup_requires + # the index url set with pip is usually not recognized + # because it is setuptools executing very early. + # We therefore run the tox command in an artifical home + # directory and set .pydistutils.cfg and pip.conf files + # accordingly. + if not homedir.check(): + homedir.ensure(dir=1) + d = dict(HOME=str(homedir)) + if index_url: + homedir.join(".pydistutils.cfg").write( + "[easy_install]\n" + "index_url = %s\n" % index_url) + d["PIP_INDEX_URL"] = index_url + return d Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 14 00:49:26 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Tue, 13 Aug 2013 22:49:26 -0000 Subject: [Pytest-commit] commit/tox: hpk42: don't try to auto-test docs - they too often fail on checklinks Message-ID: <20130813224926.7775.84223@app12.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/9034cf3f79b7/ Changeset: 9034cf3f79b7 User: hpk42 Date: 2013-08-14 00:47:09 Summary: don't try to auto-test docs - they too often fail on checklinks Affected #: 1 file diff -r 6aec60d13d3a4fed9496efd7310e76bf2beaf529 -r 9034cf3f79b762e41511e2a536d22207b7357981 tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py26,py32,py33,docs,pypy +envlist=py27,py26,py32,py33,pypy [testenv:X] commands=echo {posargs} Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Wed Aug 14 07:05:39 2013 From: issues-reply at bitbucket.org (Anthon van der Neut) Date: Wed, 14 Aug 2013 05:05:39 -0000 Subject: [Pytest-commit] Issue #113: running 'tox -- -k test_setup_py' on tox should not overwrite tox' own tox.ini (hpk42/tox) Message-ID: <20130814050539.27996.74551@app04.ash-private.bitbucket.org> New issue 113: running 'tox -- -k test_setup_py' on tox should not overwrite tox' own tox.ini https://bitbucket.org/hpk42/tox/issue/113/running-tox-k-test_setup_py-on-tox-should Anthon van der Neut: While adding some tests in test_z_cmdline, all with the substring 'test_setup_py' I selected only these for execution and quicker testing with 'tox -- -k test_setup_py'. Everything was fine until I ran tox again and after some digging noticed that tox' own tox.ini was overwritten by tox itself. 'hg revert tox.ini' and 'chmod 400 tox.ini' showed in a rerun that test_quickstart.py: test_setup_py_test() was the cause of the problem. From commits-noreply at bitbucket.org Wed Aug 14 08:00:10 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 14 Aug 2013 06:00:10 -0000 Subject: [Pytest-commit] commit/tox: hpk42: fix issue113: let all quickstart test work in fresh temp dir. Thanks Anthon van der Neut Message-ID: <20130814060010.27468.85560@app13.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/e4fd16d2b535/ Changeset: e4fd16d2b535 User: hpk42 Date: 2013-08-14 08:00:03 Summary: fix issue113: let all quickstart test work in fresh temp dir. Thanks Anthon van der Neut for reporting the underlying ordering bug. Affected #: 1 file diff -r 9034cf3f79b762e41511e2a536d22207b7357981 -r e4fd16d2b53588a3b65c19dd194797f89bba7f68 tests/test_quickstart.py --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -2,11 +2,11 @@ import tox._quickstart + at pytest.fixture(autouse=True) +def cleandir(tmpdir): + tmpdir.chdir() class TestToxQuickstartMain(object): - @pytest.fixture(autouse=True) - def cleandir(self, tmpdir): - tmpdir.chdir() def mock_term_input_return_values(self, return_values): for return_val in return_values: Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 14 08:05:22 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 14 Aug 2013 06:05:22 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20130814060522.904.68092@app08.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/5e3344f746e7/ Changeset: 5e3344f746e7 Branch: use-venv191-pip13-for-python25 User: mete0r_kr Date: 2013-08-13 19:32:35 Summary: use inlined virtualenv-1.9.1 and pip<1.4 for CPython 2.5 / Jython 2.5 Since virtualenv 1.10 and pip 1.4 has dropped python 2.5 support, use inlined virtualenv-1.9.1 and Pip<1.4 for CPython 2.5 / Jython 2.5 Affected #: 2 files diff -r 3be5bca16f8b0c4394060b8e0377ef1883c518c7 -r 5e3344f746e7954a06ac56c50cc8ff4359f95576 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -4,6 +4,7 @@ import os, sys from tox._venv import VirtualEnv, CreationConfig, getdigest from tox._venv import find_executable +from tox._venv import _getinterpreterversion #def test_global_virtualenv(capfd): # v = VirtualEnv() @@ -80,6 +81,11 @@ py.test.raises(tox.exception.InterpreterNotFound, venv.getsupportedinterpreter) +def test_getinterpreterversion(): + from distutils.sysconfig import get_python_version + version = _getinterpreterversion(sys.executable) + assert version == get_python_version() + def test_create(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:py123] diff -r 3be5bca16f8b0c4394060b8e0377ef1883c518c7 -r 5e3344f746e7954a06ac56c50cc8ff4359f95576 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -1,5 +1,7 @@ from __future__ import with_statement import sys, os, re +import textwrap +import subprocess import py import tox from tox._config import DepConfig @@ -180,10 +182,15 @@ if action is None: action = self.session.newaction(self, "create") config_interpreter = self.getsupportedinterpreter() - f, path, _ = py.std.imp.find_module("virtualenv") - f.close() - venvscript = path.rstrip("co") - #venvscript = py.path.local(tox.__file__).dirpath("virtualenv.py") + config_interpreter_version = _getinterpreterversion(config_interpreter) + use_venv191 = config_interpreter_version < '2.6' + use_pip13 = config_interpreter_version < '2.6' + if not use_venv191: + f, path, _ = py.std.imp.find_module("virtualenv") + f.close() + venvscript = path.rstrip("co") + else: + venvscript = py.path.local(tox.__file__).dirpath("virtualenv-1.9.1.py") args = [config_interpreter, venvscript] if self.envconfig.distribute: args.append("--distribute") @@ -204,6 +211,12 @@ args.append(self.path.basename) self._pcall(args, venv=False, action=action, cwd=basepath) self.just_created = True + if use_pip13: + indexserver = self.envconfig.config.indexserver['default'] + action = self.session.newaction(self, "pip_downgrade") + action.setactivity('pip-downgrade', 'pip<1.4') + argv = ["easy_install"] + self._commoninstallopts(indexserver) + ['pip<1.4'] + self._pcall(argv, cwd=self.envconfig.envlogdir, action=action) def finish(self): self._getliveconfig().writeconfig(self.path_config) @@ -366,6 +379,23 @@ self.session.report.verbosity2("setting PATH=%s" % os.environ["PATH"]) return oldPATH +def _getinterpreterversion(executable): + print_python_version = textwrap.dedent(""" + from distutils.sysconfig import get_python_version + print(get_python_version()) + """) + proc = subprocess.Popen([str(executable), '-c', print_python_version], + stdout=subprocess.PIPE) + odata, edata = proc.communicate() + if proc.returncode: + raise tox.exception.UnsupportedInterpreter( + "Error getting python version from %s" % executable) + if sys.version_info[0] == 3: + string = str + else: + string = lambda x, encoding: str(x) + return string(odata, 'ascii').strip() + def getdigest(path): path = py.path.local(path) if not path.check(file=1): https://bitbucket.org/hpk42/tox/commits/42280ff26e8c/ Changeset: 42280ff26e8c Branch: use-venv191-pip13-for-python25 User: mete0r_kr Date: 2013-08-13 22:48:03 Summary: Add missing virtualenv-1.9.1.py and fix to use indexserver.url and remove textwrap usage Affected #: 2 files diff -r 5e3344f746e7954a06ac56c50cc8ff4359f95576 -r 42280ff26e8c7eb31eea06d3b550664bb56407a4 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -1,6 +1,5 @@ from __future__ import with_statement import sys, os, re -import textwrap import subprocess import py import tox @@ -212,7 +211,7 @@ self._pcall(args, venv=False, action=action, cwd=basepath) self.just_created = True if use_pip13: - indexserver = self.envconfig.config.indexserver['default'] + indexserver = self.envconfig.config.indexserver['default'].url action = self.session.newaction(self, "pip_downgrade") action.setactivity('pip-downgrade', 'pip<1.4') argv = ["easy_install"] + self._commoninstallopts(indexserver) + ['pip<1.4'] @@ -380,10 +379,9 @@ return oldPATH def _getinterpreterversion(executable): - print_python_version = textwrap.dedent(""" - from distutils.sysconfig import get_python_version - print(get_python_version()) - """) + print_python_version = ( + 'from distutils.sysconfig import get_python_version\n' + 'print(get_python_version())\n') proc = subprocess.Popen([str(executable), '-c', print_python_version], stdout=subprocess.PIPE) odata, edata = proc.communicate() This diff is so big that we needed to truncate the remainder. https://bitbucket.org/hpk42/tox/commits/2f81a12f84bc/ Changeset: 2f81a12f84bc User: hpk42 Date: 2013-08-14 08:05:21 Summary: ref issue91 - use a vendored virtualenv-1.9.1 when creating python-2.5 environments. Merged in mete0r_kr/tox/use-venv191-pip13-for-python25 (pull request #65) use inlined virtualenv-1.9.1 and pip<1.4 for CPython 2.5 / Jython 2.5 (revised) Affected #: 3 files diff -r e4fd16d2b53588a3b65c19dd194797f89bba7f68 -r 2f81a12f84bc87215c4c5862c3555111b5ab1991 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -4,6 +4,7 @@ import os, sys from tox._venv import VirtualEnv, CreationConfig, getdigest from tox._venv import find_executable +from tox._venv import _getinterpreterversion #def test_global_virtualenv(capfd): # v = VirtualEnv() @@ -80,6 +81,11 @@ py.test.raises(tox.exception.InterpreterNotFound, venv.getsupportedinterpreter) +def test_getinterpreterversion(): + from distutils.sysconfig import get_python_version + version = _getinterpreterversion(sys.executable) + assert version == get_python_version() + def test_create(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:py123] diff -r e4fd16d2b53588a3b65c19dd194797f89bba7f68 -r 2f81a12f84bc87215c4c5862c3555111b5ab1991 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -1,5 +1,6 @@ from __future__ import with_statement import sys, os, re +import subprocess import py import tox from tox._config import DepConfig @@ -180,10 +181,15 @@ if action is None: action = self.session.newaction(self, "create") config_interpreter = self.getsupportedinterpreter() - f, path, _ = py.std.imp.find_module("virtualenv") - f.close() - venvscript = path.rstrip("co") - #venvscript = py.path.local(tox.__file__).dirpath("virtualenv.py") + config_interpreter_version = _getinterpreterversion(config_interpreter) + use_venv191 = config_interpreter_version < '2.6' + use_pip13 = config_interpreter_version < '2.6' + if not use_venv191: + f, path, _ = py.std.imp.find_module("virtualenv") + f.close() + venvscript = path.rstrip("co") + else: + venvscript = py.path.local(tox.__file__).dirpath("virtualenv-1.9.1.py") args = [config_interpreter, venvscript] if self.envconfig.distribute: args.append("--distribute") @@ -204,6 +210,12 @@ args.append(self.path.basename) self._pcall(args, venv=False, action=action, cwd=basepath) self.just_created = True + if use_pip13: + indexserver = self.envconfig.config.indexserver['default'].url + action = self.session.newaction(self, "pip_downgrade") + action.setactivity('pip-downgrade', 'pip<1.4') + argv = ["easy_install"] + self._commoninstallopts(indexserver) + ['pip<1.4'] + self._pcall(argv, cwd=self.envconfig.envlogdir, action=action) def finish(self): self._getliveconfig().writeconfig(self.path_config) @@ -372,6 +384,22 @@ self.session.report.verbosity2("setting PATH=%s" % os.environ["PATH"]) return oldPATH +def _getinterpreterversion(executable): + print_python_version = ( + 'from distutils.sysconfig import get_python_version\n' + 'print(get_python_version())\n') + proc = subprocess.Popen([str(executable), '-c', print_python_version], + stdout=subprocess.PIPE) + odata, edata = proc.communicate() + if proc.returncode: + raise tox.exception.UnsupportedInterpreter( + "Error getting python version from %s" % executable) + if sys.version_info[0] == 3: + string = str + else: + string = lambda x, encoding: str(x) + return string(odata, 'ascii').strip() + def getdigest(path): path = py.path.local(path) if not path.check(file=1): This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 14 09:58:16 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 14 Aug 2013 07:58:16 -0000 Subject: [Pytest-commit] commit/tox: Anthon van der Neut: issue_1_empty_setup_py: fix for issue #1: Empty setup.py leads to very obscure error Message-ID: <20130814075816.17427.37187@app13.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/4414956b0a64/ Changeset: 4414956b0a64 User: Anthon van der Neut Date: 2013-08-14 08:57:10 Summary: issue_1_empty_setup_py: fix for issue #1: Empty setup.py leads to very obscure error This was caused by no dist directory being created and listing that directory raising an exception. - added some test for setup.py: - empty - only start of line comment - some code, but no setup() - on error finding the dist - check if empty or comment only setup.py: msg that setup.py is empty - msg to check 'python setup.py sdist' by hand Affected #: 2 files diff -r 2f81a12f84bc87215c4c5862c3555111b5ab1991 -r 4414956b0a64281d79e3fcd986516df154f6efe1 tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -269,6 +269,54 @@ result = cmd.run("tox", ) assert result.ret == 0 +def test_minimal_setup_py_empty(cmd, initproj): + initproj("pkg123-0.7", filedefs={ + 'tests': {'test_hello.py': "def test_hello(): pass"}, + 'setup.py': """ + """ + , + 'tox.ini': '' + + }) + result = cmd.run("tox", ) + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "*ERROR*empty*", + ]) + +def test_minimal_setup_py_comment_only(cmd, initproj): + initproj("pkg123-0.7", filedefs={ + 'tests': {'test_hello.py': "def test_hello(): pass"}, + 'setup.py': """\n# some comment + + """ + , + 'tox.ini': '' + + }) + result = cmd.run("tox", ) + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "*ERROR*empty*", + ]) + +def test_minimal_setup_py_non_functional(cmd, initproj): + initproj("pkg123-0.7", filedefs={ + 'tests': {'test_hello.py': "def test_hello(): pass"}, + 'setup.py': """ + import sys + + """ + , + 'tox.ini': '' + + }) + result = cmd.run("tox", ) + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "*ERROR*check setup.py*", + ]) + def test_sdist_fails(cmd, initproj): initproj("pkg123-0.7", filedefs={ 'tests': {'test_hello.py': "def test_hello(): pass"}, diff -r 2f81a12f84bc87215c4c5862c3555111b5ab1991 -r 4414956b0a64281d79e3fcd986516df154f6efe1 tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -321,7 +321,27 @@ action.popen([sys.executable, setup, "sdist", "--formats=zip", "--dist-dir", self.config.distdir, ], cwd=self.config.setupdir) - return self.config.distdir.listdir()[0] + try: + return self.config.distdir.listdir()[0] + except py.error.ENOENT: + # check if empty or comment only + data = [] + with open(str(setup)) as fp: + for line in fp: + if line and line[0] == '#': + continue + data.append(line) + if not ''.join(data).strip(): + self.report.error( + 'setup.py is empty' + ) + raise SystemExit(1) + self.report.error( + 'No dist directory found. Please check setup.py, e.g with:\n'\ + ' python setup.py sdist' + ) + raise SystemExit(1) + def make_emptydir(self, path): if path.check(): Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 14 10:02:35 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 14 Aug 2013 08:02:35 -0000 Subject: [Pytest-commit] commit/tox: 3 new changesets Message-ID: <20130814080235.3574.12154@app06.ash-private.bitbucket.org> 3 new commits in tox: https://bitbucket.org/hpk42/tox/commits/ffb519dcbb6e/ Changeset: ffb519dcbb6e User: hpk42 Date: 2013-08-14 09:59:02 Summary: fix issue1: empty setup files are properly detected Affected #: 1 file diff -r 4414956b0a64281d79e3fcd986516df154f6efe1 -r ffb519dcbb6ea0ebdf3339dfa10d4ce6a6df6457 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ 1.6.0.dev ----------------- +- fix issue1: empty setup files are properly detected + - during installation of dependencies HOME is set to a pseudo location (envtmpdir/pseudo-home). If an index url was specified a .pydistutils.cfg file will be written so that index_url https://bitbucket.org/hpk42/tox/commits/182e8f03b686/ Changeset: 182e8f03b686 User: hpk42 Date: 2013-08-14 09:59:14 Summary: fix issue1: empty setup files are properly detected, thanks Anthon van der Neuth Affected #: 1 file diff -r ffb519dcbb6ea0ebdf3339dfa10d4ce6a6df6457 -r 182e8f03b6865117f8191035cc95a0865bacfb92 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ 1.6.0.dev ----------------- -- fix issue1: empty setup files are properly detected +- fix issue1: empty setup files are properly detected, thanks Anthon van + der Neuth - during installation of dependencies HOME is set to a pseudo location (envtmpdir/pseudo-home). If an index url was specified https://bitbucket.org/hpk42/tox/commits/9fd1946709d3/ Changeset: 9fd1946709d3 User: hpk42 Date: 2013-08-14 09:59:16 Summary: ref pull request 65 make tox run its tests against python2.5 as well vendor virtualenv as 'virtualenv.py' instead of 'virtualenv-1.9.1.py' which triggers some weird logic preventing tox to run its tests on itself. Affected #: 9 files diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c setup.py --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', author_email='holger at merlinux.eu', - packages=['tox', ], + packages=['tox', 'tox.vendor'], entry_points={'console_scripts': 'tox=tox:cmdline\ntox-quickstart=tox._quickstart:main'}, # we use a public tox version to test, see tox.ini's testenv # "deps" definition for the required dependencies diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -6,6 +6,8 @@ from tox._venv import find_executable from tox._venv import _getinterpreterversion +py25calls = int(sys.version_info[:2] == (2,5)) + #def test_global_virtualenv(capfd): # v = VirtualEnv() # l = v.list() @@ -98,7 +100,7 @@ l = mocksession._pcalls assert len(l) >= 1 args = l[0].args - assert str(args[1]).endswith("virtualenv.py") + assert "virtualenv" in str(args[1]) if sys.platform != "win32": # realpath is needed for stuff like the debian symlinks assert py.path.local(sys.executable).realpath() == args[0] @@ -173,15 +175,15 @@ venv = mocksession.getenv("py123") venv.create() l = mocksession._pcalls - assert len(l) == 1 + assert len(l) == 1 + py25calls distshare = venv.session.config.distshare distshare.ensure("dep1-1.0.zip") distshare.ensure("dep1-1.1.zip") venv.install_deps() - assert len(l) == 2 - args = l[1].args - assert l[1].cwd == venv.envconfig.envlogdir + assert len(l) == 2 + py25calls + args = l[-1].args + assert l[-1].cwd == venv.envconfig.envlogdir assert "pip" in str(args[0]) assert args[1] == "install" #arg = "--download-cache=" + str(venv.envconfig.downloadcache) @@ -206,12 +208,12 @@ venv = mocksession.getenv("py123") venv.create() l = mocksession._pcalls - assert len(l) == 1 + assert len(l) == 1 + py25calls venv.install_deps() - assert len(l) == 2 - args = l[1].args - assert l[1].cwd == venv.envconfig.envlogdir + assert len(l) == 2 + py25calls + args = l[-1].args + assert l[-1].cwd == venv.envconfig.envlogdir assert "pip" in str(args[0]) assert args[1] == "install" assert "dep1" in args @@ -234,7 +236,7 @@ venv = mocksession.getenv('py123') venv.create() l = mocksession._pcalls - assert len(l) == 1 + assert len(l) == 1 + py25calls l[:] = [] venv.install_deps() diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -3,9 +3,18 @@ import pytest import sys from tox._pytestplugin import ReportExpectMock +try: + import json +except ImportError: + import simplejson as json pytest_plugins = "pytester" +if sys.version_info < (2,6): + PIP_INSECURE = "setenv = PIP_INSECURE=1" +else: + PIP_INSECURE = "" + from tox._cmdline import Session from tox._config import parseconfig @@ -356,6 +365,8 @@ "*InvocationError*", ]) + + class TestToxRun: @pytest.fixture def example123(self, initproj): @@ -368,9 +379,10 @@ 'tox.ini': ''' [testenv] changedir=tests + %s commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml deps=pytest - ''' + ''' % PIP_INSECURE }) def test_toxuone_env(self, cmd, example123): @@ -407,7 +419,7 @@ jsonpath = cmd.tmpdir.join("res.json") result = cmd.run("tox", "--result-json", jsonpath) assert result.ret == 1 - data = py.std.json.load(jsonpath.open("r")) + data = json.load(jsonpath.open("r")) verify_json_report_format(data) result.stdout.fnmatch_lines([ "*1 failed*", @@ -461,10 +473,11 @@ [testenv] usedevelop=True changedir=tests + %s commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml [] deps=pytest - ''' + ''' % PIP_INSECURE }) result = cmd.run("tox", "-v") assert not result.ret diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tox.ini --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py26,py32,py33,pypy +envlist=py25,py27,py26,py32,py33,pypy [testenv:X] commands=echo {posargs} diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -506,8 +506,12 @@ def info_versions(self): versions = ['tox-%s' % tox.__version__] - version = py.process.cmdexec("virtualenv --version") - versions.append("virtualenv-%s" % version.strip()) + try: + version = py.process.cmdexec("virtualenv --version") + except py.process.cmdexec.Error: + versions.append("virtualenv-1.9.1 (vendored)") + else: + versions.append("virtualenv-%s" % version.strip()) self.report.keyvalue("tool-versions:", " ".join(versions)) diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -181,7 +181,8 @@ if action is None: action = self.session.newaction(self, "create") config_interpreter = self.getsupportedinterpreter() - config_interpreter_version = _getinterpreterversion(config_interpreter) + config_interpreter_version = _getinterpreterversion( + config_interpreter) use_venv191 = config_interpreter_version < '2.6' use_pip13 = config_interpreter_version < '2.6' if not use_venv191: @@ -189,15 +190,17 @@ f.close() venvscript = path.rstrip("co") else: - venvscript = py.path.local(tox.__file__).dirpath("virtualenv-1.9.1.py") - args = [config_interpreter, venvscript] + venvscript = py.path.local(tox.__file__).dirpath( + "vendor", "virtualenv.py") + args = [config_interpreter, str(venvscript)] if self.envconfig.distribute: args.append("--distribute") else: args.append("--setuptools") if self.envconfig.sitepackages: args.append('--system-site-packages') - # add interpreter explicitly, to prevent using default (virtualenv.ini) + # add interpreter explicitly, to prevent using + # default (virtualenv.ini) args.extend(['--python', str(config_interpreter)]) #if sys.platform == "win32": # f, path, _ = py.std.imp.find_module("virtualenv") @@ -214,8 +217,10 @@ indexserver = self.envconfig.config.indexserver['default'].url action = self.session.newaction(self, "pip_downgrade") action.setactivity('pip-downgrade', 'pip<1.4') - argv = ["easy_install"] + self._commoninstallopts(indexserver) + ['pip<1.4'] - self._pcall(argv, cwd=self.envconfig.envlogdir, action=action) + argv = ["easy_install"] + \ + self._installopts(indexserver) + ['pip<1.4'] + self._pcall(argv, cwd=self.envconfig.envlogdir, + action=action) def finish(self): self._getliveconfig().writeconfig(self.path_config) diff -r 182e8f03b6865117f8191035cc95a0865bacfb92 -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c tox/vendor/__init__.py --- /dev/null +++ b/tox/vendor/__init__.py @@ -0,0 +1,1 @@ +# This diff is so big that we needed to truncate the remainder. Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 14 15:28:06 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 14 Aug 2013 13:28:06 -0000 Subject: [Pytest-commit] commit/pytest: 5 new changesets Message-ID: <20130814132806.11324.88156@app11.ash-private.bitbucket.org> 5 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/e8b5e88650aa/ Changeset: e8b5e88650aa User: hpk42 Date: 2013-08-11 18:19:58 Summary: strike distribute dep Affected #: 3 files diff -r 5260ac5bdfc087a0e2612f4fea367d786bec42ba -r e8b5e88650aaf0af519c25b774f14ecf4bc8e024 _pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.4.0.dev10' +__version__ = '2.4.0.dev11' diff -r 5260ac5bdfc087a0e2612f4fea367d786bec42ba -r e8b5e88650aaf0af519c25b774f14ecf4bc8e024 setup.py --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.4.0.dev10', + version='2.4.0.dev11', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff -r 5260ac5bdfc087a0e2612f4fea367d786bec42ba -r e8b5e88650aaf0af519c25b774f14ecf4bc8e024 tox.ini --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,6 @@ deps=pytest-xdist setenv= PYTHONDONTWRITEBYTECODE=1 -distribute=true commands= py.test -n3 -rfsxX \ --junitxml={envlogdir}/junit-{envname}.xml {posargs:testing} https://bitbucket.org/hpk42/pytest/commits/d08f04f46fdc/ Changeset: d08f04f46fdc Branch: quiet-color-summary User: hpk42 Date: 2013-08-14 15:27:13 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/bd32a2ccf9c7/ Changeset: bd32a2ccf9c7 Branch: argcomplete User: hpk42 Date: 2013-08-14 15:27:30 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/a761ebdef9ea/ Changeset: a761ebdef9ea Branch: tox_reference User: hpk42 Date: 2013-08-14 15:27:39 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/6cc0b0dbb07f/ Changeset: 6cc0b0dbb07f Branch: opt-drop-non-hyphened-long-options User: hpk42 Date: 2013-08-14 15:27:47 Summary: close branch Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Wed Aug 14 15:34:44 2013 From: notifications at travis-ci.org (Travis CI) Date: Wed, 14 Aug 2013 13:34:44 +0000 Subject: [Pytest-commit] [Broken] hpk42/pytest#32 (master - 8f9b4fe) Message-ID: <520b8773d2f00_22bd6260564@71f20499-f1c2-4963-853b-f3d7de358baa.mail> Build Update for hpk42/pytest ------------------------------------- Build: #32 Status: Broken Duration: 3 minutes and 56 seconds Commit: 8f9b4fe (master) Author: holger krekel Message: strike distribute dep View the changeset: https://github.com/hpk42/pytest/compare/694aa9030a31...8f9b4fef4d0e View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/10198271 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 15 07:06:28 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 05:06:28 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130815050628.19361.35412@app02.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/3e0a7136a103/ Changeset: 3e0a7136a103 Branch: overriden-fixture-finalizer User: bubenkoff Date: 2013-08-14 10:09:02 Summary: ignores Affected #: 1 file diff -r 5260ac5bdfc087a0e2612f4fea367d786bec42ba -r 3e0a7136a1034f0d3e096ec29362360c908a4f40 .hgignore --- a/.hgignore +++ b/.hgignore @@ -32,3 +32,4 @@ .cache .coverage .ropeproject +*.sublime-* https://bitbucket.org/hpk42/pytest/commits/992d815488fa/ Changeset: 992d815488fa Branch: overriden-fixture-finalizer User: bubenkoff Date: 2013-08-14 13:58:59 Summary: tests for fixture finalizers Affected #: 1 file diff -r 3e0a7136a1034f0d3e096ec29362360c908a4f40 -r 992d815488fab984bb92d3351b8e3208cf3b8dc5 testing/test_fixture_finalizer.py --- /dev/null +++ b/testing/test_fixture_finalizer.py @@ -0,0 +1,30 @@ +"""Tests for fixtures with different scoping.""" +import py.code + + +def test_fixture_finalizer(testdir): + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def browser(request): + + def finalize(): + print 'Finalized' + request.addfinalizer(finalize) + return {} + """) + b = testdir.mkdir("subdir") + b.join("test_overriden_fixture_finalizer.py").write(py.code.Source(""" + import pytest + @pytest.fixture + def browser(browser): + browser['visited'] = True + return browser + + def test_browser(browser): + assert browser['visited'] is True + """)) + reprec = testdir.runpytest("-s") + for test in ['test_browser']: + reprec.stdout.fnmatch_lines('Finalized') https://bitbucket.org/hpk42/pytest/commits/ffcbf3e090c2/ Changeset: ffcbf3e090c2 User: hpk42 Date: 2013-08-15 07:06:25 Summary: Merged in bubenkoff/pytest/overriden-fixture-finalizer (pull request #64) overriden fixture finalizer tests Affected #: 2 files diff -r e8b5e88650aaf0af519c25b774f14ecf4bc8e024 -r ffcbf3e090c24239ab12a092c929fcecdfe49369 .hgignore --- a/.hgignore +++ b/.hgignore @@ -32,3 +32,4 @@ .cache .coverage .ropeproject +*.sublime-* diff -r e8b5e88650aaf0af519c25b774f14ecf4bc8e024 -r ffcbf3e090c24239ab12a092c929fcecdfe49369 testing/test_fixture_finalizer.py --- /dev/null +++ b/testing/test_fixture_finalizer.py @@ -0,0 +1,30 @@ +"""Tests for fixtures with different scoping.""" +import py.code + + +def test_fixture_finalizer(testdir): + testdir.makeconftest(""" + import pytest + + @pytest.fixture + def browser(request): + + def finalize(): + print 'Finalized' + request.addfinalizer(finalize) + return {} + """) + b = testdir.mkdir("subdir") + b.join("test_overriden_fixture_finalizer.py").write(py.code.Source(""" + import pytest + @pytest.fixture + def browser(browser): + browser['visited'] = True + return browser + + def test_browser(browser): + assert browser['visited'] is True + """)) + reprec = testdir.runpytest("-s") + for test in ['test_browser']: + reprec.stdout.fnmatch_lines('Finalized') Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 07:12:13 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 05:12:13 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: close branch Message-ID: <20130815051213.28524.41817@app03.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/305ffa6e868f/ Changeset: 305ffa6e868f Branch: overriden-fixture-finalizer User: hpk42 Date: 2013-08-15 07:12:03 Summary: close branch Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 07:13:50 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 05:13:50 -0000 Subject: [Pytest-commit] commit/tox: 4 new changesets Message-ID: <20130815051350.1863.45190@app05.ash-private.bitbucket.org> 4 new commits in tox: https://bitbucket.org/hpk42/tox/commits/9aaf5c8111de/ Changeset: 9aaf5c8111de Branch: posargs-fix User: hpk42 Date: 2013-08-15 07:13:35 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/tox/commits/5e47ba93663b/ Changeset: 5e47ba93663b Branch: issue-10-pip-UnicodeDecodeError User: hpk42 Date: 2013-08-15 07:13:35 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/tox/commits/b33450bbc672/ Changeset: b33450bbc672 Branch: jezdez/added-readme-to-package-manifest-templat-1372083252428 User: hpk42 Date: 2013-08-15 07:13:35 Summary: close branch Affected #: 0 files https://bitbucket.org/hpk42/tox/commits/ada8604b306e/ Changeset: ada8604b306e Branch: use-venv191-pip13-for-python25 User: hpk42 Date: 2013-08-15 07:13:35 Summary: close branch Affected #: 0 files Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Aug 15 07:11:19 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 15 Aug 2013 05:11:19 +0000 Subject: [Pytest-commit] [Still Failing] hpk42/pytest#33 (master - 00c85c4) Message-ID: <520c62f79b460_2288815628c@f18df8e2-3d12-4df3-9b78-3fda1841f526.mail> Build Update for hpk42/pytest ------------------------------------- Build: #33 Status: Still Failing Duration: 3 minutes and 41 seconds Commit: 00c85c4 (master) Author: holger krekel Message: Merged in bubenkoff/pytest/overriden-fixture-finalizer (pull request #64) overriden fixture finalizer tests View the changeset: https://github.com/hpk42/pytest/compare/8f9b4fef4d0e...00c85c411a6c View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/10228417 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 15 11:32:14 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 09:32:14 -0000 Subject: [Pytest-commit] commit/tox: carljm: Add doc examples of using easy_install and pip install --find-links. Message-ID: <20130815093214.24149.40697@app11.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/394c7438efdc/ Changeset: 394c7438efdc User: carljm Date: 2013-08-14 23:24:23 Summary: Add doc examples of using easy_install and pip install --find-links. Affected #: 1 file diff -r 9fd1946709d37f4ee04ea6159e730096bf9ad87c -r 394c7438efdcae278cca3c0bbd6bde6f32aa4362 doc/example/basic.txt --- a/doc/example/basic.txt +++ b/doc/example/basic.txt @@ -109,6 +109,35 @@ tox -i DEV=http://pypi.python.org/simple # changes :DEV: package URLs tox -i http://pypi.python.org/simple # changes default +further customizing installation +--------------------------------- + +.. versionadded:: 1.6 + +By default tox uses `pip`_ to install packages (both the sdist of your +package-under-test and any dependencies you specify in ``tox.ini``) into each +test virtualenv, with a command-line like ``pip install --pre +SomePackage==1.0``. + +You can fully customize tox's install-command in your ``tox.ini`` with the +``install_command`` option. For instance, to use ``easy_install`` instead of +`pip`_:: + + [testenv] + install_command = easy_install {packages} + +Or to use pip's ``--find-links`` and ``--no-index`` options to specify an +alternative source for your dependencies:: + + [testenv] + install_command = pip install --pre --find-links http://packages.example.com --no-index {opts} {packages} + +(Including ``{opts}`` is only necessary if you want your install command to +also respect tox's options for setting the download cache and package index +server). + +.. _pip: http://pip-installer.org + forcing re-creation of virtual environments ----------------------------------------------- Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 13:03:22 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 11:03:22 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130815110322.2699.52717@app07.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/7e041e5cf6de/ Changeset: 7e041e5cf6de Branch: fix-broken-tests User: bubenkoff Date: 2013-08-15 09:25:00 Summary: initial Affected #: 0 files https://bitbucket.org/hpk42/pytest/commits/78c8ce18b913/ Changeset: 78c8ce18b913 Branch: fix-broken-tests User: bubenkoff Date: 2013-08-15 11:52:55 Summary: fix broken python3 and python2.5 tests Affected #: 2 files diff -r 7e041e5cf6de7f0e1a39cfdd7ee1ab2330caec15 -r 78c8ce18b913ff27e9ed05ff77f352c771e9ee5a testing/test_fixture_finalizer.py --- a/testing/test_fixture_finalizer.py +++ b/testing/test_fixture_finalizer.py @@ -5,12 +5,13 @@ def test_fixture_finalizer(testdir): testdir.makeconftest(""" import pytest + import sys @pytest.fixture def browser(request): def finalize(): - print 'Finalized' + sys.stdout.write('Finalized') request.addfinalizer(finalize) return {} """) diff -r 7e041e5cf6de7f0e1a39cfdd7ee1ab2330caec15 -r 78c8ce18b913ff27e9ed05ff77f352c771e9ee5a tox.ini --- a/tox.ini +++ b/tox.ini @@ -31,6 +31,7 @@ changedir=. basepython=python2.7 deps=pytest-xdist +distribute=true setenv= PYTHONDONTWRITEBYTECODE=1 commands= https://bitbucket.org/hpk42/pytest/commits/3067cee3dcbb/ Changeset: 3067cee3dcbb User: hpk42 Date: 2013-08-15 13:03:20 Summary: Merged in bubenkoff/pytest/fix-broken-tests (pull request #65) Fix broken python3 and python2.5 tests Affected #: 2 files diff -r ffcbf3e090c24239ab12a092c929fcecdfe49369 -r 3067cee3dcbbb487bdc65e7e2d0ff30852815f8a testing/test_fixture_finalizer.py --- a/testing/test_fixture_finalizer.py +++ b/testing/test_fixture_finalizer.py @@ -5,12 +5,13 @@ def test_fixture_finalizer(testdir): testdir.makeconftest(""" import pytest + import sys @pytest.fixture def browser(request): def finalize(): - print 'Finalized' + sys.stdout.write('Finalized') request.addfinalizer(finalize) return {} """) diff -r ffcbf3e090c24239ab12a092c929fcecdfe49369 -r 3067cee3dcbbb487bdc65e7e2d0ff30852815f8a tox.ini --- a/tox.ini +++ b/tox.ini @@ -31,6 +31,7 @@ changedir=. basepython=python2.7 deps=pytest-xdist +distribute=true setenv= PYTHONDONTWRITEBYTECODE=1 commands= Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 13:05:39 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 11:05:39 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: fix manifest Message-ID: <20130815110539.6201.82628@app01.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/6020045d40a9/ Changeset: 6020045d40a9 User: hpk42 Date: 2013-08-15 13:05:01 Summary: fix manifest Affected #: 1 file diff -r 3067cee3dcbbb487bdc65e7e2d0ff30852815f8a -r 6020045d40a9f50cf62019657a7b58caf6c80435 MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include CHANGELOG include README.rst include setup.py -include distribute_setup.py include tox.ini include LICENSE graft doc Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Thu Aug 15 13:09:57 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 15 Aug 2013 11:09:57 +0000 Subject: [Pytest-commit] [Fixed] hpk42/pytest#34 (master - 9fef3c4) Message-ID: <520cb7059eb10_223b3f416156e@cace8eca-aca6-479a-b9c8-1470979395d4.mail> Build Update for hpk42/pytest ------------------------------------- Build: #34 Status: Fixed Duration: 5 minutes and 17 seconds Commit: 9fef3c4 (master) Author: holger krekel Message: Merged in bubenkoff/pytest/fix-broken-tests (pull request #65) Fix broken python3 and python2.5 tests View the changeset: https://github.com/hpk42/pytest/compare/00c85c411a6c...9fef3c44b40f View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/10236392 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From notifications at travis-ci.org Thu Aug 15 13:10:29 2013 From: notifications at travis-ci.org (Travis CI) Date: Thu, 15 Aug 2013 11:10:29 +0000 Subject: [Pytest-commit] [Fixed] hpk42/pytest#35 (master - 9f8307a) Message-ID: <520cb7254c2c0_267943016469@b597163a-d566-4209-a74f-4c4b79b40f75.mail> Build Update for hpk42/pytest ------------------------------------- Build: #35 Status: Fixed Duration: 4 minutes and 1 second Commit: 9f8307a (master) Author: holger krekel Message: fix manifest View the changeset: https://github.com/hpk42/pytest/compare/9fef3c44b40f...9f8307afbfd7 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/10236461 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From commits-noreply at bitbucket.org Thu Aug 15 15:20:16 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 13:20:16 -0000 Subject: [Pytest-commit] commit/tox: hpk42: Added tag 1.6.0 for changeset 33e5e5dff406 Message-ID: <20130815132016.13766.37268@app03.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/a7ef669e28c1/ Changeset: a7ef669e28c1 User: hpk42 Date: 2013-08-15 15:20:09 Summary: Added tag 1.6.0 for changeset 33e5e5dff406 Affected #: 1 file diff -r 33e5e5dff406e699893a65ecd5044d3eee35b69b -r a7ef669e28c1f367517a65f005509a238b0c1bee .hgtags --- a/.hgtags +++ b/.hgtags @@ -13,3 +13,4 @@ 668f66e4781b0beae509db8125dc02218f6efe4e 1.4.2 f5177c612fbadb8552c58693fa7249388c1c1bd3 1.4.3 8fcc1bed3e918b625d85864cc3f4623578852e7e 1.5.0 +33e5e5dff406e699893a65ecd5044d3eee35b69b 1.6.0 Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 15:43:27 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 13:43:27 -0000 Subject: [Pytest-commit] commit/tox: hpk42: fix link in readme Message-ID: <20130815134327.15564.19668@app13.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/78ace40b78b5/ Changeset: 78ace40b78b5 User: hpk42 Date: 2013-08-15 15:43:20 Summary: fix link in readme Affected #: 1 file diff -r a7ef669e28c1f367517a65f005509a238b0c1bee -r 78ace40b78b55eb729dd95cc7028347b73689739 README.rst --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ What is Tox? -------------------- -Tox as is a generic virtualenv_ management and test command line tool you can use for: +Tox as is a generic virtualenv management and test command line tool you can use for: * checking your package installs correctly with different Python versions and interpreters Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Aug 15 14:10:41 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Thu, 15 Aug 2013 12:10:41 -0000 Subject: [Pytest-commit] commit/tox: 4 new changesets Message-ID: <20130815121041.27289.70454@app12.ash-private.bitbucket.org> 4 new commits in tox: https://bitbucket.org/hpk42/tox/commits/4949def7e678/ Changeset: 4949def7e678 User: hpk42 Date: 2013-08-15 13:00:26 Summary: extend pseudo-homedir with .pip/pip.conf so that any "pip" command triggered by tests (such as tox' tests itself) will pick it up. Affected #: 2 files diff -r 394c7438efdcae278cca3c0bbd6bde6f32aa4362 -r 4949def7e678884e07157f12d7c33aead42227f7 tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -632,3 +632,15 @@ assert env["HOME"] == str(tmpdir) assert not tmpdir.join(".pydistutils.cfg").check() assert "PIP_INDEX_URL" not in env + +def test_hack_home_env_passthrough(tmpdir, monkeypatch): + from tox._venv import hack_home_env + env = hack_home_env(tmpdir, "http://index") + monkeypatch.setattr(os, "environ", env) + + tmpdir = tmpdir.mkdir("tmpdir2") + env2 = hack_home_env(tmpdir) + assert env2["HOME"] == str(tmpdir) + assert env2["PIP_INDEX_URL"] == "http://index" + assert "index_url = http://index" in \ + tmpdir.join(".pydistutils.cfg").read() diff -r 394c7438efdcae278cca3c0bbd6bde6f32aa4362 -r 4949def7e678884e07157f12d7c33aead42227f7 tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -457,7 +457,7 @@ locate_via_py(*m.groups()) -def hack_home_env(homedir, index_url): +def hack_home_env(homedir, index_url=None): # XXX HACK (this could also live with tox itself, consider) # if tox uses pip on a package that requires setup_requires # the index url set with pip is usually not recognized @@ -468,9 +468,12 @@ if not homedir.check(): homedir.ensure(dir=1) d = dict(HOME=str(homedir)) + if not index_url: + index_url = os.environ.get("TOX_INDEX_URL") if index_url: homedir.join(".pydistutils.cfg").write( "[easy_install]\n" "index_url = %s\n" % index_url) d["PIP_INDEX_URL"] = index_url + d["TOX_INDEX_URL"] = index_url return d https://bitbucket.org/hpk42/tox/commits/50bd50082b7c/ Changeset: 50bd50082b7c User: hpk42 Date: 2013-08-15 13:00:38 Summary: refine python2.5 and install_command behaviour and documentation. also show i in "--showconfig" and rename internally from "install_command_argv" to install_command for consistency. also deprecate downloadcache, distribute settings. Affected #: 8 files diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,17 @@ 1.6.0.dev ----------------- +- fix issue35: add new EXPERIMENTAL "install_command" testenv-option to configure the + installation command with options for dep/pkg install. Thanks Carl Meyer + for the PR and docs. + + +- address issueintroduce python2.5 support by vendoring the virtualenv-1.9.1 script + and forcing pip<1.4. Also the default [py25] environment modifies the + default installer_command (new config option) to use pip without the "--pre" + which was introduced with pip-1.4 and is required if you want to install non-stable releases. + (tox defaults to install with "--pre" otherwise). + - fix issue1: empty setup files are properly detected, thanks Anthon van der Neuth @@ -11,10 +22,6 @@ - remove toxbootstrap.py for now because it is broken. -- fix issue35: add new "install_command" testenv-option to configure the - installation command with options for dep/pkg install. Thanks Carl Meyer - for the PR and docs. - - fix issue109 and fix issue111: multiple "-e" options are now combined (previously the last one would win). Thanks Anthon van der Neut. diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -80,9 +80,12 @@ .. versionadded:: 1.6 - the command to be used for installing packages into the virtual - environment; both the sdist for the package under test and any - defined dependencies. Must contain the substitution key + **WARNING**: This setting is **EXPERIMENTAL** so use with care + and be ready to adapt your tox.ini's with post-1.6 tox releases. + + the ``install_command`` setting is used for installing packages into + the virtual environment; both the package under test + and any defined dependencies. Must contain the substitution key ``{packages}`` which will be replaced by the packages to install. May also contain the substitution key ``{opts}``, which will be replaced by the ``-i`` option to specify index server @@ -94,7 +97,16 @@ :confval:`downloadcache`, and/or your :confval:`install_command` should not include the ``{opts}`` substitution key (in which case those options will have no effect). - **default**: ``pip install {opts} {packages}`` + **default**:: + + pip install --pre {opts} {packages} + + **default on environment names containing 'py25'**:: + + pip install --insecure {opts} {packages}`` + + (this will use pip<1.4 (so no "--pre" option) and + python2.5 typically has no SSL support). .. confval:: whitelist_externals=MULTI-LINE-LIST @@ -137,37 +149,41 @@ .. confval:: downloadcache=path + **DEPRECATED** -- as of August 2013 this option is not very + useful because of pypi's CDN and because of caching pypi + server solutions like `devpi `_. + use this directory for caching downloads. This value is overriden by the environment variable ``PIP_DOWNLOAD_CACHE`` if it exists. If you specify a custom :confval:`install_command` that uses an installer other than pip, your installer must support the `--download-cache` command-line option. **default**: no download cache will be used. - **note**: if creating multiple environments use of a download cache greatly - speeds up the testing process. .. confval:: distribute=True|False - Set to ``True`` if you want to use distribute_ instead of the default - setuptools_ in the virtual environment. Prior to tox-1.5 the - default was True and now is False, meaning ``setuptools`` is used - (note that setuptools-0.7 merged with distribute). In future versions - of tox this option might be ignored and setuptools always chosen. + **DEPRECATED** -- as of August 2013 you should use setuptools + which has merged most of distribute_ 's changes. Just use + the default, Luke! In future versions of tox this option might + be ignored and setuptools always chosen. + **default:** False. .. confval:: sitepackages=True|False Set to ``True`` if you want to create virtual environments that also - have access to globally installed packages. **default:** False, meaning - that virtualenvs will be created with ``--no-site-packages`` by default. + have access to globally installed packages. + + **default:** False, meaning that virtualenvs will be + created without inheriting the global site packages. .. confval:: args_are_paths=BOOL treat positional arguments passed to ``tox`` as file system paths and - if they exist on the filesystem - rewrite them according to the ``changedir``. - **default**: True (due to the exists-on-filesystem check it's usually - safe to try rewriting). + **default**: True (due to the exists-on-filesystem check it's + usually safe to try rewriting). .. confval:: envtmpdir=path diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -473,14 +473,28 @@ assert envconfig.changedir.basename == "abc" assert envconfig.changedir == config.setupdir.join("abc") - def test_install_command(self, newconfig): + def test_install_command_defaults_py25(self, newconfig): + config = newconfig(""" + [testenv:py25] + [testenv:py25-x] + [testenv:py26] + """) + for name in ("py25", "py25-x"): + env = config.envconfigs[name] + assert env.install_command == \ + "pip install --insecure {opts} {packages}".split() + env = config.envconfigs["py26"] + assert env.install_command == \ + "pip install --pre {opts} {packages}".split() + + def test_install_command_setting(self, newconfig): config = newconfig(""" [testenv] - install_command=pip install --pre {packages} + install_command=some_install {packages} """) envconfig = config.envconfigs['python'] - assert envconfig.install_command_argv == [ - 'pip', 'install', '--pre', '{packages}'] + assert envconfig.install_command == [ + 'some_install', '{packages}'] def test_install_command_must_contain_packages(self, newconfig): py.test.raises(tox.exception.ConfigError, newconfig, """ @@ -506,7 +520,8 @@ envconfig = config.envconfigs['python'] assert envconfig.downloadcache == '/from/env' - def test_downloadcache_only_if_in_config(self, newconfig, tmpdir, monkeypatch): + def test_downloadcache_only_if_in_config(self, newconfig, tmpdir, + monkeypatch): monkeypatch.setenv("PIP_DOWNLOAD_CACHE", tmpdir) config = newconfig('') envconfig = config.envconfigs['python'] @@ -744,7 +759,8 @@ config = newconfig(["-vv"], "") assert config.option.verbosity == 2 - def test_substitution_jenkins_default(self, tmpdir, monkeypatch, newconfig): + def test_substitution_jenkins_default(self, tmpdir, + monkeypatch, newconfig): monkeypatch.setenv("HUDSON_URL", "xyz") config = newconfig(""" [testenv:py24] diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -10,11 +10,6 @@ pytest_plugins = "pytester" -if sys.version_info < (2,6): - PIP_INSECURE = "setenv = PIP_INSECURE=1" -else: - PIP_INSECURE = "" - from tox._cmdline import Session from tox._config import parseconfig @@ -379,10 +374,10 @@ 'tox.ini': ''' [testenv] changedir=tests - %s - commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml + commands= py.test --basetemp={envtmpdir} \ + --junitxml=junit-{envname}.xml deps=pytest - ''' % PIP_INSECURE + ''' }) def test_toxuone_env(self, cmd, example123): @@ -473,11 +468,10 @@ [testenv] usedevelop=True changedir=tests - %s commands= py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml [] deps=pytest - ''' % PIP_INSECURE + ''' }) result = cmd.run("tox", "-v") assert not result.ret @@ -521,9 +515,9 @@ # content of: tox.ini [testenv] commands=pip -h - [testenv:py25] + [testenv:py26] basepython=python - [testenv:py26] + [testenv:py27] basepython=python """}) result = cmd.run("tox") @@ -532,19 +526,19 @@ def test_notest(initproj, cmd): initproj("example123", filedefs={'tox.ini': """ # content of: tox.ini - [testenv:py25] + [testenv:py26] basepython=python """}) result = cmd.run("tox", "-v", "--notest") assert not result.ret result.stdout.fnmatch_lines([ "*summary*", - "*py25*skipped tests*", + "*py26*skipped tests*", ]) - result = cmd.run("tox", "-v", "--notest", "-epy25") + result = cmd.run("tox", "-v", "--notest", "-epy26") assert not result.ret result.stdout.fnmatch_lines([ - "*py25*reusing*", + "*py26*reusing*", ]) def test_PYC(initproj, cmd, monkeypatch): diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tox.ini --- a/tox.ini +++ b/tox.ini @@ -8,10 +8,6 @@ commands=py.test --junitxml={envlogdir}/junit-{envname}.xml {posargs} deps=pytest>=2.3.5 -[testenv:py25] # requires virtualenv-1.9.1 -setenvs = - PIP_INSECURE=True - [testenv:docs] basepython=python changedir=doc diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -492,6 +492,8 @@ self.report.line(" envlogdir=%s" % envconfig.envlogdir) self.report.line(" changedir=%s" % envconfig.changedir) self.report.line(" args_are_path=%s" % envconfig.args_are_paths) + self.report.line(" install_command=%s" % + envconfig.install_command) self.report.line(" commands=") for command in envconfig.commands: self.report.line(" %s" % command) diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -76,8 +76,8 @@ parser.add_argument("-v", nargs=0, action=CountAction, default=0, dest="verbosity", help="increase verbosity of reporting output.") - parser.add_argument("--showconfig", action="store_true", dest="showconfig", - help="show configuration information. ") + parser.add_argument("--showconfig", action="store_true", + help="show configuration information for all environments. ") parser.add_argument("-l", "--listenvs", action="store_true", dest="listenvs", help="show list of test environments") parser.add_argument("-c", action="store", default="tox.ini", @@ -331,15 +331,24 @@ # env var, if present, takes precedence downloadcache = os.environ.get("PIP_DOWNLOAD_CACHE", downloadcache) vc.downloadcache = py.path.local(downloadcache) - vc.install_command_argv = reader.getargv( + + # on python 2.5 we can't use "--pre" and we typically + # need to use --insecure for pip commands because python2.5 + # doesn't support SSL + pip_default_opts = ["{opts}", "{packages}"] + if "py25" in vc.envname: # XXX too rough check for "python2.5" + pip_default_opts.insert(0, "--insecure") + else: + pip_default_opts.insert(0, "--pre") + vc.install_command = reader.getargv( section, "install_command", - "pip install {opts} {packages}", + "pip install " + " ".join(pip_default_opts), replace=False, ) - if '{packages}' not in vc.install_command_argv: + if '{packages}' not in vc.install_command: raise tox.exception.ConfigError( - "'install_command' must contain '{packages}' substitution") + "'install_command' must contain '{packages}' substitution") return vc def _getenvlist(self, reader, toxsection): diff -r 4949def7e678884e07157f12d7c33aead42227f7 -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -285,7 +285,7 @@ def run_install_command(self, args, indexserver=None, action=None, extraenv=None): - argv = self.envconfig.install_command_argv[:] + argv = self.envconfig.install_command[:] # use pip-script on win32 to avoid the executable locking if argv[0] == "pip" and sys.platform == "win32": argv[0] = "pip-script.py" https://bitbucket.org/hpk42/tox/commits/efe7d94c863a/ Changeset: efe7d94c863a User: hpk42 Date: 2013-08-15 13:00:39 Summary: move all interpreter information detection to tox/interpreters.py Affected #: 9 files diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,6 @@ installation command with options for dep/pkg install. Thanks Carl Meyer for the PR and docs. - - address issueintroduce python2.5 support by vendoring the virtualenv-1.9.1 script and forcing pip<1.4. Also the default [py25] environment modifies the default installer_command (new config option) to use pip without the "--pre" @@ -36,6 +35,9 @@ - if a HOMEDIR cannot be determined, use the toxinidir. +- refactor interpreter information detection to live in new + tox/interpreters.py file, tests in tests/test_interpreters.py. + 1.5.0 ----------------- diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -88,8 +88,8 @@ and any defined dependencies. Must contain the substitution key ``{packages}`` which will be replaced by the packages to install. May also contain the substitution key ``{opts}``, which - will be replaced by the ``-i`` option to specify index server - (according to :confval:`indexserver` and the ``:indexserver:dep`` + will be replaced by the ``-i INDEXURL`` option if an index server + is active (see :confval:`indexserver` and the ``:indexserver:dep`` syntax of :confval:`deps`) and the ``--download-cache`` option (if you've specified :confval:`downloadcache`). If your installer does not support ``-i`` and ``--download-cache`` command-line options, diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -5,9 +5,9 @@ from textwrap import dedent import py -from tox._config import IniReader, CommandParser -from tox._config import parseconfig -from tox._config import prepare_parse, _split_env +from tox._config import * +from tox._config import _split_env + class TestVenvConfig: def test_config_parsing_minimal(self, tmpdir, newconfig): @@ -473,13 +473,29 @@ assert envconfig.changedir.basename == "abc" assert envconfig.changedir == config.setupdir.join("abc") - def test_install_command_defaults_py25(self, newconfig): + def test_install_command_defaults_py25(self, newconfig, monkeypatch): + from tox.interpreters import Interpreters + def get_info(self, name): + if "x25" in name: + class I: + runnable = True + executable = "python2.5" + version_info = (2,5) + else: + class I: + runnable = False + executable = "python" + return I + monkeypatch.setattr(Interpreters, "get_info", get_info) config = newconfig(""" - [testenv:py25] + [testenv:x25] + basepython = x25 [testenv:py25-x] + basepython = x25 [testenv:py26] + basepython = "python" """) - for name in ("py25", "py25-x"): + for name in ("x25", "py25-x"): env = config.envconfigs[name] assert env.install_command == \ "pip install --insecure {opts} {packages}".split() @@ -714,36 +730,6 @@ assert conf.changedir.basename == 'testing' assert conf.changedir.dirpath().realpath() == tmpdir.realpath() - @pytest.mark.xfailif("sys.platform == 'win32'") - def test_substitution_envsitepackagesdir(self, tmpdir, monkeypatch, - newconfig): - """ - The envsitepackagesdir property is mostly doing system work, - so this test doesn't excercise it very well. - - Usage of envsitepackagesdir on win32/jython will explicitly - throw an exception, - """ - class MockPopen(object): - returncode = 0 - - def __init__(self, *args, **kwargs): - pass - - def communicate(self, *args, **kwargs): - return 'onevalue', 'othervalue' - - monkeypatch.setattr(subprocess, 'Popen', MockPopen) - env = 'py%s' % (''.join(sys.version.split('.')[0:2])) - config = newconfig(""" - [testenv:%s] - commands = {envsitepackagesdir} - """ % (env)) - conf = config.envconfigs[env] - argv = conf.commands - assert argv[0][0] == 'onevalue' - - class TestGlobalOptions: def test_notest(self, newconfig): config = newconfig([], "") diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tests/test_interpreters.py --- /dev/null +++ b/tests/test_interpreters.py @@ -0,0 +1,95 @@ +import sys +import os + +import pytest +from tox.interpreters import * + + at pytest.fixture +def interpreters(): + return Interpreters() + + at pytest.mark.skipif("sys.platform != 'win32'") +def test_locate_via_py(monkeypatch): + from tox._venv import locate_via_py + class PseudoPy: + def sysexec(self, *args): + assert args[0] == '-3.2' + assert args[1] == '-c' + # Return value needs to actually exist! + return sys.executable + @staticmethod + def ret_pseudopy(name): + assert name == 'py' + return PseudoPy() + # Monkeypatch py.path.local.sysfind to return PseudoPy + monkeypatch.setattr(py.path.local, 'sysfind', ret_pseudopy) + assert locate_via_py('3', '2') == sys.executable + +def test_find_executable(): + p = find_executable(sys.executable) + assert p == py.path.local(sys.executable) + for ver in [""] + "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split(): + name = "python%s" % ver + if sys.platform == "win32": + pydir = "python%s" % ver.replace(".", "") + x = py.path.local("c:\%s" % pydir) + print (x) + if not x.check(): + continue + else: + if not py.path.local.sysfind(name): + continue + p = find_executable(name) + assert p + popen = py.std.subprocess.Popen([str(p), '-V'], + stderr=py.std.subprocess.PIPE) + stdout, stderr = popen.communicate() + assert ver in py.builtin._totext(stderr, "ascii") + +def test_find_executable_extra(monkeypatch): + @staticmethod + def sysfind(x): + return "hello" + monkeypatch.setattr(py.path.local, "sysfind", sysfind) + t = find_executable("qweqwe") + assert t == "hello" + +def test_run_and_get_interpreter_info(): + name = os.path.basename(sys.executable) + info = run_and_get_interpreter_info(name, sys.executable) + assert info.version_info == tuple(sys.version_info) + assert info.name == name + assert info.executable == sys.executable + +class TestInterpreters: + + def test_get_info_self_exceptions(self, interpreters): + pytest.raises(ValueError, lambda: + interpreters.get_info()) + pytest.raises(ValueError, lambda: + interpreters.get_info(name="12", executable="123")) + + def test_get_executable(self, interpreters): + x = interpreters.get_executable(sys.executable) + assert x == sys.executable + assert not interpreters.get_executable("12l3k1j23") + + def test_get_info__name(self, interpreters): + basename = os.path.basename(sys.executable) + info = interpreters.get_info(basename) + assert info.version_info == tuple(sys.version_info) + assert info.name == basename + assert info.executable == sys.executable + assert info.runnable + + def test_get_info__name_not_exists(self, interpreters): + info = interpreters.get_info("qlwkejqwe") + assert not info.version_info + assert info.name == "qlwkejqwe" + assert not info.executable + assert not info.runnable + + def test_get_sitepackagesdir_error(self, interpreters): + info = interpreters.get_info(sys.executable) + s = interpreters.get_sitepackagesdir(info, "") + assert s diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -2,9 +2,7 @@ import tox import pytest import os, sys -from tox._venv import VirtualEnv, CreationConfig, getdigest -from tox._venv import find_executable -from tox._venv import _getinterpreterversion +from tox._venv import * py25calls = int(sys.version_info[:2] == (2,5)) @@ -19,52 +17,6 @@ def test_getdigest(tmpdir): assert getdigest(tmpdir) == "0"*32 - at pytest.mark.skipif("sys.platform != 'win32'") -def test_locate_via_py(monkeypatch): - from tox._venv import locate_via_py - class PseudoPy: - def sysexec(self, *args): - assert args[0] == '-3.2' - assert args[1] == '-c' - # Return value needs to actually exist! - return sys.executable - @staticmethod - def ret_pseudopy(name): - assert name == 'py' - return PseudoPy() - # Monkeypatch py.path.local.sysfind to return PseudoPy - monkeypatch.setattr(py.path.local, 'sysfind', ret_pseudopy) - assert locate_via_py('3', '2') == sys.executable - -def test_find_executable(): - p = find_executable(sys.executable) - assert p == py.path.local(sys.executable) - for ver in [""] + "2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3".split(): - name = "python%s" % ver - if sys.platform == "win32": - pydir = "python%s" % ver.replace(".", "") - x = py.path.local("c:\%s" % pydir) - print (x) - if not x.check(): - continue - else: - if not py.path.local.sysfind(name): - continue - p = find_executable(name) - assert p - popen = py.std.subprocess.Popen([str(p), '-V'], - stderr=py.std.subprocess.PIPE) - stdout, stderr = popen.communicate() - assert ver in py.builtin._totext(stderr, "ascii") - -def test_find_executable_extra(monkeypatch): - @staticmethod - def sysfind(x): - return "hello" - monkeypatch.setattr(py.path.local, "sysfind", sysfind) - t = find_executable("qweqwe") - assert t == "hello" - def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession): config = newconfig([], """ [testenv:python] @@ -83,10 +35,6 @@ py.test.raises(tox.exception.InterpreterNotFound, venv.getsupportedinterpreter) -def test_getinterpreterversion(): - from distutils.sysconfig import get_python_version - version = _getinterpreterversion(sys.executable) - assert version == get_python_version() def test_create(monkeypatch, mocksession, newconfig): config = newconfig([], """ @@ -107,7 +55,7 @@ #assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python - assert interp == venv.getconfigexecutable() + assert interp == venv.envconfig._basepython_info.executable assert venv.path_config.check(exists=False) @pytest.mark.skipif("sys.platform == 'win32'") @@ -243,7 +191,7 @@ # two different index servers, two calls assert len(l) == 3 args = " ".join(l[0].args) - assert "-i" not in args + assert "-i " not in args assert "dep1" in args args = " ".join(l[1].args) diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tox/_cmdline.py --- a/tox/_cmdline.py +++ b/tox/_cmdline.py @@ -486,6 +486,8 @@ for envconfig in self.config.envconfigs.values(): self.report.line("[testenv:%s]" % envconfig.envname, bold=True) self.report.line(" basepython=%s" % envconfig.basepython) + self.report.line(" _basepython_info=%s" % + envconfig._basepython_info) self.report.line(" envpython=%s" % envconfig.envpython) self.report.line(" envtmpdir=%s" % envconfig.envtmpdir) self.report.line(" envbindir=%s" % envconfig.envbindir) diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -8,6 +8,8 @@ import subprocess import textwrap +from tox.interpreters import Interpreters + import py import tox @@ -118,6 +120,7 @@ def __init__(self): self.envconfigs = {} self.invocationcwd = py.path.local() + self.interpreters = Interpreters() class VenvConfig: def __init__(self, **kw): @@ -141,32 +144,10 @@ # no @property to avoid early calling (see callable(subst[key]) checks) def envsitepackagesdir(self): - print_envsitepackagesdir = textwrap.dedent(""" - import sys - from distutils.sysconfig import get_python_lib - sys.stdout.write(get_python_lib(prefix=sys.argv[1])) - """) - - exe = self.getsupportedinterpreter() - # can't use check_output until py27 - proc = subprocess.Popen( - [str(exe), '-c', print_envsitepackagesdir, str(self.envdir)], - stdout=subprocess.PIPE) - odata, edata = proc.communicate() - if proc.returncode: - raise tox.exception.UnsupportedInterpreter( - "Error getting site-packages from %s" % self.basepython) - return odata - - def getconfigexecutable(self): - from tox._venv import find_executable - - python = self.basepython - if not python: - python = sys.executable - x = find_executable(str(python)) - if x: - x = x.realpath() + self.getsupportedinterpreter() # for throwing exceptions + x = self.config.interpreters.get_sitepackagesdir( + info=self._basepython_info, + envdir=self.envdir) return x def getsupportedinterpreter(self): @@ -174,10 +155,11 @@ "jython" in self.basepython: raise tox.exception.UnsupportedInterpreter( "Jython/Windows does not support installing scripts") - config_executable = self.getconfigexecutable() - if not config_executable: + info = self.config.interpreters.get_info(self.basepython) + if not info.executable: raise tox.exception.InterpreterNotFound(self.basepython) - return config_executable + return info.executable + testenvprefix = "testenv:" class parseini: @@ -285,6 +267,7 @@ else: bp = sys.executable vc.basepython = reader.getdefault(section, "basepython", bp) + vc._basepython_info = config.interpreters.get_info(vc.basepython) reader.addsubstitions(envdir=vc.envdir, envname=vc.envname, envbindir=vc.envbindir, envpython=vc.envpython, envsitepackagesdir=vc.envsitepackagesdir) @@ -336,7 +319,8 @@ # need to use --insecure for pip commands because python2.5 # doesn't support SSL pip_default_opts = ["{opts}", "{packages}"] - if "py25" in vc.envname: # XXX too rough check for "python2.5" + info = vc._basepython_info + if info.runnable and info.version_info < (2,6): pip_default_opts.insert(0, "--insecure") else: pip_default_opts.insert(0, "--pre") diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -145,7 +145,7 @@ return "could not install deps %s" %(self.envconfig.deps,) def _getliveconfig(self): - python = self.getconfigexecutable() + python = self.envconfig._basepython_info.executable md5 = getdigest(python) version = tox.__version__ distribute = self.envconfig.distribute @@ -169,9 +169,6 @@ l.append(dep) return l - def getconfigexecutable(self): - return self.envconfig.getconfigexecutable() - def getsupportedinterpreter(self): return self.envconfig.getsupportedinterpreter() @@ -180,11 +177,11 @@ # return if action is None: action = self.session.newaction(self, "create") + + interpreters = self.envconfig.config.interpreters config_interpreter = self.getsupportedinterpreter() - config_interpreter_version = _getinterpreterversion( - config_interpreter) - use_venv191 = config_interpreter_version < '2.6' - use_pip13 = config_interpreter_version < '2.6' + info = interpreters.get_info(executable=config_interpreter) + use_venv191 = use_pip13 = info.version_info < (2,6) if not use_venv191: f, path, _ = py.std.imp.find_module("virtualenv") f.close() @@ -389,21 +386,6 @@ self.session.report.verbosity2("setting PATH=%s" % os.environ["PATH"]) return oldPATH -def _getinterpreterversion(executable): - print_python_version = ( - 'from distutils.sysconfig import get_python_version\n' - 'print(get_python_version())\n') - proc = subprocess.Popen([str(executable), '-c', print_python_version], - stdout=subprocess.PIPE) - odata, edata = proc.communicate() - if proc.returncode: - raise tox.exception.UnsupportedInterpreter( - "Error getting python version from %s" % executable) - if sys.version_info[0] == 3: - string = str - else: - string = lambda x, encoding: str(x) - return string(odata, 'ascii').strip() def getdigest(path): path = py.path.local(path) @@ -411,51 +393,6 @@ return "0" * 32 return path.computehash() -if sys.platform != "win32": - def find_executable(name): - return py.path.local.sysfind(name) - -else: - # Exceptions to the usual windows mapping - win32map = { - 'python': sys.executable, - 'jython': "c:\jython2.5.1\jython.bat", - } - def locate_via_py(v_maj, v_min): - ver = "-%s.%s" % (v_maj, v_min) - script = "import sys; print(sys.executable)" - py_exe = py.path.local.sysfind('py') - if py_exe: - try: - exe = py_exe.sysexec(ver, '-c', script).strip() - except py.process.cmdexec.Error: - exe = None - if exe: - exe = py.path.local(exe) - if exe.check(): - return exe - - def find_executable(name): - p = py.path.local.sysfind(name) - if p: - return p - actual = None - # Is this a standard PythonX.Y name? - m = re.match(r"python(\d)\.(\d)", name) - if m: - # The standard names are in predictable places. - actual = r"c:\python%s%s\python.exe" % m.groups() - if not actual: - actual = win32map.get(name, None) - if actual: - actual = py.path.local(actual) - if actual.check(): - return actual - # The standard executables can be found as a last resort via the - # Python launcher py.exe - if m: - locate_via_py(*m.groups()) - def hack_home_env(homedir, index_url=None): # XXX HACK (this could also live with tox itself, consider) diff -r 50bd50082b7cacf9a11ed5605d0af3383db23e8b -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c tox/interpreters.py --- /dev/null +++ b/tox/interpreters.py @@ -0,0 +1,170 @@ +import sys +import os +import py +import subprocess +import inspect + +class Interpreters: + def __init__(self): + self.name2executable = {} + self.executable2info = {} + + def get_executable(self, name): + """ return path object to the executable for the given + name (e.g. python2.5, python2.7, python etc.) + if name is already an existing path, return name. + If an interpreter cannot be found, return None. + """ + try: + return self.name2executable[name] + except KeyError: + self.name2executable[name] = e = find_executable(name) + return e + + def get_info(self, name=None, executable=None): + if name is None and executable is None: + raise ValueError("need to specify name or executable") + if name: + if executable is not None: + raise ValueError("cannot specify both name, executable") + executable = self.get_executable(name) + if not executable: + return NoInterpreterInfo(name=name) + try: + return self.executable2info[executable] + except KeyError: + info = run_and_get_interpreter_info(name, executable) + self.executable2info[executable] = info + return info + + def get_sitepackagesdir(self, info, envdir): + if not info.executable: + return "" + envdir = str(envdir) + try: + res = exec_on_interpreter(info.executable, + [inspect.getsource(sitepackagesdir), + "print (sitepackagesdir(%r))" % envdir]) + except ExecFailed: + val = sys.exc_info()[1] + print ("execution failed: %s -- %s" %(val.out, val.err)) + return "" + else: + return res["dir"] + +def run_and_get_interpreter_info(name, executable): + assert executable + try: + result = exec_on_interpreter(executable, + [inspect.getsource(pyinfo), "print (pyinfo())"]) + except ExecFailed: + val = sys.exc_info()[1] + return NoInterpreterInfo(name, **val.__dict__) + else: + return InterpreterInfo(name, executable, **result) + +def exec_on_interpreter(executable, source): + if isinstance(source, list): + source = "\n".join(source) + from subprocess import Popen, PIPE + args = [str(executable)] + popen = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + popen.stdin.write(source.encode("utf8")) + out, err = popen.communicate() + if popen.returncode: + raise ExecFailed(executable, source, out, err) + try: + result = eval(out) + except Exception: + raise ExecFailed(executable, source, out, + "could not decode %r" % out) + return result + +class ExecFailed(Exception): + def __init__(self, executable, source, out, err): + self.executable = executable + self.source = source + self.out = out + self.err = err + +class InterpreterInfo: + runnable = True + + def __init__(self, name, executable, version_info): + assert name and executable and version_info + self.name = name + self.executable = executable + self.version_info = version_info + + def __str__(self): + return "" % ( + self.executable, self.version_info) + +class NoInterpreterInfo: + runnable = False + def __init__(self, name, executable=None, + out=None, err="not found"): + self.name = name + self.executable = executable + self.version_info = None + self.out = out + self.err = err + + def __str__(self): + if self.executable: + return "" + else: + return "" % self.name + +if sys.platform != "win32": + def find_executable(name): + return py.path.local.sysfind(name) + +else: + # Exceptions to the usual windows mapping + win32map = { + 'python': sys.executable, + 'jython': "c:\jython2.5.1\jython.bat", + } + def locate_via_py(v_maj, v_min): + ver = "-%s.%s" % (v_maj, v_min) + script = "import sys; print(sys.executable)" + py_exe = py.path.local.sysfind('py') + if py_exe: + try: + exe = py_exe.sysexec(ver, '-c', script).strip() + except py.process.cmdexec.Error: + exe = None + if exe: + exe = py.path.local(exe) + if exe.check(): + return exe + + def find_executable(name): + p = py.path.local.sysfind(name) + if p: + return p + actual = None + # Is this a standard PythonX.Y name? + m = re.match(r"python(\d)\.(\d)", name) + if m: + # The standard names are in predictable places. + actual = r"c:\python%s%s\python.exe" % m.groups() + if not actual: + actual = win32map.get(name, None) + if actual: + actual = py.path.local(actual) + if actual.check(): + return actual + # The standard executables can be found as a last resort via the + # Python launcher py.exe + if m: + locate_via_py(*m.groups()) + +def pyinfo(): + import sys + return dict(version_info=tuple(sys.version_info)) + +def sitepackagesdir(envdir): + from distutils.sysconfig import get_python_lib + return dict(dir=get_python_lib(envdir)) https://bitbucket.org/hpk42/tox/commits/33e5e5dff406/ Changeset: 33e5e5dff406 User: hpk42 Date: 2013-08-15 14:10:14 Summary: refactor docs and changelog Affected #: 11 files diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,24 +1,26 @@ -1.6.0.dev +1.6.0 ----------------- -- fix issue35: add new EXPERIMENTAL "install_command" testenv-option to configure the - installation command with options for dep/pkg install. Thanks Carl Meyer - for the PR and docs. +- fix issue35: add new EXPERIMENTAL "install_command" testenv-option to + configure the installation command with options for dep/pkg install. + Thanks Carl Meyer for the PR and docs. -- address issueintroduce python2.5 support by vendoring the virtualenv-1.9.1 script - and forcing pip<1.4. Also the default [py25] environment modifies the - default installer_command (new config option) to use pip without the "--pre" - which was introduced with pip-1.4 and is required if you want to install non-stable releases. - (tox defaults to install with "--pre" otherwise). +- fix issue91: python2.5 support by vendoring the virtualenv-1.9.1 + script and forcing pip<1.4. Also the default [py25] environment + modifies the default installer_command (new config option) + to use pip without the "--pre" option which was introduced + with pip-1.4 and is now required if you want to install non-stable + releases. (tox defaults to install with "--pre" everywhere). + +- during installation of dependencies HOME is now set to a pseudo + location ({envtmpdir}/pseudo-home). If an index url was specified + a .pydistutils.cfg file will be written with an index_url setting + so that packages defining ``setup_requires`` dependencies will not + silently use your HOME-directory settings or https://pypi.python.org. - fix issue1: empty setup files are properly detected, thanks Anthon van der Neuth -- during installation of dependencies HOME is set to a pseudo - location (envtmpdir/pseudo-home). If an index url was specified - a .pydistutils.cfg file will be written so that index_url - is set if a package contains a ``setup_requires``. - - remove toxbootstrap.py for now because it is broken. - fix issue109 and fix issue111: multiple "-e" options are now combined diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b doc/conf.py --- a/doc/conf.py +++ b/doc/conf.py @@ -48,7 +48,7 @@ # built documents. # # The short X.Y version. -release = version = "1.5.0" +release = version = "1.6.0" # The full version, including alpha/beta/rc tags. # The language for content autogenerated by Sphinx. Refer to documentation diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -87,26 +87,22 @@ the virtual environment; both the package under test and any defined dependencies. Must contain the substitution key ``{packages}`` which will be replaced by the packages to - install. May also contain the substitution key ``{opts}``, which - will be replaced by the ``-i INDEXURL`` option if an index server - is active (see :confval:`indexserver` and the ``:indexserver:dep`` - syntax of :confval:`deps`) and the ``--download-cache`` option (if - you've specified :confval:`downloadcache`). If your installer does - not support ``-i`` and ``--download-cache`` command-line options, - you should not use :confval:`indexserver` or - :confval:`downloadcache`, and/or your :confval:`install_command` - should not include the ``{opts}`` substitution key (in which case - those options will have no effect). + install. You should also accept "{opts}" if you are using + pip or easy_install -- it will contain index server options + if you have configured them via :confval:`indexserver` + and the deprecated :confval:`downloadcache` option + if you have configured it. + **default**:: pip install --pre {opts} {packages} - - **default on environment names containing 'py25'**:: + + **default on environments using python2.5**:: pip install --insecure {opts} {packages}`` - (this will use pip<1.4 (so no "--pre" option) and - python2.5 typically has no SSL support). + (this will use pip<1.4 (so no ``--pre`` option) and python2.5 + typically has no SSL support, therefore ``--insecure``). .. confval:: whitelist_externals=MULTI-LINE-LIST diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b doc/example/basic.txt --- a/doc/example/basic.txt +++ b/doc/example/basic.txt @@ -114,28 +114,21 @@ .. versionadded:: 1.6 -By default tox uses `pip`_ to install packages (both the sdist of your -package-under-test and any dependencies you specify in ``tox.ini``) into each -test virtualenv, with a command-line like ``pip install --pre -SomePackage==1.0``. - -You can fully customize tox's install-command in your ``tox.ini`` with the -``install_command`` option. For instance, to use ``easy_install`` instead of -`pip`_:: +By default tox uses `pip`_ to install packages, both the +package-under-test and any dependencies you specify in ``tox.ini``. +You can fully customize tox's install-command through the +testenv-specific :confval:`install_command=ARGV` setting. +For instance, to use ``easy_install`` instead of `pip`_:: [testenv] - install_command = easy_install {packages} + install_command = easy_install {opts} {packages} -Or to use pip's ``--find-links`` and ``--no-index`` options to specify an -alternative source for your dependencies:: +Or to use pip's ``--find-links`` and ``--no-index`` options to specify +an alternative source for your dependencies:: [testenv] install_command = pip install --pre --find-links http://packages.example.com --no-index {opts} {packages} -(Including ``{opts}`` is only necessary if you want your install command to -also respect tox's options for setting the download cache and package index -server). - .. _pip: http://pip-installer.org forcing re-creation of virtual environments diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b doc/index.txt --- a/doc/index.txt +++ b/doc/index.txt @@ -66,10 +66,13 @@ * supports :ref:`using different / multiple PyPI index servers ` -* uses pip_ and distribute_ by default. +* uses pip_ and setuptools_ by default. Experimental + support for configuring the installer command + through :confval:`install_command=ARGV`. -* **cross-Python compatible**: Python-2.5 up to Python-3.3, Jython and pypy_ - support. +* **cross-Python compatible**: Python-2.5 up to Python-3.3, + Jython and pypy_ support. Python-2.5 is supported through + a vendored ``virtualenv-1.9.1`` script. * **cross-platform**: Windows and Unix style environments @@ -77,8 +80,9 @@ (formerly known as Hudson) and helps you to avoid boilerplatish and platform-specific build-step hacks. -* **unified automatic artifact management** between ``tox`` runs both - in a local developer shell as well as in a CI/Jenkins context. +* **full interoperability with devpi**: is integrated with and + is used for testing in the devpi_ system, a versatile pypi + index server and release managing tool. * **driven by a simple ini-style config file** diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b doc/links.txt --- a/doc/links.txt +++ b/doc/links.txt @@ -1,4 +1,5 @@ +.. _devpi: http://doc.devpi.net .. _Python: http://www.python.org .. _virtualenv: https://pypi.python.org/pypi/virtualenv .. _virtualenv3: https://pypi.python.org/pypi/virtualenv3 diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b setup.py --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.6rc2', + version='1.6.0', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b tests/test_config.py --- a/tests/test_config.py +++ b/tests/test_config.py @@ -522,19 +522,19 @@ monkeypatch.delenv("PIP_DOWNLOAD_CACHE", raising=False) config = newconfig(""" [testenv] - downloadcache=/the/cache + downloadcache=thecache """) envconfig = config.envconfigs['python'] - assert envconfig.downloadcache == '/the/cache' + assert envconfig.downloadcache.basename == 'thecache' def test_downloadcache_env_override(self, newconfig, monkeypatch): - monkeypatch.setenv("PIP_DOWNLOAD_CACHE", '/from/env') + monkeypatch.setenv("PIP_DOWNLOAD_CACHE", 'fromenv') config = newconfig(""" [testenv] - downloadcache=/from/config + downloadcache=somepath """) envconfig = config.envconfigs['python'] - assert envconfig.downloadcache == '/from/env' + assert envconfig.downloadcache.basename == "fromenv" def test_downloadcache_only_if_in_config(self, newconfig, tmpdir, monkeypatch): diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b tests/test_interpreters.py --- a/tests/test_interpreters.py +++ b/tests/test_interpreters.py @@ -10,7 +10,6 @@ @pytest.mark.skipif("sys.platform != 'win32'") def test_locate_via_py(monkeypatch): - from tox._venv import locate_via_py class PseudoPy: def sysexec(self, *args): assert args[0] == '-3.2' @@ -75,10 +74,8 @@ assert not interpreters.get_executable("12l3k1j23") def test_get_info__name(self, interpreters): - basename = os.path.basename(sys.executable) - info = interpreters.get_info(basename) + info = interpreters.get_info(executable=sys.executable) assert info.version_info == tuple(sys.version_info) - assert info.name == basename assert info.executable == sys.executable assert info.runnable diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.6rc2' +__version__ = '1.6.0' class exception: class Error(Exception): diff -r efe7d94c863aabd6ea2d1513b4513ce9b0d4291c -r 33e5e5dff406e699893a65ecd5044d3eee35b69b tox/interpreters.py --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -1,6 +1,7 @@ import sys import os import py +import re import subprocess import inspect @@ -59,7 +60,8 @@ [inspect.getsource(pyinfo), "print (pyinfo())"]) except ExecFailed: val = sys.exc_info()[1] - return NoInterpreterInfo(name, **val.__dict__) + return NoInterpreterInfo(name, executable=val.executable, + out=val.out, err=val.err) else: return InterpreterInfo(name, executable, **result) @@ -74,7 +76,7 @@ if popen.returncode: raise ExecFailed(executable, source, out, err) try: - result = eval(out) + result = eval(out.strip()) except Exception: raise ExecFailed(executable, source, out, "could not decode %r" % out) @@ -91,7 +93,7 @@ runnable = True def __init__(self, name, executable, version_info): - assert name and executable and version_info + assert executable and version_info self.name = name self.executable = executable self.version_info = version_info Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Fri Aug 16 11:22:22 2013 From: issues-reply at bitbucket.org (Adam Groszer) Date: Fri, 16 Aug 2013 09:22:22 -0000 Subject: [Pytest-commit] Issue #114: win32: specify python.exe locations (hpk42/tox) Message-ID: <20130816092222.4140.43224@app12.ash-private.bitbucket.org> New issue 114: win32: specify python.exe locations https://bitbucket.org/hpk42/tox/issue/114/win32-specify-pythonexe-locations Adam Groszer: Any chance to have a place to specify pyhon.exe locations? The problem is that not everyone can/will use the r"c:\python\\d.\\d\python.exe" location. E.g. on winbot.zope.org I need 32 and 64 bit pythons beside each other. I'd vote for a global tox.ini where one could define something. From commits-noreply at bitbucket.org Fri Aug 16 11:34:08 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 16 Aug 2013 09:34:08 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130816093408.1659.68167@app06.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/8cf687dda7b0/ Changeset: 8cf687dda7b0 User: antocuni Date: 2013-03-14 16:10:33 Summary: correctly handle nose.SkipTest during collection Affected #: 4 files diff -r 1944bf94e4648184bddcb5bbbbe8c02bcecd2184 -r 8cf687dda7b0c121f14332244b44135bf0407752 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -347,6 +347,18 @@ """ Collector instances create children through collect() and thus iteratively build a tree. """ + + _skip_exceptions = None + @property + def skip_exceptions(self): + if self._skip_exceptions is None: + return (py.test.skip.Exception,) + return self._skip_exceptions + + @skip_exceptions.setter + def skip_exceptions(self, value): + self._skip_exceptions = value + class CollectError(Exception): """ an error during collection, contains a custom message. """ diff -r 1944bf94e4648184bddcb5bbbbe8c02bcecd2184 -r 8cf687dda7b0c121f14332244b44135bf0407752 _pytest/nose.py --- a/_pytest/nose.py +++ b/_pytest/nose.py @@ -38,6 +38,8 @@ # del item.parent._nosegensetup def pytest_make_collect_report(collector): + SkipTest = py.std.unittest.SkipTest + collector.skip_exceptions += (SkipTest,) if isinstance(collector, pytest.Generator): call_optional(collector.obj, 'setup') diff -r 1944bf94e4648184bddcb5bbbbe8c02bcecd2184 -r 8cf687dda7b0c121f14332244b44135bf0407752 _pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -249,7 +249,7 @@ if not call.excinfo: outcome = "passed" else: - if call.excinfo.errisinstance(py.test.skip.Exception): + if call.excinfo.errisinstance(collector.skip_exceptions): outcome = "skipped" r = collector._repr_failure_py(call.excinfo, "line").reprcrash longrepr = (str(r.path), r.lineno, r.message) diff -r 1944bf94e4648184bddcb5bbbbe8c02bcecd2184 -r 8cf687dda7b0c121f14332244b44135bf0407752 testing/test_nose.py --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -305,3 +305,12 @@ result.stdout.fnmatch_lines("*1 passed*") +def test_SkipTest_during_collection(testdir): + testdir.makepyfile(""" + import nose + raise nose.SkipTest("during collection") + def test_failing(): + assert False + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines("*1 skipped*") https://bitbucket.org/hpk42/pytest/commits/15d47614851b/ Changeset: 15d47614851b User: antocuni Date: 2013-03-14 16:53:57 Summary: (antocuni, ronny around): import directly from _pytest.runner to avoid the usage of @property Affected #: 1 file diff -r 8cf687dda7b0c121f14332244b44135bf0407752 -r 15d47614851bd72c4e7afc88f8fae5ae38d0fae9 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -10,6 +10,7 @@ from UserDict import DictMixin as MappingMixin from _pytest.mark import MarkInfo +import _pytest.runner tracebackcutdir = py.path.local(_pytest.__file__).dirpath() @@ -348,16 +349,9 @@ and thus iteratively build a tree. """ - _skip_exceptions = None - @property - def skip_exceptions(self): - if self._skip_exceptions is None: - return (py.test.skip.Exception,) - return self._skip_exceptions - - @skip_exceptions.setter - def skip_exceptions(self, value): - self._skip_exceptions = value + # the set of exceptions to interpret as "Skip the whole module" during + # collection + skip_exceptions = (_pytest.runner.Skipped,) class CollectError(Exception): """ an error during collection, contains a custom message. """ https://bitbucket.org/hpk42/pytest/commits/2393d3dcacdf/ Changeset: 2393d3dcacdf User: hpk42 Date: 2013-08-16 11:33:58 Summary: merge pull request #27: correctly handle nose.SkipTest during collection. Thanks Antonio Cuni, Ronny Pfannschmidt. I did a few tweaks to the test and the activation (depending on if unittest is imported at all). Affected #: 6 files diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ Changes between 2.3.5 and 2.4.DEV ----------------------------------- +- PR27: correctly handle nose.SkipTest during collection. Thanks + Antonio Cuni, Ronny Pfannschmidt. + - new monkeypatch.replace() to avoid imports and provide a shorter invocation for patching out classes/functions from modules: diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 _pytest/main.py --- a/_pytest/main.py +++ b/_pytest/main.py @@ -10,6 +10,7 @@ from UserDict import DictMixin as MappingMixin from _pytest.mark import MarkInfo +import _pytest.runner tracebackcutdir = py.path.local(_pytest.__file__).dirpath() @@ -368,6 +369,11 @@ """ Collector instances create children through collect() and thus iteratively build a tree. """ + + # the set of exceptions to interpret as "Skip the whole module" during + # collection + skip_exceptions = (_pytest.runner.Skipped,) + class CollectError(Exception): """ an error during collection, contains a custom message. """ diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 _pytest/nose.py --- a/_pytest/nose.py +++ b/_pytest/nose.py @@ -40,6 +40,9 @@ # del item.parent._nosegensetup def pytest_make_collect_report(collector): + if sys.modules.get("unittest"): + SkipTest = py.std.unittest.SkipTest + collector.skip_exceptions += (SkipTest,) if isinstance(collector, pytest.Generator): call_optional(collector.obj, 'setup') diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 _pytest/pytester.py --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -604,9 +604,10 @@ passed = [] skipped = [] failed = [] - for rep in self.getreports("pytest_runtest_logreport"): + for rep in self.getreports( + "pytest_collectreport pytest_runtest_logreport"): if rep.passed: - if rep.when == "call": + if getattr(rep, "when", None) == "call": passed.append(rep) elif rep.skipped: skipped.append(rep) diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 _pytest/runner.py --- a/_pytest/runner.py +++ b/_pytest/runner.py @@ -258,7 +258,7 @@ if not call.excinfo: outcome = "passed" else: - if call.excinfo.errisinstance(py.test.skip.Exception): + if call.excinfo.errisinstance(collector.skip_exceptions): outcome = "skipped" r = collector._repr_failure_py(call.excinfo, "line").reprcrash longrepr = (str(r.path), r.lineno, r.message) diff -r 6020045d40a9f50cf62019657a7b58caf6c80435 -r 2393d3dcacdf411a855acaac836bae027d72a668 testing/test_nose.py --- a/testing/test_nose.py +++ b/testing/test_nose.py @@ -327,6 +327,15 @@ """Undoes the setup.""" raise Exception("should not call teardown for skipped tests") ''') + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1, skipped=1) - result = testdir.runpytest() - result.stdout.fnmatch_lines("*1 skipped*") +def test_SkipTest_during_collection(testdir): + testdir.makepyfile(""" + import nose + raise nose.SkipTest("during collection") + def test_failing(): + assert False + """) + reprec = testdir.inline_run() + reprec.assertoutcome(skipped=1) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Aug 16 11:38:01 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 16 Aug 2013 09:38:01 -0000 Subject: [Pytest-commit] commit/pytest: 3 new changesets Message-ID: <20130816093801.10717.89967@app13.ash-private.bitbucket.org> 3 new commits in pytest: https://bitbucket.org/hpk42/pytest/commits/c88e134bf30d/ Changeset: c88e134bf30d User: markon Date: 2013-08-15 12:52:34 Summary: Fix @parametrize when using an integer and strings as parameters in a test accepting a parameter and a fixture as arguments. Affected #: 1 file diff -r ffcbf3e090c24239ab12a092c929fcecdfe49369 -r c88e134bf30d6a84d97d7d636936b2d221be4a34 testing/test_parametrize_with_fixture.py --- /dev/null +++ b/testing/test_parametrize_with_fixture.py @@ -0,0 +1,24 @@ + + +def test_parametrize(testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def myfixture(): + return 'example' + + + @pytest.mark.parametrize( + 'limit', + ( + 0, + '0', + 'foo', + ) + ) + def test_limit(limit, myfixture): + return + """) + reprec = testdir.runpytest() + assert 'KeyError' in reprec.stdout https://bitbucket.org/hpk42/pytest/commits/d968e0aa0478/ Changeset: d968e0aa0478 User: markon Date: 2013-08-16 09:55:25 Summary: test marked as Affected #: 1 file diff -r c88e134bf30d6a84d97d7d636936b2d221be4a34 -r d968e0aa0478d4df45592d8a0e2db8547399f475 testing/test_parametrize_with_fixture.py --- a/testing/test_parametrize_with_fixture.py +++ b/testing/test_parametrize_with_fixture.py @@ -1,5 +1,7 @@ +import pytest + at pytest.mark.xfail() def test_parametrize(testdir): testdir.makepyfile(""" import pytest https://bitbucket.org/hpk42/pytest/commits/78b7645e66c6/ Changeset: 78b7645e66c6 User: hpk42 Date: 2013-08-16 11:38:00 Summary: Merged in markon/pytest (pull request #66) Fix @parametrize. Affected #: 1 file diff -r 2393d3dcacdf411a855acaac836bae027d72a668 -r 78b7645e66c65118439b59d9b677e7ec71a05f8c testing/test_parametrize_with_fixture.py --- /dev/null +++ b/testing/test_parametrize_with_fixture.py @@ -0,0 +1,26 @@ +import pytest + + + at pytest.mark.xfail() +def test_parametrize(testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def myfixture(): + return 'example' + + + @pytest.mark.parametrize( + 'limit', + ( + 0, + '0', + 'foo', + ) + ) + def test_limit(limit, myfixture): + return + """) + reprec = testdir.runpytest() + assert 'KeyError' in reprec.stdout Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Aug 16 11:42:44 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Fri, 16 Aug 2013 09:42:44 -0000 Subject: [Pytest-commit] commit/pytest: hpk42: refs issue290 -- move and refactor the test the string/int-id parametrization test (Which xfails) Message-ID: <20130816094244.32409.97874@app06.ash-private.bitbucket.org> 1 new commit in pytest: https://bitbucket.org/hpk42/pytest/commits/933a880e9acc/ Changeset: 933a880e9acc User: hpk42 Date: 2013-08-16 11:41:31 Summary: refs issue290 -- move and refactor the test the string/int-id parametrization test (Which xfails) Affected #: 2 files diff -r 78b7645e66c65118439b59d9b677e7ec71a05f8c -r 933a880e9acc5352fda851e5a9a5422c7e555202 testing/python/metafunc.py --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -813,3 +813,20 @@ testdir.makepyfile(s) reprec = testdir.inline_run() reprec.assertoutcome(passed=2, skipped=2) + + + @pytest.mark.xfail(reason="issue 290") + def test_parametrize_ID_generation_string_int_works(self, testdir): + testdir.makepyfile(""" + import pytest + + @pytest.fixture + def myfixture(): + return 'example' + @pytest.mark.parametrize( + 'limit', (0, '0')) + def test_limit(limit, myfixture): + return + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=2) diff -r 78b7645e66c65118439b59d9b677e7ec71a05f8c -r 933a880e9acc5352fda851e5a9a5422c7e555202 testing/test_parametrize_with_fixture.py --- a/testing/test_parametrize_with_fixture.py +++ b/testing/test_parametrize_with_fixture.py @@ -1,26 +1,1 @@ import pytest - - - at pytest.mark.xfail() -def test_parametrize(testdir): - testdir.makepyfile(""" - import pytest - - @pytest.fixture - def myfixture(): - return 'example' - - - @pytest.mark.parametrize( - 'limit', - ( - 0, - '0', - 'foo', - ) - ) - def test_limit(limit, myfixture): - return - """) - reprec = testdir.runpytest() - assert 'KeyError' in reprec.stdout Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From notifications at travis-ci.org Fri Aug 16 11:36:31 2013 From: notifications at travis-ci.org (Travis CI) Date: Fri, 16 Aug 2013 09:36:31 +0000 Subject: [Pytest-commit] [Broken] hpk42/pytest#36 (master - 9203b85) Message-ID: <520df29ef2300_231975e14399d@dd74c443-aaa8-4da2-bbdc-3e32ea20d83f.mail> Build Update for hpk42/pytest ------------------------------------- Build: #36 Status: Broken Duration: 48 seconds Commit: 9203b85 (master) Author: holger krekel Message: merge pull request #27: correctly handle nose.SkipTest during collection. Thanks Antonio Cuni, Ronny Pfannschmidt. I did a few tweaks to the test and the activation (depending on if unittest is imported at all). View the changeset: https://github.com/hpk42/pytest/compare/9f8307afbfd7...9203b85f0d18 View the full build log and details: https://travis-ci.org/hpk42/pytest/builds/10271811 -- You can configure recipients for build notifications in your .travis.yml file. See http://about.travis-ci.org/docs/user/build-configuration -------------- next part -------------- An HTML attachment was scrubbed... URL: From issues-reply at bitbucket.org Fri Aug 16 11:58:38 2013 From: issues-reply at bitbucket.org (holger krekel) Date: Fri, 16 Aug 2013 09:58:38 -0000 Subject: [Pytest-commit] Issue #115: tox travis support (hpk42/tox) Message-ID: <20130816095838.28909.76927@app01.ash-private.bitbucket.org> New issue 115: tox travis support https://bitbucket.org/hpk42/tox/issue/115/tox-travis-support holger krekel: tox should grow some support for converting/running from .travis.yml files. Via twitter @mgedmin @jezdez @dstufft all gave useful hints. Projects to look into for inspiration or integration: - Panci https://github.com/msabramo/python-panci - travis-solo https://github.com/jstasiak/travis-solo (via @jstasiak ) I think that generating a tox.ini on the fly could work well. It might make additions of features to tox neccessary. For example, it would be nice to be able to specify platform-dependent extra commands for installing debian packages etc. From issues-reply at bitbucket.org Fri Aug 16 20:30:51 2013 From: issues-reply at bitbucket.org (Monty Taylor) Date: Fri, 16 Aug 2013 18:30:51 -0000 Subject: [Pytest-commit] Issue #116: New pypi override breaks people who override pypi (hpk42/tox) Message-ID: <20130816183051.32295.71311@app10.ash-private.bitbucket.org> New issue 116: New pypi override breaks people who override pypi https://bitbucket.org/hpk42/tox/issue/116/new-pypi-override-breaks-people-who Monty Taylor: The OpenStack build farm has a decently complicated set of things it does to make sure that ~/.pip/pip.conf and ~/.pydistutils are set. The new hack_home_env code subverts that and is causing build failures in our build farm because it's causing things to actually talk to pypi.python.org, which we generally don't want to happen. BUT - we do not set pypi.openstack.org in our tox.ini files because we don't want devs running at home to be hitting our mirror. Can we add a flag that allows disabling this behavior? We could work around it by just setting TOX_INDEX_URL in the env - but there are times when we construct this: [global] index-url = http://pypi.openstack.org/openstack extra-index-url = http://pypi.python.org/simple For things that are not official, and therefore not covered by our mirror. From issues-reply at bitbucket.org Sat Aug 17 17:40:10 2013 From: issues-reply at bitbucket.org (Tomaz Muraus) Date: Sat, 17 Aug 2013 15:40:10 -0000 Subject: [Pytest-commit] Issue #117: Tox 1.6.0 breaks when running tests under Python 2.5 (pip < 1.4 doesn't seem to support --insecure option) (hpk42/tox) Message-ID: <20130817154010.4744.7647@app01.ash-private.bitbucket.org> New issue 117: Tox 1.6.0 breaks when running tests under Python 2.5 (pip < 1.4 doesn't seem to support --insecure option) https://bitbucket.org/hpk42/tox/issue/117/tox-160-breaks-when-running-tests-under Tomaz Muraus: Newest version of tox (1.6.0) uses pip < 1.4 when running tests with Python 2.5 and passes `--insecure` option to pip when installing the dependencies. The problem is that pip doesn't seem to support `--insecure` argument and even the new versions of pip use `--allow-insecure` and not `--insecure`. Error (I've truncated all the environment variables) ```bash kami /w/lc/libcloud (git:trunk)$ rm -rf .tox ; tox -e py25 GLOB sdist-make: /w/lc/libcloud/setup.py py25 create: /w/lc/libcloud/.tox/py25 py25 pip-downgrade: pip<1.4 py25 installdeps: mock, unittest2, lockfile, ssl, simplejson, paramiko py25 inst: /w/lc/libcloud/.tox/dist/apache-libcloud-0.14.0-dev.zip ERROR: invocation failed, logfile: /w/lc/libcloud/.tox/py25/log/py25-3.log ERROR: actionid=py25 msg=installpkg cmdargs=[local('/w/lc/libcloud/.tox/py25/bin/pip'), 'install', '--insecure', '/w/lc/libcloud/.tox/dist/apache-libcloud-0.14.0-dev.zip'] env={'PYTHONIOENCODING': 'utf_8', ....} Usage: pip install [options] ... pip install [options] -r ... pip install [options] [-e] ... pip install [options] [-e] ... pip install [options] ... no such option: --insecure ___________________________________________ summary ____________________________________________ ERROR: py25: InvocationError: /w/lc/libcloud/.tox/py25/bin/pip install --insecure /w/lc/libcloud/.tox/dist/apache-libcloud-0.14.0-dev.zip (see /w/lc/libcloud/.tox/py25/log/py25-3.log) ``` Tox version: ```bash tox --version 1.6.0 imported from /usr/local/lib/python2.7/dist-packages/tox/__init__.pyc ``` Pip version which get installed under Python 2.5 environments: ```bash /w/lc/libcloud/.tox/py25/bin/pip --version pip 1.3.1 from /w/lc/libcloud/.tox/py25/lib/python2.5/site-packages/pip-1.3.1-py2.5.egg (python 2.5) ``` Thanks From issues-reply at bitbucket.org Wed Aug 21 02:09:05 2013 From: issues-reply at bitbucket.org (Barry Warsaw) Date: Wed, 21 Aug 2013 00:09:05 -0000 Subject: [Pytest-commit] Issue #118: Test failures in a Debian build environment (hpk42/tox) Message-ID: <20130821000905.472.35865@app02.ash-private.bitbucket.org> New issue 118: Test failures in a Debian build environment https://bitbucket.org/hpk42/tox/issue/118/test-failures-in-a-debian-build Barry Warsaw: I'm updating the Debian unstable package to tox 1.6.0 and ran across two problems in test_venv.py. Both are due to realpath() checks and the fact that on Debian/Ubuntu, /usr/bin/python is a symlink to /usr/bin/python2.7. The fix is to be sure to .realpath() both sides of the assertion. From issues-reply at bitbucket.org Wed Aug 21 11:50:51 2013 From: issues-reply at bitbucket.org (Bogdan Hodorog) Date: Wed, 21 Aug 2013 09:50:51 -0000 Subject: [Pytest-commit] Issue #119: {envsitepackagesdir} doesn't substituted site-packages dir of tox's testenv (hpk42/tox) Message-ID: <20130821095051.422.33610@app09.ash-private.bitbucket.org> New issue 119: {envsitepackagesdir} doesn't substituted site-packages dir of tox's testenv https://bitbucket.org/hpk42/tox/issue/119/envsitepackagesdir-doesnt-substituted-site Bogdan Hodorog: # Steps to reproduce # 1. Create the following virtenv (==1.10.1) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.bash} virtualenv buggytox buggytox/bin/pip install tox ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The final virtenv should look like: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.bash} $ buggytox/bin/pip list pip (1.4.1) py (1.4.15) setuptools (0.9.8) tox (1.6.0) virtualenv (1.10.1) wsgiref (0.1.2) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2. Create a dummy project. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.bash} mkdir dummy echo "from setuptools import setup, find_packages setup( name="child", version="0.1", packages=find_packages(), )" > dummy/setup.py echo '[tox] envlist = buggy [testenv:buggy] commands = python -c "{envsitepackagesdir}"' > dummy/tox.ini ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3. Run tox ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.bash} cd dummy tox ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Expected # '.tox/buggytox/lib/python-xx/site-packages' is displayed # Actual # the 'buggytox/lib/python-xx/site-packages' is diplayed # Context # I came across this issue trying to have my tests run with py.tests. I opted having the tests included in the package and I was trying to follow [manual instructions](http://tox.readthedocs.org/en/latest/example/pytest.html#known-issues-and-limitations). I was expecting the {envsitepackagesdir} substitution will point to the [testenv:xx] site-packages dir. Infact I got the parent context site-packages dir which basically will render the method proposed in the forementioned link useless The [test code](https://bitbucket.org/hpk42/tox/src/78ace40b78b55eb729dd95cc7028347b73689739/tests/test_z_cmdline.py?at=default#cl-629) here for {envsitepackagesdir} subt is also quite generic, just checks a path containing 'site-packages' is obtained. From commits-noreply at bitbucket.org Wed Aug 21 13:38:14 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 21 Aug 2013 11:38:14 -0000 Subject: [Pytest-commit] commit/tox: 4 new changesets Message-ID: <20130821113814.24386.51023@app05.ash-private.bitbucket.org> 4 new commits in tox: https://bitbucket.org/hpk42/tox/commits/1e2f3676cd33/ Changeset: 1e2f3676cd33 User: hpk42 Date: 2013-08-18 13:08:12 Summary: fix doc typo Affected #: 1 file diff -r 78ace40b78b55eb729dd95cc7028347b73689739 -r 1e2f3676cd33a29d9c379be2da0d100f075d0fcb doc/config.txt --- a/doc/config.txt +++ b/doc/config.txt @@ -87,7 +87,7 @@ the virtual environment; both the package under test and any defined dependencies. Must contain the substitution key ``{packages}`` which will be replaced by the packages to - install. You should also accept "{opts}" if you are using + install. You should also accept ``{opts}`` if you are using pip or easy_install -- it will contain index server options if you have configured them via :confval:`indexserver` and the deprecated :confval:`downloadcache` option https://bitbucket.org/hpk42/tox/commits/e4c41b2148db/ Changeset: e4c41b2148db User: hpk42 Date: 2013-08-21 13:31:22 Summary: fix issue119: sitepackagesdir now correctly points to virtualenv dir, not tox's own. also added a test to prevent regression. Affected #: 3 files diff -r 1e2f3676cd33a29d9c379be2da0d100f075d0fcb -r e4c41b2148db9138278e3764f37cb2c834a9818e CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +1.6.1 +----- + +- fix issue119: {envsitepackagesdir} is now correctly computed and has + a better test to prevent regression. + + 1.6.0 ----------------- diff -r 1e2f3676cd33a29d9c379be2da0d100f075d0fcb -r e4c41b2148db9138278e3764f37cb2c834a9818e tests/test_z_cmdline.py --- a/tests/test_z_cmdline.py +++ b/tests/test_z_cmdline.py @@ -636,7 +636,7 @@ result = cmd.run("tox") assert result.ret == 0 result.stdout.fnmatch_lines(""" - X:*site-packages* + X:*.tox*python*site-packages* """) def verify_json_report_format(data, testenvs=True): diff -r 1e2f3676cd33a29d9c379be2da0d100f075d0fcb -r e4c41b2148db9138278e3764f37cb2c834a9818e tox/interpreters.py --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -20,6 +20,7 @@ return self.name2executable[name] except KeyError: self.name2executable[name] = e = find_executable(name) + print ("executable for %s is %s" %(name, e)) return e def get_info(self, name=None, executable=None): @@ -31,6 +32,7 @@ executable = self.get_executable(name) if not executable: return NoInterpreterInfo(name=name) + print ("get info for %s" % executable) try: return self.executable2info[executable] except KeyError: @@ -169,4 +171,4 @@ def sitepackagesdir(envdir): from distutils.sysconfig import get_python_lib - return dict(dir=get_python_lib(envdir)) + return dict(dir=get_python_lib(prefix=envdir)) https://bitbucket.org/hpk42/tox/commits/df42ff838df0/ Changeset: df42ff838df0 User: hpk42 Date: 2013-08-21 13:34:09 Summary: fix issue116: make 1.6 introduced behaviour of changing to a per-env HOME directory during install activities dependent on "--set-home" for now. Should re-establish the old behaviour. Affected #: 6 files diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ - fix issue119: {envsitepackagesdir} is now correctly computed and has a better test to prevent regression. +- fix issue116: make 1.6 introduced behaviour of changing to a + per-env HOME directory during install activities dependent + on "--set-home" for now. Should re-establish the old behaviour + when no option is given. 1.6.0 ----------------- diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e setup.py --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ description='virtualenv-based automation of test activities', long_description=open("README.rst").read(), url='http://tox.testrun.org/', - version='1.6.0', + version='1.6.1', license='http://opensource.org/licenses/MIT', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -568,6 +568,24 @@ x4 = venv.getcommandpath("x", cwd=tmpdir) mocksession.report.expect("warning", "*test command found but not*") +def test_sethome_only_on_option(newmocksession, monkeypatch): + mocksession = newmocksession([], "") + venv = mocksession.getenv('python') + action = mocksession.newaction(venv, "qwe", []) + monkeypatch.setattr(tox._venv, "hack_home_env", None) + venv._install(["x"], action=action) + +def test_sethome_works_on_option(newmocksession, monkeypatch): + mocksession = newmocksession(["--set-home", "-i ALL=http://qwe"], "") + venv = mocksession.getenv('python') + action = mocksession.newaction(venv, "qwe", []) + venv._install(["x"], action=action) + _, mocked = mocksession.report.getnext("logpopen") + p = mocked.env["HOME"] + pydist = py.path.local(p).join(".pydistutils.cfg") + assert "http://qwe" in pydist.read() + + def test_hack_home_env(tmpdir): from tox._venv import hack_home_env env = hack_home_env(tmpdir, "http://index") diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e tox/__init__.py --- a/tox/__init__.py +++ b/tox/__init__.py @@ -1,5 +1,5 @@ # -__version__ = '1.6.0' +__version__ = '1.6.1' class exception: class Error(Exception): diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e tox/_config.py --- a/tox/_config.py +++ b/tox/_config.py @@ -99,6 +99,10 @@ parser.add_argument("--develop", action="store_true", dest="develop", help="install package in the venv using 'setup.py develop' via " "'pip -e .'") + parser.add_argument("--set-home", action="store_true", dest="sethome", + help="(experimental) force creating a new $HOME for each test " + "environment and create .pydistutils.cfg|pip.conf files " + "if index servers are specified with tox. ") parser.add_argument('-i', action="append", dest="indexurl", metavar="URL", help="set indexserver url (if URL is of form name=url set the " diff -r e4c41b2148db9138278e3764f37cb2c834a9818e -r df42ff838df081b61fd4f02b4545cc33ee70062e tox/_venv.py --- a/tox/_venv.py +++ b/tox/_venv.py @@ -322,9 +322,13 @@ extraopts = extraopts or [] for ixserver in l: - extraenv = hack_home_env( - homedir=self.envconfig.envtmpdir.join("pseudo-home"), - index_url = ixserver.url) + if self.envconfig.config.option.sethome: + extraenv = hack_home_env( + homedir=self.envconfig.envtmpdir.join("pseudo-home"), + index_url = ixserver.url) + else: + extraenv = {} + args = d[ixserver] + extraopts self.run_install_command(args, ixserver.url, action, extraenv=extraenv) https://bitbucket.org/hpk42/tox/commits/714d84b76856/ Changeset: 714d84b76856 User: hpk42 Date: 2013-08-21 13:37:30 Summary: fix issue118: tests should check realpath() on both sides. Thanks Barry Warsaw. Affected #: 2 files diff -r df42ff838df081b61fd4f02b4545cc33ee70062e -r 714d84b76856a23f7b4967903130b95cd973475a CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,9 @@ on "--set-home" for now. Should re-establish the old behaviour when no option is given. +- fix issue118: correctly have two tests use realpath(). Thanks Barry + Warsaw. + 1.6.0 ----------------- diff -r df42ff838df081b61fd4f02b4545cc33ee70062e -r 714d84b76856a23f7b4967903130b95cd973475a tests/test_venv.py --- a/tests/test_venv.py +++ b/tests/test_venv.py @@ -25,7 +25,8 @@ venv = VirtualEnv(config.envconfigs['python'], session=mocksession) interp = venv.getsupportedinterpreter() # realpath needed for debian symlinks - assert interp == py.path.local(sys.executable).realpath() + assert py.path.local(interp).realpath() \ + == py.path.local(sys.executable).realpath() monkeypatch.setattr(sys, 'platform', "win32") monkeypatch.setattr(venv.envconfig, 'basepython', 'jython') py.test.raises(tox.exception.UnsupportedInterpreter, @@ -51,7 +52,8 @@ assert "virtualenv" in str(args[1]) if sys.platform != "win32": # realpath is needed for stuff like the debian symlinks - assert py.path.local(sys.executable).realpath() == args[0] + assert py.path.local(sys.executable).realpath() \ + == py.path.local(args[0]).realpath() #assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Aug 21 13:59:06 2013 From: commits-noreply at bitbucket.org (commits-noreply at bitbucket.org) Date: Wed, 21 Aug 2013 11:59:06 -0000 Subject: [Pytest-commit] commit/tox: hol...@merlinux.eu: fix prints Message-ID: <20130821115906.9083.51815@app04.ash-private.bitbucket.org> 1 new commit in tox: https://bitbucket.org/hpk42/tox/commits/8d1530139e75/ Changeset: 8d1530139e75 User: hol... at merlinux.eu Date: 2013-08-21 13:58:44 Summary: fix prints Affected #: 1 file diff -r 714d84b76856a23f7b4967903130b95cd973475a -r 8d1530139e75b6e417620b0f44c6f8ca0820aab9 tox/interpreters.py --- a/tox/interpreters.py +++ b/tox/interpreters.py @@ -20,7 +20,6 @@ return self.name2executable[name] except KeyError: self.name2executable[name] = e = find_executable(name) - print ("executable for %s is %s" %(name, e)) return e def get_info(self, name=None, executable=None): @@ -32,7 +31,6 @@ executable = self.get_executable(name) if not executable: return NoInterpreterInfo(name=name) - print ("get info for %s" % executable) try: return self.executable2info[executable] except KeyError: Repository URL: https://bitbucket.org/hpk42/tox/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From issues-reply at bitbucket.org Thu Aug 29 18:28:40 2013 From: issues-reply at bitbucket.org (Hynek Schlawack) Date: Thu, 29 Aug 2013 16:28:40 -0000 Subject: [Pytest-commit] Issue #120: Substitution breaks for commands substitution (hpk42/tox) Message-ID: <20130829162840.25031.67962@app09.ash-private.bitbucket.org> New issue 120: Substitution breaks for commands substitution https://bitbucket.org/hpk42/tox/issue/120/substitution-breaks-for-commands Hynek Schlawack: Since there doesn?t seem to be a way to describe several environments at once like `[testenv:py32,py33]` or just `[testenv:py3]` (please correct me if I?m wrong :)) I would like to substitute commands but when I do this: ``` [testenv:py32] commands = py.test --cov structlog --cov-config=.coveragerc.py3 [testenv:py33] commands = {[testenv:py32]commands} ``` I?ll get ``` ERROR: InvocationError: could not find executable 'py.test --cov structlog --cov-config=.coveragerc.py3' ``` If I copy and paste the command line, it works fine. My guess is that it tries to treat the whole command line as the executable instead of just `py.test` and splitting the rest as arguments? From issues-reply at bitbucket.org Fri Aug 30 02:15:32 2013 From: issues-reply at bitbucket.org (=?utf-8?q?Wojciech_Bana=C5=9B?=) Date: Fri, 30 Aug 2013 00:15:32 -0000 Subject: [Pytest-commit] Issue #121: White space in the path are reason an error in the "tox". (hpk42/tox) Message-ID: <20130830001532.25375.92763@app13.ash-private.bitbucket.org> New issue 121: White space in the path are reason an error in the "tox". https://bitbucket.org/hpk42/tox/issue/121/white-space-in-the-path-are-reason-an Wojciech Bana?: As shown below, if the path to the source program are white space (in this case the spaces), the "tox" does not work and throws this error. When I moved the source to the directory "/home/wojciech/django-money" then the "tox" works. ``` #!python django-money$ tox GLOB sdist-make: /home/wojciech/Aptana Studio 3 Workspace/django-money/setup.py py27 create: /home/wojciech/Aptana Studio 3 Workspace/django-money/.tox/py27 py27 installdeps: -r"/home/wojciech/Aptana Studio 3 Workspace/django-money/requirements.txt" Traceback (most recent call last): File "/home/wojciech/.pyenv/versions/2.7.5/bin/tox", line 9, in load_entry_point('tox==1.6.0', 'console_scripts', 'tox')() File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 26, in main retcode = Session(config).runcommand() File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 301, in runcommand return self.subcommand_test() File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 433, in subcommand_test if self.setupenv(venv): File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 358, in setupenv status = venv.update(action=action) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_venv.py", line 142, in update self.install_deps(action) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_venv.py", line 272, in install_deps self._install(deps, action=action) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_venv.py", line 330, in _install extraenv=extraenv) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_venv.py", line 303, in run_install_command extraenv=env, action=action) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_venv.py", line 378, in _pcall return action.popen(args, cwd=cwd, env=env, redirect=redirect) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 96, in popen popen = self._popen(args, cwd, env=env, stdout=f, stderr=STDOUT) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/site-packages/tox/_cmdline.py", line 153, in _popen stdout=stdout, stderr=stderr, env=env) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/home/wojciech/.pyenv/versions/2.7.5/lib/python2.7/subprocess.py", line 1308, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory ```