Skip to content

Commit b9663fe

Browse files
authored
Merge pull request #9442 from hramezani/drop_python_36
Drop Python3.6 in CI, setup.cfg, and readme.
2 parents 79dbd19 + 0b7c3d1 commit b9663fe

File tree

16 files changed

+21
-86
lines changed

16 files changed

+21
-86
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ jobs:
3131
fail-fast: false
3232
matrix:
3333
name: [
34-
"windows-py36",
3534
"windows-py37",
3635
"windows-py37-pluggy",
3736
"windows-py38",
3837
"windows-py39",
3938
"windows-py310",
4039

41-
"ubuntu-py36",
4240
"ubuntu-py37",
4341
"ubuntu-py37-pluggy",
4442
"ubuntu-py37-freeze",
@@ -56,10 +54,6 @@ jobs:
5654
]
5755

5856
include:
59-
- name: "windows-py36"
60-
python: "3.6"
61-
os: windows-latest
62-
tox_env: "py36-xdist"
6357
- name: "windows-py37"
6458
python: "3.7"
6559
os: windows-latest
@@ -82,10 +76,6 @@ jobs:
8276
os: windows-latest
8377
tox_env: "py310-xdist"
8478

85-
- name: "ubuntu-py36"
86-
python: "3.6"
87-
os: ubuntu-latest
88-
tox_env: "py36-xdist"
8979
- name: "ubuntu-py37"
9080
python: "3.7"
9181
os: ubuntu-latest

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ repos:
3232
rev: v2.6.0
3333
hooks:
3434
- id: reorder-python-imports
35-
args: ['--application-directories=.:src', --py36-plus]
35+
args: ['--application-directories=.:src', --py37-plus]
3636
- repo: https://github.com/asottile/pyupgrade
3737
rev: v2.29.1
3838
hooks:
3939
- id: pyupgrade
40-
args: [--py36-plus]
40+
args: [--py37-plus]
4141
- repo: https://github.com/asottile/setup-cfg-fmt
4242
rev: v1.20.0
4343
hooks:

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Features
100100
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial),
101101
`nose <https://docs.pytest.org/en/stable/how-to/nose.html>`_ test suites out of the box
102102

103-
- Python 3.6+ and PyPy3
103+
- Python 3.7+ or PyPy3
104104

105105
- Rich plugin architecture, with over 850+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
106106

changelog/9437.breaking.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dropped support for Python 3.6, which reached `end-of-life <https://devguide.python.org/#status-of-python-branches>`__ at 2021-12-23.

doc/en/getting-started.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Get Started
99
Install ``pytest``
1010
----------------------------------------
1111

12-
``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
12+
``pytest`` requires: Python 3.7+ or PyPy3.
1313

1414
1. Run the following command in your command line:
1515

doc/en/how-to/skipping.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ It is also possible to skip the whole module using
8484

8585
If you wish to skip something conditionally then you can use ``skipif`` instead.
8686
Here is an example of marking a test function to be skipped
87-
when run on an interpreter earlier than Python3.6:
87+
when run on an interpreter earlier than Python3.10:
8888

8989
.. code-block:: python
9090
9191
import sys
9292
9393
94-
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
94+
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
9595
def test_function():
9696
...
9797

doc/en/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The ``pytest`` framework makes it easy to write small, readable tests, and can
1717
scale to support complex functional testing for applications and libraries.
1818

1919

20-
**Pythons**: ``pytest`` requires: Python 3.6, 3.7, 3.8, 3.9, or PyPy3.
20+
``pytest`` requires: Python 3.7+ or PyPy3.
2121

2222
**PyPI package name**: :pypi:`pytest`
2323

@@ -78,7 +78,7 @@ Features
7878

7979
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box
8080

81-
- Python 3.6+ and PyPy 3
81+
- Python 3.7+ or PyPy 3
8282

