1import glob 2import os 3import sys 4import itertools 5 6import pathlib 7 8import pytest 9from pytest_fixture_config import yield_requires_config 10 11import pytest_virtualenv 12 13from .textwrap import DALS 14from .test_easy_install import make_nspkg_sdist 15 16 17@pytest.fixture(autouse=True) 18def pytest_virtualenv_works(virtualenv): 19 """ 20 pytest_virtualenv may not work. if it doesn't, skip these 21 tests. See #1284. 22 """ 23 venv_prefix = virtualenv.run( 24 'python -c "import sys; print(sys.prefix)"', 25 capture=True, 26 ).strip() 27 if venv_prefix == sys.prefix: 28 pytest.skip("virtualenv is broken (see pypa/setuptools#1284)") 29 30 31@yield_requires_config(pytest_virtualenv.CONFIG, ['virtualenv_executable']) 32@pytest.fixture(scope='function') 33def bare_virtualenv(): 34 """ Bare virtualenv (no pip/setuptools/wheel). 35 """ 36 with pytest_virtualenv.VirtualEnv(args=( 37 '--no-wheel', 38 '--no-pip', 39 '--no-setuptools', 40 )) as venv: 41 yield venv 42 43 44def test_clean_env_install(bare_virtualenv, tmp_src): 45 """ 46 Check setuptools can be installed in a clean environment. 47 """ 48 bare_virtualenv.run(['python', 'setup.py', 'install'], cd=tmp_src) 49 50 51def _get_pip_versions(): 52 # This fixture will attempt to detect if tests are being run without 53 # network connectivity and if so skip some tests 54 55 network = True 56 if not os.environ.get('NETWORK_REQUIRED', False): # pragma: nocover 57 try: 58 from urllib.request import urlopen 59 from urllib.error import URLError 60 except ImportError: 61 from urllib2 import urlopen, URLError # Python 2.7 compat 62 63 try: 64 urlopen('https://pypi.org', timeout=1) 65 except URLError: 66 # No network, disable most of these tests 67 network = False 68 69 def mark(param, *marks): 70 if not isinstance(param, type(pytest.param(''))): 71 param = pytest.param(param) 72 return param._replace(marks=param.marks + marks) 73 74 def skip_network(param): 75 return param if network else mark(param, pytest.mark.skip(reason="no network")) 76 77 issue2599 = pytest.mark.skipif( 78 sys.version_info > (3, 10), 79 reason="pypa/setuptools#2599", 80 ) 81 82 network_versions = [ 83 mark('pip==9.0.3', issue2599), 84 mark('pip==10.0.1', issue2599), 85 mark('pip==18.1', issue2599), 86 mark('pip==19.3.1', pytest.mark.xfail(reason='pypa/pip#6599')), 87 'pip==20.0.2', 88 'https://github.com/pypa/pip/archive/main.zip', 89 ] 90 91 versions = itertools.chain( 92 [None], 93 map(skip_network, network_versions) 94 ) 95 96 return list(versions) 97 98 99@pytest.mark.parametrize('pip_version', _get_pip_versions()) 100def test_pip_upgrade_from_source(pip_version, tmp_src, virtualenv): 101 """ 102 Check pip can upgrade setuptools from source. 103 """ 104 # Install pip/wheel, and remove setuptools (as it 105 # should not be needed for bootstraping from source) 106 if pip_version is None: 107 upgrade_pip = () 108 else: 109 upgrade_pip = ('python -m pip install -U {pip_version} --retries=1',) 110 virtualenv.run(' && '.join(( 111 'pip uninstall -y setuptools', 112 'pip install -U wheel', 113 ) + upgrade_pip).format(pip_version=pip_version)) 114 dist_dir = virtualenv.workspace 115 # Generate source distribution / wheel. 116 virtualenv.run(' && '.join(( 117 'python setup.py -q sdist -d {dist}', 118 'python setup.py -q bdist_wheel -d {dist}', 119 )).format(dist=dist_dir), cd=tmp_src) 120 sdist = glob.glob(os.path.join(dist_dir, '*.zip'))[0] 121 wheel = glob.glob(os.path.join(dist_dir, '*.whl'))[0] 122 # Then update from wheel. 123 virtualenv.run('pip install ' + wheel) 124 # And finally try to upgrade from source. 125 virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist) 126 127 128def _check_test_command_install_requirements(virtualenv, tmpdir, cwd): 129 """ 130 Check the test command will install all required dependencies. 131 """ 132 # Install setuptools. 133 virtualenv.run('python setup.py develop', cd=cwd) 134 135 def sdist(distname, version): 136 dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version)) 137 make_nspkg_sdist(str(dist_path), distname, version) 138 return dist_path 139 dependency_links = [ 140 pathlib.Path(str(dist_path)).as_uri() 141 for dist_path in ( 142 sdist('foobar', '2.4'), 143 sdist('bits', '4.2'), 144 sdist('bobs', '6.0'), 145 sdist('pieces', '0.6'), 146 ) 147 ] 148 with tmpdir.join('setup.py').open('w') as fp: 149 fp.write(DALS( 150 ''' 151 from setuptools import setup 152 153 setup( 154 dependency_links={dependency_links!r}, 155 install_requires=[ 156 'barbazquux1; sys_platform in ""', 157 'foobar==2.4', 158 ], 159 setup_requires='bits==4.2', 160 tests_require=""" 161 bobs==6.0 162 """, 163 extras_require={{ 164 'test': ['barbazquux2'], 165 ':"" in sys_platform': 'pieces==0.6', 166 ':python_version > "1"': """ 167 pieces 168 foobar 169 """, 170 }} 171 ) 172 '''.format(dependency_links=dependency_links))) 173 with tmpdir.join('test.py').open('w') as fp: 174 fp.write(DALS( 175 ''' 176 import foobar 177 import bits 178 import bobs 179 import pieces 180 181 open('success', 'w').close() 182 ''')) 183 # Run test command for test package. 184 # use 'virtualenv.python' as workaround for man-group/pytest-plugins#166 185 cmd = [virtualenv.python, 'setup.py', 'test', '-s', 'test'] 186 virtualenv.run(cmd, cd=str(tmpdir)) 187 assert tmpdir.join('success').check() 188 189 190def test_test_command_install_requirements(virtualenv, tmpdir, request): 191 # Ensure pip/wheel packages are installed. 192 virtualenv.run( 193 "python -c \"__import__('pkg_resources').require(['pip', 'wheel'])\"") 194 # uninstall setuptools so that 'setup.py develop' works 195 virtualenv.run("python -m pip uninstall -y setuptools") 196 # disable index URL so bits and bobs aren't requested from PyPI 197 virtualenv.env['PIP_NO_INDEX'] = '1' 198 _check_test_command_install_requirements(virtualenv, tmpdir, request.config.rootdir) 199 200 201def test_no_missing_dependencies(bare_virtualenv, request): 202 """ 203 Quick and dirty test to ensure all external dependencies are vendored. 204 """ 205 for command in ('upload',): # sorted(distutils.command.__all__): 206 cmd = ['python', 'setup.py', command, '-h'] 207 bare_virtualenv.run(cmd, cd=request.config.rootdir) 208