Skip to content

Commit

Permalink
build!: drop support for python 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
tysmith committed Oct 30, 2024
1 parent 64a9212 commit 0e7b79d
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 75 deletions.
6 changes: 1 addition & 5 deletions .taskcluster.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ tasks:
- tox; tox -e codecov
jobs:
include:
- name: tests python 3.8
version: "3.8"
env:
TOXENV: py38,lint
- name: tests python 3.9
version: "3.9"
env:
Expand Down Expand Up @@ -51,7 +47,7 @@ tasks:
env:
TOXENV: py312,lint
- name: PyPI upload
version: "3.8"
version: "3.9"
env:
TOXENV: pypi
script:
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ log_level = "DEBUG"

[tool.ruff]
fix = true
target-version = "py38"
target-version = "py39"

[tool.ruff.lint]
select = [
Expand Down Expand Up @@ -82,7 +82,6 @@ select = [
]
ignore = [
"PERF203",
"SIM117",
]

[tool.setuptools_scm]
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ package_dir =
= src
packages =
ffpuppet
python_requires = >=3.8
python_requires = >=3.9
zip_safe = False

[options.entry_points]
Expand Down
6 changes: 5 additions & 1 deletion src/ffpuppet/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
from abc import ABC, abstractmethod
from os import SEEK_SET, stat
from platform import system
from typing import IO, Callable, Iterable, Pattern
from typing import IO, TYPE_CHECKING, Callable

from psutil import AccessDenied, NoSuchProcess, Process

if TYPE_CHECKING:
from collections.abc import Iterable
from re import Pattern

__author__ = "Tyson Smith"
__credits__ = ["Tyson Smith"]

Expand Down
8 changes: 6 additions & 2 deletions src/ffpuppet/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@
from os.path import isfile, realpath
from pathlib import Path
from platform import system
from re import IGNORECASE
from re import IGNORECASE, Pattern
from re import compile as re_compile
from re import match as re_match
from shutil import copy, copyfileobj
from subprocess import Popen, check_output
from sys import executable
from typing import Generator, Pattern
from urllib.request import pathname2url

with suppress(ImportError):
Expand All @@ -30,6 +29,8 @@
with suppress(ImportError):
from xvfbwrapper import Xvfb

from typing import TYPE_CHECKING

from .bootstrapper import Bootstrapper
from .checks import CheckLogContents, CheckLogSize, CheckMemoryUsage
from .exceptions import BrowserExecutionError, InvalidPrefs, LaunchError
Expand All @@ -39,6 +40,9 @@
from .profile import Profile
from .puppet_logger import PuppetLogger

if TYPE_CHECKING:
from collections.abc import Generator

if system() == "Windows":
# config_job_object is only available on Windows
from .job_object import config_job_object, resume_suspended_process
Expand Down
5 changes: 4 additions & 1 deletion src/ffpuppet/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
from stat import S_IWUSR
from subprocess import STDOUT, CalledProcessError, check_output
from time import sleep, time
from typing import Any, Callable, Generator, Iterable
from typing import TYPE_CHECKING, Any, Callable

from psutil import Process, process_iter

from .sanitizer_util import SanitizerOptions

if TYPE_CHECKING:
from collections.abc import Generator, Iterable

if system() == "Windows":
from .lsof import pids_by_file

Expand Down
54 changes: 28 additions & 26 deletions src/ffpuppet/minidump_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,32 +168,34 @@ def create_log(self, src: Path, filename: str, timeout: int = 300) -> Path:
cmd = self._cmd(src)
dst = self._storage / filename
# using nested with statements for python 3.8 support
with TemporaryFile(dir=self._storage, prefix="mdsw_out_") as out_fp:
with TemporaryFile(dir=self._storage, prefix="mdsw_err_") as err_fp:
LOG.debug("running %r", " ".join(cmd))
try:
run(cmd, check=True, stderr=err_fp, stdout=out_fp, timeout=timeout)
out_fp.seek(0)
# load json, format data and write log
with dst.open("wb") as log_fp:
self._fmt_output(load(out_fp), log_fp)
except (CalledProcessError, JSONDecodeError, TimeoutExpired) as exc:
if isinstance(exc, CalledProcessError):
msg = f"minidump-stackwalk failed ({exc.returncode})"
elif isinstance(exc, JSONDecodeError):
msg = "json decode error"
else:
msg = "minidump-stackwalk timeout"
LOG.warning("Failed to parse minidump: %s", msg)
err_fp.seek(0)
out_fp.seek(0)
# write log
with dst.open("wb") as log_fp:
log_fp.write(f"Failed to parse minidump: {msg}".encode())
log_fp.write(b"\n\nminidump-stackwalk stderr:\n")
log_fp.write(err_fp.read())
log_fp.write(b"\n\nminidump-stackwalk stdout:\n")
log_fp.write(out_fp.read())
with (
TemporaryFile(dir=self._storage, prefix="mdsw_out_") as out_fp,
TemporaryFile(dir=self._storage, prefix="mdsw_err_") as err_fp,
):
LOG.debug("running %r", " ".join(cmd))
try:
run(cmd, check=True, stderr=err_fp, stdout=out_fp, timeout=timeout)
out_fp.seek(0)
# load json, format data and write log
with dst.open("wb") as log_fp:
self._fmt_output(load(out_fp), log_fp)
except (CalledProcessError, JSONDecodeError, TimeoutExpired) as exc:
if isinstance(exc, CalledProcessError):
msg = f"minidump-stackwalk failed ({exc.returncode})"
elif isinstance(exc, JSONDecodeError):
msg = "json decode error"
else:
msg = "minidump-stackwalk timeout"
LOG.warning("Failed to parse minidump: %s", msg)
err_fp.seek(0)
out_fp.seek(0)
# write log
with dst.open("wb") as log_fp:
log_fp.write(f"Failed to parse minidump: {msg}".encode())
log_fp.write(b"\n\nminidump-stackwalk stderr:\n")
log_fp.write(err_fp.read())
log_fp.write(b"\n\nminidump-stackwalk stdout:\n")
log_fp.write(out_fp.read())
return dst

@staticmethod
Expand Down
6 changes: 3 additions & 3 deletions src/ffpuppet/process_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pathlib import Path
from platform import system
from time import perf_counter, sleep
from typing import TYPE_CHECKING, Callable, Generator, Iterable, List, Tuple, cast
from typing import TYPE_CHECKING, Callable, cast

try:
from signal import SIGUSR1, Signals
Expand All @@ -24,6 +24,7 @@
from .exceptions import TerminateError

if TYPE_CHECKING:
from collections.abc import Generator, Iterable
from subprocess import Popen

LOG = getLogger(__name__)
Expand Down Expand Up @@ -64,9 +65,8 @@ def _safe_wait_procs(
while True:
remaining = None if deadline is None else max(deadline - perf_counter(), 0)
with suppress(AccessDenied):
# Python 3.8 is not compatible with __future__.annotations in cast()
return cast(
Tuple[List[Process], List[Process]],
tuple[list[Process], list[Process]],
wait_procs(procs, timeout=remaining, callback=callback),
)
if deadline is not None and deadline <= perf_counter():
Expand Down
17 changes: 11 additions & 6 deletions src/ffpuppet/puppet_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
from shutil import copy2, copyfileobj, copytree, rmtree
from subprocess import STDOUT, CalledProcessError, check_output
from tempfile import NamedTemporaryFile, mkdtemp
from typing import IO, Iterator, KeysView
from typing import IO, TYPE_CHECKING

from .helpers import onerror, warn_open

if TYPE_CHECKING:
from collections.abc import Iterator, KeysView

LOG = getLogger(__name__)

__author__ = "Tyson Smith"
Expand Down Expand Up @@ -278,11 +281,13 @@ def save_logs(
# check logs for rr related issues
# OSError: in case the file does not exist
# ValueError: cannot mmap an empty file on Windows
with suppress(OSError, ValueError):
with (dest / "log_stderr.txt").open("rb") as lfp:
with mmap(lfp.fileno(), 0, access=ACCESS_READ) as lmm:
if lmm.find(b"=== Start rr backtrace:") != -1:
LOG.warning("rr traceback detected in stderr log")
with (
suppress(OSError, ValueError),
(dest / "log_stderr.txt").open("rb") as lfp,
mmap(lfp.fileno(), 0, access=ACCESS_READ) as lmm,
):
if lmm.find(b"=== Start rr backtrace:") != -1:
LOG.warning("rr traceback detected in stderr log")
if rr_pack and not self._rr_packed:
LOG.debug("packing rr trace")
try:
Expand Down
5 changes: 4 additions & 1 deletion src/ffpuppet/sanitizer_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from logging import getLogger
from os.path import exists
from re import compile as re_compile
from typing import Iterator
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from collections.abc import Iterator

LOG = getLogger(__name__)

Expand Down
13 changes: 7 additions & 6 deletions src/ffpuppet/test_bootstrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,11 @@ def test_bootstrapper_05(mocker):
fake_conn.recv.return_value = "foo"
fake_sock.accept.return_value = (fake_conn, None)
mocker.patch("ffpuppet.bootstrapper.select", return_value=([fake_sock], None, None))
with Bootstrapper(fake_sock) as bts:
with raises(BrowserTerminatedError, match="Failure during browser startup"):
bts.wait(lambda: False)
with (
Bootstrapper(fake_sock) as bts,
raises(BrowserTerminatedError, match="Failure during browser startup"),
):
bts.wait(lambda: False)
assert fake_conn.close.call_count == 1


Expand Down Expand Up @@ -197,9 +199,8 @@ def test_bootstrapper_08(mocker, bind, attempts, raised):
fake_sock.bind.side_effect = bind
mocker.patch("ffpuppet.bootstrapper.select", return_value=([fake_sock], None, None))
mocker.patch("ffpuppet.bootstrapper.socket", return_value=fake_sock)
with raises(raised):
with Bootstrapper.create(attempts=attempts):
pass
with raises(raised), Bootstrapper.create(attempts=attempts):
pass
assert fake_sock.bind.call_count == attempts
assert fake_sock.close.call_count == attempts

Expand Down
24 changes: 12 additions & 12 deletions src/ffpuppet/test_ffpuppet.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@ def _srv_thread(httpd):
@mark.skipif(system() == "Windows", reason="Unsupported on Windows")
def test_ffpuppet_00(tmp_path):
"""test that invalid executables raise the right exception"""
with FFPuppet() as ffp:
with raises(OSError, match="is not an executable"):
ffp.launch(tmp_path)
with FFPuppet() as ffp, raises(OSError, match="is not an executable"):
ffp.launch(tmp_path)


def test_ffpuppet_01():
Expand Down Expand Up @@ -415,21 +414,22 @@ def test_ffpuppet_15(mocker, tmp_path, debugger, dbg_bin, version):

def test_ffpuppet_16(tmp_path):
"""test calling save_logs() before close()"""
with FFPuppet() as ffp:
with HTTPTestServer() as srv:
ffp.launch(TESTFF_BIN, location=srv.get_addr())
with raises(AssertionError):
ffp.save_logs(tmp_path / "logs")
with FFPuppet() as ffp, HTTPTestServer() as srv:
ffp.launch(TESTFF_BIN, location=srv.get_addr())
with raises(AssertionError):
ffp.save_logs(tmp_path / "logs")


def test_ffpuppet_17(tmp_path):
"""test detecting invalid prefs file"""
prefs = tmp_path / "prefs.js"
prefs.write_bytes(b"//fftest_invalid_js\n")
with FFPuppet() as ffp:
with HTTPTestServer() as srv:
with raises(LaunchError, match="'.+?' is invalid"):
ffp.launch(TESTFF_BIN, location=srv.get_addr(), prefs_js=prefs)
with (
FFPuppet() as ffp,
HTTPTestServer() as srv,
raises(LaunchError, match="'.+?' is invalid"),
):
ffp.launch(TESTFF_BIN, location=srv.get_addr(), prefs_js=prefs)


def test_ffpuppet_18():
Expand Down
8 changes: 5 additions & 3 deletions src/ffpuppet/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ def test_profile_06(mocker, tmp_path):
mocker.patch("ffpuppet.profile.rmtree", autospec=True, side_effect=OSError("test"))
with Profile(working_path=str(tmp_path)) as profile:
profile.remove(ignore_errors=True)
with Profile(working_path=str(tmp_path)) as profile:
with raises(OSError, match="test"):
profile.remove(ignore_errors=False)
with (
Profile(working_path=str(tmp_path)) as profile,
raises(OSError, match="test"),
):
profile.remove(ignore_errors=False)


def test_profile_07(mocker, tmp_path):
Expand Down
12 changes: 7 additions & 5 deletions src/ffpuppet/test_puppet_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,13 @@ def test_puppet_logger_07(mocker, tmp_path):

def test_puppet_logger_08(tmp_path):
"""test PuppetLogger.add_log() with file not on disk"""
with PuppetLogger(base_path=str(tmp_path)) as plog:
with SpooledTemporaryFile(max_size=2048) as log_fp:
plog.add_log("test", logfp=log_fp)
with raises(OSError, match="log file None does not exist"):
plog.get_fp("test")
with (
PuppetLogger(base_path=str(tmp_path)) as plog,
SpooledTemporaryFile(max_size=2048) as log_fp,
):
plog.add_log("test", logfp=log_fp)
with raises(OSError, match="log file None does not exist"):
plog.get_fp("test")


def test_puppet_logger_09(mocker, tmp_path):
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py{38,39,310,311,312},lint
envlist = py{39,310,311,312},lint
skip_missing_interpreters = true
tox_pip_extensions_ext_venv_update = true

Expand Down

0 comments on commit 0e7b79d

Please sign in to comment.