Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop Python3.6 in CI, setup.cfg, and readme. #9442

Merged
merged 7 commits into from Dec 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 0 additions & 10 deletions .github/workflows/main.yml
Expand Up @@ -31,14 +31,12 @@ jobs:
fail-fast: false
matrix:
name: [
"windows-py36",
"windows-py37",
"windows-py37-pluggy",
"windows-py38",
"windows-py39",
"windows-py310",

"ubuntu-py36",
"ubuntu-py37",
"ubuntu-py37-pluggy",
"ubuntu-py37-freeze",
Expand All @@ -56,10 +54,6 @@ jobs:
]

include:
- name: "windows-py36"
python: "3.6"
os: windows-latest
tox_env: "py36-xdist"
- name: "windows-py37"
python: "3.7"
os: windows-latest
Expand All @@ -82,10 +76,6 @@ jobs:
os: windows-latest
tox_env: "py310-xdist"

- name: "ubuntu-py36"
python: "3.6"
os: ubuntu-latest
tox_env: "py36-xdist"
- name: "ubuntu-py37"
python: "3.7"
os: ubuntu-latest
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Expand Up @@ -32,12 +32,12 @@ repos:
rev: v2.6.0
hooks:
- id: reorder-python-imports
args: ['--application-directories=.:src', --py36-plus]
args: ['--application-directories=.:src', --py37-plus]
- repo: https://github.com/asottile/pyupgrade
rev: v2.29.1
hooks:
- id: pyupgrade
args: [--py36-plus]
args: [--py37-plus]
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v1.20.0
hooks:
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -100,7 +100,7 @@ Features
- Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial),
`nose <https://docs.pytest.org/en/stable/how-to/nose.html>`_ test suites out of the box

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

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

Expand Down
1 change: 1 addition & 0 deletions changelog/9437.breaking.rst
@@ -0,0 +1 @@
Dropped support for Python 3.6, which reached `end-of-life <https://devguide.python.org/#status-of-python-branches>`__ at 2021-12-23.
2 changes: 1 addition & 1 deletion doc/en/getting-started.rst
Expand Up @@ -9,7 +9,7 @@ Get Started
Install ``pytest``
----------------------------------------

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

1. Run the following command in your command line:

Expand Down
4 changes: 2 additions & 2 deletions doc/en/how-to/skipping.rst
Expand Up @@ -84,14 +84,14 @@ It is also possible to skip the whole module using

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

.. code-block:: python

import sys


@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher")
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
def test_function():
...

Expand Down
4 changes: 2 additions & 2 deletions doc/en/index.rst
Expand Up @@ -17,7 +17,7 @@ The ``pytest`` framework makes it easy to write small, readable tests, and can
scale to support complex functional testing for applications and libraries.


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

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

Expand Down Expand Up @@ -78,7 +78,7 @@ Features

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

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

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

