Skip to content

Commit 47d7f2b

Browse files
authored
Merge pull request #6123 from xavfernandez/deprecate34
Deprecate Python 3.4
2 parents 4dc8710 + b268c67 commit 47d7f2b

File tree

8 files changed

+64
-21
lines changed

8 files changed

+64
-21
lines changed

news/6106.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deprecate support for Python 3.4

src/pip/_internal/cli/base_command.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
install_req_from_editable, install_req_from_line,
2727
)
2828
from pip._internal.req.req_file import parse_requirements
29+
from pip._internal.utils.deprecation import deprecated
2930
from pip._internal.utils.logging import setup_logging
3031
from pip._internal.utils.misc import (
3132
get_prog, normalize_path, redact_password_from_url,
@@ -134,6 +135,15 @@ def main(self, args):
134135
user_log_file=options.log,
135136
)
136137

138+
if sys.version_info[:2] == (3, 4):
139+
deprecated(
140+
"Python 3.4 support has been deprecated. pip 19.1 will be the "
141+
"last one supporting it. Please upgrade your Python as Python "
142+
"3.4 won't be maintained after March 2019 (cf PEP 429).",
143+
replacement=None,
144+
gone_in='19.2',
145+
)
146+
137147
# TODO: Try to get these passing down from the command?
138148
# without resorting to os.environ to hold these.
139149
# This also affects isolated builds and it should.

tests/conftest.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def with_wheel(virtualenv, wheel_install):
277277

278278

279279
@pytest.fixture
280-
def script(tmpdir, virtualenv):
280+
def script(tmpdir, virtualenv, deprecated_python):
281281
"""
282282
Return a PipTestEnvironment which is unique to each test function and
283283
will execute all commands inside of the unique virtual environment for this
@@ -301,6 +301,9 @@ def script(tmpdir, virtualenv):
301301
# PipTestEnvironment needs to capture and assert against temp
302302
capture_temp=True,
303303
assert_no_temp=True,
304+
305+
# Deprecated python versions produce an extra deprecation warning
306+
pip_expect_stderr=deprecated_python,
304307
)
305308

306309

@@ -341,3 +344,9 @@ def pip(self, *args):
341344
@pytest.fixture
342345
def in_memory_pip():
343346
return InMemoryPip()
347+
348+
349+
@pytest.fixture
350+
def deprecated_python():
351+
"""Used to indicate wheither pip deprecated this python version"""
352+
return sys.version_info[:2] == (3, 4)

tests/functional/test_completion.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,10 @@ def test_completion_path_after_option(script, data):
283283

284284

285285
@pytest.mark.parametrize('flag', ['--bash', '--zsh', '--fish'])
286-
def test_completion_uses_same_executable_name(script, flag):
287-
expect_stderr = sys.version_info[:2] == (3, 3)
286+
def test_completion_uses_same_executable_name(script, flag, deprecated_python):
288287
executable_name = 'pip{}'.format(sys.version_info[0])
288+
# Deprecated python versions produce an extra deprecation warning
289289
result = script.run(
290-
executable_name, 'completion', flag, expect_stderr=expect_stderr
290+
executable_name, 'completion', flag, expect_stderr=deprecated_python,
291291
)
292292
assert executable_name in result.stdout

tests/functional/test_freeze.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,16 @@ def test_freeze_editable_not_vcs(script, tmpdir):
138138

139139

140140
@pytest.mark.git
141-
def test_freeze_editable_git_with_no_remote(script, tmpdir):
141+
def test_freeze_editable_git_with_no_remote(script, tmpdir, deprecated_python):
142142
"""
143143
Test an editable Git install with no remote url.
144144
"""
145145
pkg_path = _create_test_package(script)
146146
script.pip('install', '-e', pkg_path)
147147
result = script.pip('freeze')
148148

149-
assert result.stderr == ''
149+
if not deprecated_python:
150+
assert result.stderr == ''
150151

151152
# We need to apply os.path.normcase() to the path since that is what
152153
# the freeze code does.
@@ -460,7 +461,8 @@ def test_freeze_bazaar_clone(script, tmpdir):
460461
""")
461462

462463

