import os import subprocess import virtualenv from setuptools.extern.six.moves import http_client from setuptools.extern.six.moves import xmlrpc_client TOP = 200 PYPI_HOSTNAME = 'pypi.python.org' def rpc_pypi(method, *args): """Call an XML-RPC method on the Pypi server.""" conn = http_client.HTTPSConnection(PYPI_HOSTNAME) headers = {'Content-Type': 'text/xml'} payload = xmlrpc_client.dumps(args, method) conn.request("POST", "/pypi", payload, headers) response = conn.getresponse() if response.status == 200: result = xmlrpc_client.loads(response.read())[0][0] return result else: raise RuntimeError("Unable to download the list of top " "packages from Pypi.") def get_top_packages(limit): """Collect the name of the top packages on Pypi.""" packages = rpc_pypi('top_packages') return packages[:limit] def _package_install(package_name, tmp_dir=None, local_setuptools=True): """Try to install a package and return the exit status. This function creates a virtual environment, install setuptools using pip and then install the required package. If local_setuptools is True, it will install the local version of setuptools. """ package_dir = os.path.join(tmp_dir, "test_%s" % package_name) if not local_setuptools: package_dir = package_dir + "_baseline" virtualenv.create_environment(package_dir) pip_path = os.path.join(package_dir, "bin", "pip") if local_setuptools: subprocess.check_call([pip_path, "install", "."]) returncode = subprocess.call([pip_path, "install", package_name]) return returncode def test_package_install(package_name, tmpdir): """Test to verify the outcome of installing a package. This test compare that the return code when installing a package is the same as with the current stable version of setuptools. """ new_exit_status = _package_install(package_name, tmp_dir=str(tmpdir)) if new_exit_status: print("Installation failed, testing against stable setuptools", package_name) old_exit_status = _package_install(package_name, tmp_dir=str(tmpdir), local_setuptools=False) assert new_exit_status == old_exit_status def pytest_generate_tests(metafunc): """Generator function for test_package_install. This function will generate calls to test_package_install. If a package list has been specified on the command line, it will be used. Otherwise, Pypi will be queried to get the current list of top packages. """ if "package_name" in metafunc.fixturenames: if not metafunc.config.option.package_name: packages = get_top_packages(TOP) packages = [name for name, downloads in packages] else: packages = metafunc.config.option.package_name metafunc.parametrize("package_name", packages)