Expand Down
2 changes: 0 additions & 2 deletions pyproject.toml
Expand Up @@ -28,8 +28,6 @@ filterwarnings = [
"default:the imp module is deprecated in favour of importlib:DeprecationWarning:nose.*",
# distutils is deprecated in 3.10, scheduled for removal in 3.12
"ignore:The distutils package is deprecated:DeprecationWarning",
# produced by python3.6/site.py itself (3.6.7 on Travis, could not trigger it with 3.6.8)."
"ignore:.*U.*mode is deprecated:DeprecationWarning:(?!(pytest|_pytest))",
# produced by pytest-xdist
"ignore:.*type argument to addoption.*:DeprecationWarning",
# produced on execnet (pytest-xdist)
Expand Down
3 changes: 1 addition & 2 deletions setup.cfg
Expand Up @@ -17,7 +17,6 @@ classifiers =
Operating System :: POSIX
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Expand Down Expand Up @@ -51,7 +50,7 @@ install_requires =
atomicwrites>=1.0;sys_platform=="win32"
colorama;sys_platform=="win32"
importlib-metadata>=0.12;python_version<"3.8"
python_requires = >=3.6
python_requires = >=3.7
package_dir =
=src
setup_requires =
Expand Down
17 changes: 7 additions & 10 deletions src/_pytest/assertion/rewrite.py
Expand Up @@ -293,9 +293,8 @@ def _write_pyc_fp(
# import. However, there's little reason to deviate.
fp.write(importlib.util.MAGIC_NUMBER)
# https://www.python.org/dev/peps/pep-0552/
if sys.version_info >= (3, 7):
flags = b"\x00\x00\x00\x00"
fp.write(flags)
flags = b"\x00\x00\x00\x00"
fp.write(flags)
# as of now, bytecode header expects 32-bit numbers for size and mtime (#4903)
mtime = int(source_stat.st_mtime) & 0xFFFFFFFF
size = source_stat.st_size & 0xFFFFFFFF
Expand Down Expand Up @@ -376,31 +375,29 @@ def _read_pyc(
except OSError:
return None
with fp:
# https://www.python.org/dev/peps/pep-0552/
has_flags = sys.version_info >= (3, 7)
try:
stat_result = os.stat(source)
mtime = int(stat_result.st_mtime)
size = stat_result.st_size
data = fp.read(16 if has_flags else 12)
data = fp.read(16)
except OSError as e:
trace(f"_read_pyc({source}): OSError {e}")
return None
# Check for invalid or out of date pyc file.
if len(data) != (16 if has_flags else 12):
if len(data) != (16):
trace("_read_pyc(%s): invalid pyc (too short)" % source)
return None
if data[:4] != importlib.util.MAGIC_NUMBER:
trace("_read_pyc(%s): invalid pyc (bad magic number)" % source)
return None
if has_flags and data[4:8] != b"\x00\x00\x00\x00":
if data[4:8] != b"\x00\x00\x00\x00":
trace("_read_pyc(%s): invalid pyc (unsupported flags)" % source)
return None
mtime_data = data[8 if has_flags else 4 : 12 if has_flags else 8]
mtime_data = data[8:12]
if int.from_bytes(mtime_data, "little") != mtime & 0xFFFFFFFF:
trace("_read_pyc(%s): out of date" % source)
return None
size_data = data[12 if has_flags else 8 : 16 if has_flags else 12]
size_data = data[12:16]
if int.from_bytes(size_data, "little") != size & 0xFFFFFFFF:
trace("_read_pyc(%s): invalid pyc (incorrect size)" % source)
return None
Expand Down
11 changes: 0 additions & 11 deletions src/_pytest/compat.py
Expand Up @@ -4,7 +4,6 @@
import inspect
import os
import sys
from contextlib import contextmanager
from inspect import Parameter
from inspect import signature
from pathlib import Path
Expand Down Expand Up @@ -186,16 +185,6 @@ def getfuncargnames(
return arg_names


if sys.version_info < (3, 7):

@contextmanager
def nullcontext():
yield

else:
from contextlib import nullcontext as nullcontext # noqa: F401


def get_default_arg_names(function: Callable[..., Any]) -> Tuple[str, ...]:
# Note: this code intentionally mirrors the code at the beginning of
# getfuncargnames, to get the arguments which were excluded from its result
Expand Down
14 changes: 2 additions & 12 deletions src/_pytest/logging.py
Expand Up @@ -3,8 +3,8 @@
import logging
import os
import re
import sys
from contextlib import contextmanager
from contextlib import nullcontext
from io import StringIO
from pathlib import Path
from typing import AbstractSet
Expand All @@ -22,7 +22,6 @@
from _pytest._io import TerminalWriter
from _pytest.capture import CaptureManager
from _pytest.compat import final
from _pytest.compat import nullcontext
from _pytest.config import _strtobool
from _pytest.config import Config
from _pytest.config import create_terminal_writer
Expand Down Expand Up @@ -628,16 +627,7 @@ def set_log_path(self, fname: str) -> None:

# https://github.com/python/mypy/issues/11193
stream: io.TextIOWrapper = fpath.open(mode="w", encoding="UTF-8") # type: ignore[assignment]
if sys.version_info >= (3, 7):
old_stream = self.log_file_handler.setStream(stream)
else:
old_stream = self.log_file_handler.stream
self.log_file_handler.acquire()
try:
self.log_file_handler.flush()
self.log_file_handler.stream = stream
finally:
self.log_file_handler.release()
old_stream = self.log_file_handler.setStream(stream)
if old_stream:
old_stream.close()

Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/pytester.py
Expand Up @@ -128,7 +128,7 @@ def get_open_files(self) -> List[Tuple[str, str]]:
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
check=True,
universal_newlines=True,
text=True,
).stdout

def isopen(line: str) -> bool:
Expand Down
28 changes: 0 additions & 28 deletions testing/test_debugging.py
Expand Up @@ -8,14 +8,6 @@
from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import Pytester

try:
# Type ignored for Python <= 3.6.
breakpoint # type: ignore
except NameError:
SUPPORTS_BREAKPOINT_BUILTIN = False
else:
SUPPORTS_BREAKPOINT_BUILTIN = True


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

Expand Down Expand Up @@ -911,14 +903,6 @@ def test_foo():


class TestDebuggingBreakpoints:
def test_supports_breakpoint_module_global(self) -> None:
"""Test that supports breakpoint global marks on Python 3.7+."""
if sys.version_info >= (3, 7):
assert SUPPORTS_BREAKPOINT_BUILTIN is True

@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
)
@pytest.mark.parametrize("arg", ["--pdb", ""])
def test_sys_breakpointhook_configure_and_unconfigure(
self, pytester: Pytester, arg: str
Expand Down Expand Up @@ -952,9 +936,6 @@ def test_nothing(): pass
result = pytester.runpytest_subprocess(*args)
result.stdout.fnmatch_lines(["*1 passed in *"])

@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
)
def test_pdb_custom_cls(self, pytester: Pytester, custom_debugger_hook) -> None:
p1 = pytester.makepyfile(
"""
Expand All @@ -969,9 +950,6 @@ def test_nothing():
assert custom_debugger_hook == ["init", "set_trace"]

@pytest.mark.parametrize("arg", ["--pdb", ""])
@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
)
def test_environ_custom_class(
self, pytester: Pytester, custom_debugger_hook, arg: str
) -> None:
Expand Down Expand Up @@ -1002,9 +980,6 @@ def test_nothing(): pass
result = pytester.runpytest_subprocess(*args)
result.stdout.fnmatch_lines(["*1 passed in *"])

@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
)
@pytest.mark.skipif(
not _ENVIRON_PYTHONBREAKPOINT == "",
reason="Requires breakpoint() default value",
Expand All @@ -1025,9 +1000,6 @@ def test_1():
assert "reading from stdin while output" not in rest
TestPDB.flush(child)

@pytest.mark.skipif(
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
)
def test_pdb_not_altered(self, pytester: Pytester) -> None:
p1 = pytester.makepyfile(
"""
Expand Down
2 changes: 1 addition & 1 deletion testing/test_parseopt.py
Expand Up @@ -295,7 +295,7 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
check=True,
universal_newlines=True,
text=True,
).stdout
except (OSError, subprocess.CalledProcessError):
pytest.skip("bash is not available")
Expand Down
1 change: 0 additions & 1 deletion tox.ini
Expand Up @@ -4,7 +4,6 @@ minversion = 3.20.0
distshare = {homedir}/.tox/distshare
envlist =
linting
py36
py37
py38
py39
Expand Down