463-
def test_freeze_with_requirement_option_file_url_egg_not_installed(script):
464+
def test_freeze_with_requirement_option_file_url_egg_not_installed(
465+
script, deprecated_python):
464466
"""
465467
Test "freeze -r requirements.txt" with a local file URL whose egg name
466468
is not installed.
@@ -477,7 +479,10 @@ def test_freeze_with_requirement_option_file_url_egg_not_installed(script):
477479
'Requirement file [requirements.txt] contains {}, but package '
478480
"'Does.Not-Exist' is not installed\n"
479481
).format(url)
480-
assert result.stderr == expected_err
482+
if deprecated_python:
483+
assert expected_err in result.stderr
484+
else:
485+
assert expected_err == result.stderr
481486

482487

483488
def test_freeze_with_requirement_option(script):

tests/functional/test_install.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def test_pep518_uses_build_env(script, data, common_wheels, command, variant):
3737
)
3838

3939

40-
def test_pep518_build_env_uses_same_pip(script, data, pip_src, common_wheels):
40+
def test_pep518_build_env_uses_same_pip(
41+
script, data, pip_src, common_wheels, deprecated_python):
4142
"""Ensure the subprocess call to pip for installing the
4243
build dependencies is using the same version of pip.
4344
"""
@@ -47,6 +48,7 @@ def test_pep518_build_env_uses_same_pip(script, data, pip_src, common_wheels):
4748
'python', pip_src / 'src/pip', 'install', '--no-index',
4849
'-f', common_wheels, '-f', data.packages,
4950
data.src.join("pep518-3.0"),
51+
expect_stderr=deprecated_python,
5052
)
5153

5254

@@ -162,16 +164,16 @@ def test_pep518_forkbombs(script, data, common_wheels, command, package):
162164

163165

164166
@pytest.mark.network
165-
def test_pip_second_command_line_interface_works(script, pip_src, data,
166-
common_wheels):
167+
def test_pip_second_command_line_interface_works(
168+
script, pip_src, data, common_wheels, deprecated_python):
167169
"""
168170
Check if ``pip<PYVERSION>`` commands behaves equally
169171
"""
170172
# Re-install pip so we get the launchers.
171173
script.pip_install_local('-f', common_wheels, pip_src)
172174
# On old versions of Python, urllib3/requests will raise a warning about
173175
# the lack of an SSLContext.
174-
kwargs = {}
176+
kwargs = {'expect_stderr': deprecated_python}
175177
if pyversion_tuple < (2, 7, 9):
176178
kwargs['expect_stderr'] = True
177179

tests/functional/test_install_check.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from tests.lib import create_test_package_with_setup
22

33

4-
def matches_expected_lines(string, expected_lines):
5-
return set(string.splitlines()) == set(expected_lines)
4+
def matches_expected_lines(string, expected_lines, exact=True):
5+
if exact:
6+
return set(string.splitlines()) == set(expected_lines)
7+
# If not exact, check that all expected lines are present
8+
return set(expected_lines) <= set(string.splitlines())
69

710

8-
def test_check_install_canonicalization(script):
11+
def test_check_install_canonicalization(script, deprecated_python):
912
pkga_path = create_test_package_with_setup(
1013
script,
1114
name='pkgA',
@@ -33,7 +36,9 @@ def test_check_install_canonicalization(script):
3336
expected_lines = [
3437
"pkga 1.0 requires SPECIAL.missing, which is not installed.",
3538
]
36-
assert matches_expected_lines(result.stderr, expected_lines)
39+
# Deprecated python versions produce an extra warning on stderr
40+
assert matches_expected_lines(
41+
result.stderr, expected_lines, exact=not deprecated_python)
3742
assert result.returncode == 0
3843

3944
# Install the second missing package and expect that there is no warning
@@ -42,7 +47,8 @@ def test_check_install_canonicalization(script):
4247
result = script.pip(
4348
'install', '--no-index', special_path, '--quiet',
4449
)
45-
assert matches_expected_lines(result.stderr, [])
50+
assert matches_expected_lines(
51+
result.stderr, [], exact=not deprecated_python)
4652
assert result.returncode == 0
4753

4854
# Double check that all errors are resolved in the end
@@ -54,7 +60,8 @@ def test_check_install_canonicalization(script):
5460
assert result.returncode == 0
5561

5662

57-
def test_check_install_does_not_warn_for_out_of_graph_issues(script):
63+
def test_check_install_does_not_warn_for_out_of_graph_issues(
64+
script, deprecated_python):
5865
pkg_broken_path = create_test_package_with_setup(
5966
script,
6067
name='broken',
@@ -74,7 +81,9 @@ def test_check_install_does_not_warn_for_out_of_graph_issues(script):
7481

7582
# Install a package without it's dependencies
7683
result = script.pip('install', '--no-index', pkg_broken_path, '--no-deps')
77-
assert matches_expected_lines(result.stderr, [])
84+
# Deprecated python versions produce an extra warning on stderr
85+
assert matches_expected_lines(
86+
result.stderr, [], exact=not deprecated_python)
7887

7988
# Install conflict package
8089
result = script.pip(
@@ -86,14 +95,15 @@ def test_check_install_does_not_warn_for_out_of_graph_issues(script):
8695
"broken 1.0 has requirement conflict<1.0, but "
8796
"you'll have conflict 1.0 which is incompatible."
8897
),
89-
])
98+
], exact=not deprecated_python)
9099

91100
# Install unrelated package
92101
result = script.pip(
93102
'install', '--no-index', pkg_unrelated_path, '--quiet',
94103
)
95104
# should not warn about broken's deps when installing unrelated package
96-
assert matches_expected_lines(result.stderr, [])
105+
assert matches_expected_lines(
106+
result.stderr, [], exact=not deprecated_python)
97107

98108
result = script.pip('check', expect_error=True)
99109
expected_lines = [

tests/lib/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ def __init__(self, base_path, *args, **kwargs):
323323
environ["PYTHONIOENCODING"] = "UTF-8"
324324
kwargs["environ"] = environ
325325

326+
# Whether all pip invocations should expect stderr
327+
# (useful for Python version deprecation)
328+
self.pip_expect_stderr = kwargs.pop('pip_expect_stderr', None)
329+
326330
# Call the TestFileEnvironment __init__
327331
super(PipTestEnvironment, self).__init__(base_path, *args, **kwargs)
328332

@@ -375,6 +379,8 @@ def run(self, *args, **kw):
375379
)
376380

377381
def pip(self, *args, **kwargs):
382+
if self.pip_expect_stderr:
383+
kwargs['expect_stderr'] = True
378384
# On old versions of Python, urllib3/requests will raise a warning
379385
# about the lack of an SSLContext. Expect it when running commands
380386
# that will touch the outside world.

0 commit comments

Comments
 (0)