8383
- Rich plugin architecture, with over 800+ :ref:`external plugins <plugin-list>` and thriving community
8484

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ filterwarnings = [
2828
"default:the imp module is deprecated in favour of importlib:DeprecationWarning:nose.*",
2929
# distutils is deprecated in 3.10, scheduled for removal in 3.12
3030
"ignore:The distutils package is deprecated:DeprecationWarning",
31-
# produced by python3.6/site.py itself (3.6.7 on Travis, could not trigger it with 3.6.8)."
32-
"ignore:.*U.*mode is deprecated:DeprecationWarning:(?!(pytest|_pytest))",
3331
# produced by pytest-xdist
3432
"ignore:.*type argument to addoption.*:DeprecationWarning",
3533
# produced on execnet (pytest-xdist)

setup.cfg

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ classifiers =
1717
Operating System :: POSIX
1818
Programming Language :: Python :: 3
1919
Programming Language :: Python :: 3 :: Only
20-
Programming Language :: Python :: 3.6
2120
Programming Language :: Python :: 3.7
2221
Programming Language :: Python :: 3.8
2322
Programming Language :: Python :: 3.9
@@ -51,7 +50,7 @@ install_requires =
5150
atomicwrites>=1.0;sys_platform=="win32"
5251
colorama;sys_platform=="win32"
5352
importlib-metadata>=0.12;python_version<"3.8"
54-
python_requires = >=3.6
53+
python_requires = >=3.7
5554
package_dir =
5655
=src
5756
setup_requires =

src/_pytest/assertion/rewrite.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,8 @@ def _write_pyc_fp(
293293
# import. However, there's little reason to deviate.
294294
fp.write(importlib.util.MAGIC_NUMBER)
295295
# https://www.python.org/dev/peps/pep-0552/
296-
if sys.version_info >= (3, 7):
297-
flags = b"\x00\x00\x00\x00"
298-
fp.write(flags)
296+
flags = b"\x00\x00\x00\x00"
297+
fp.write(flags)
299298
# as of now, bytecode header expects 32-bit numbers for size and mtime (#4903)
300299
mtime = int(source_stat.st_mtime) & 0xFFFFFFFF
301300
size = source_stat.st_size & 0xFFFFFFFF
@@ -376,31 +375,29 @@ def _read_pyc(
376375
except OSError:
377376
return None
378377
with fp:
379-
# https://www.python.org/dev/peps/pep-0552/
380-
has_flags = sys.version_info >= (3, 7)
381378
try:
382379
stat_result = os.stat(source)
383380
mtime = int(stat_result.st_mtime)
384381
size = stat_result.st_size
385-
data = fp.read(16 if has_flags else 12)
382+
data = fp.read(16)
386383
except OSError as e:
387384
trace(f"_read_pyc({source}): OSError {e}")
388385
return None
389386
# Check for invalid or out of date pyc file.
390-
if len(data) != (16 if has_flags else 12):
387+
if len(data) != (16):
391388
trace("_read_pyc(%s): invalid pyc (too short)" % source)
392389
return None
393390
if data[:4] != importlib.util.MAGIC_NUMBER:
394391
trace("_read_pyc(%s): invalid pyc (bad magic number)" % source)
395392
return None
396-
if has_flags and data[4:8] != b"\x00\x00\x00\x00":
393+
if data[4:8] != b"\x00\x00\x00\x00":
397394
trace("_read_pyc(%s): invalid pyc (unsupported flags)" % source)
398395
return None
399-
mtime_data = data[8 if has_flags else 4 : 12 if has_flags else 8]
396+
mtime_data = data[8:12]
400397
if int.from_bytes(mtime_data, "little") != mtime & 0xFFFFFFFF:
401398
trace("_read_pyc(%s): out of date" % source)
402399
return None
403-
size_data = data[12 if has_flags else 8 : 16 if has_flags else 12]
400+
size_data = data[12:16]
404401
if int.from_bytes(size_data, "little") != size & 0xFFFFFFFF:
405402
trace("_read_pyc(%s): invalid pyc (incorrect size)" % source)
406403
return None

src/_pytest/compat.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import inspect
55
import os
66
import sys
7-
from contextlib import contextmanager
87
from inspect import Parameter
98
from inspect import signature
109
from pathlib import Path
@@ -186,16 +185,6 @@ def getfuncargnames(
186185
return arg_names
187186

188187

189-
if sys.version_info < (3, 7):
190-
191-
@contextmanager
192-
def nullcontext():
193-
yield
194-
195-
else:
196-
from contextlib import nullcontext as nullcontext # noqa: F401
197-
198-
199188
def get_default_arg_names(function: Callable[..., Any]) -> Tuple[str, ...]:
200189
# Note: this code intentionally mirrors the code at the beginning of
201190
# getfuncargnames, to get the arguments which were excluded from its result

src/_pytest/logging.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import logging
44
import os
55
import re
6-
import sys
76
from contextlib import contextmanager
7+
from contextlib import nullcontext
88
from io import StringIO
99
from pathlib import Path
1010
from typing import AbstractSet
@@ -22,7 +22,6 @@
2222
from _pytest._io import TerminalWriter
2323
from _pytest.capture import CaptureManager
2424
from _pytest.compat import final
25-
from _pytest.compat import nullcontext
2625
from _pytest.config import _strtobool
2726
from _pytest.config import Config
2827
from _pytest.config import create_terminal_writer
@@ -628,16 +627,7 @@ def set_log_path(self, fname: str) -> None:
628627

629628
# https://github.com/python/mypy/issues/11193
630629
stream: io.TextIOWrapper = fpath.open(mode="w", encoding="UTF-8") # type: ignore[assignment]
631-
if sys.version_info >= (3, 7):
632-
old_stream = self.log_file_handler.setStream(stream)
633-
else:
634-
old_stream = self.log_file_handler.stream
635-
self.log_file_handler.acquire()
636-
try:
637-
self.log_file_handler.flush()
638-
self.log_file_handler.stream = stream
639-
finally:
640-
self.log_file_handler.release()
630+
old_stream = self.log_file_handler.setStream(stream)
641631
if old_stream:
642632
old_stream.close()
643633

src/_pytest/pytester.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def get_open_files(self) -> List[Tuple[str, str]]:
128128
stdout=subprocess.PIPE,
129129
stderr=subprocess.DEVNULL,
130130
check=True,
131-
universal_newlines=True,
131+
text=True,
132132
).stdout
133133

134134
def isopen(line: str) -> bool:

testing/test_debugging.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@
88
from _pytest.monkeypatch import MonkeyPatch
99
from _pytest.pytester import Pytester
1010

11-
try:
12-
# Type ignored for Python <= 3.6.
13-
breakpoint # type: ignore
14-
except NameError:
15-
SUPPORTS_BREAKPOINT_BUILTIN = False
16-
else:
17-
SUPPORTS_BREAKPOINT_BUILTIN = True
18-
1911

2012
_ENVIRON_PYTHONBREAKPOINT = os.environ.get("PYTHONBREAKPOINT", "")
2113

@@ -911,14 +903,6 @@ def test_foo():
911903

912904

913905
class TestDebuggingBreakpoints:
914-
def test_supports_breakpoint_module_global(self) -> None:
915-
"""Test that supports breakpoint global marks on Python 3.7+."""
916-
if sys.version_info >= (3, 7):
917-
assert SUPPORTS_BREAKPOINT_BUILTIN is True
918-
919-
@pytest.mark.skipif(
920-
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
921-
)
922906
@pytest.mark.parametrize("arg", ["--pdb", ""])
923907
def test_sys_breakpointhook_configure_and_unconfigure(
924908
self, pytester: Pytester, arg: str
@@ -952,9 +936,6 @@ def test_nothing(): pass
952936
result = pytester.runpytest_subprocess(*args)
953937
result.stdout.fnmatch_lines(["*1 passed in *"])
954938

955-
@pytest.mark.skipif(
956-
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
957-
)
958939
def test_pdb_custom_cls(self, pytester: Pytester, custom_debugger_hook) -> None:
959940
p1 = pytester.makepyfile(
960941
"""
@@ -969,9 +950,6 @@ def test_nothing():
969950
assert custom_debugger_hook == ["init", "set_trace"]
970951

971952
@pytest.mark.parametrize("arg", ["--pdb", ""])
972-
@pytest.mark.skipif(
973-
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
974-
)
975953
def test_environ_custom_class(
976954
self, pytester: Pytester, custom_debugger_hook, arg: str
977955
) -> None:
@@ -1002,9 +980,6 @@ def test_nothing(): pass
1002980
result = pytester.runpytest_subprocess(*args)
1003981
result.stdout.fnmatch_lines(["*1 passed in *"])
1004982

1005-
@pytest.mark.skipif(
1006-
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
1007-
)
1008983
@pytest.mark.skipif(
1009984
not _ENVIRON_PYTHONBREAKPOINT == "",
1010985
reason="Requires breakpoint() default value",
@@ -1025,9 +1000,6 @@ def test_1():
10251000
assert "reading from stdin while output" not in rest
10261001
TestPDB.flush(child)
10271002

1028-
@pytest.mark.skipif(
1029-
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
1030-
)
10311003
def test_pdb_not_altered(self, pytester: Pytester) -> None:
10321004
p1 = pytester.makepyfile(
10331005
"""

testing/test_parseopt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
295295
stdout=subprocess.PIPE,
296296
stderr=subprocess.DEVNULL,
297297
check=True,
298-
universal_newlines=True,
298+
text=True,
299299
).stdout
300300
except (OSError, subprocess.CalledProcessError):
301301
pytest.skip("bash is not available")

tox.ini

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ minversion = 3.20.0
44
distshare = {homedir}/.tox/distshare
55
envlist =
66
linting
7-
py36
87
py37
98
py38
109
py39

0 commit comments

Comments
 (0)