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

upgrade to pytest 8 #1054

Merged
merged 1 commit into from
Nov 22, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/+upgraded_to_pytest_8.infrastructure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Upgraded to pytest 8.
157 changes: 106 additions & 51 deletions pdm.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ format = [
lint = [
"yapf==0.27",
"ruff==0.0.272",
"pytest==6.2.5",
"pytest==8.3.3",
"liccheck>=0.9.2",
"setuptools>=60", # required by liccheck
]
Expand All @@ -201,9 +201,9 @@ release = [
test = [
"coverage==7.2.7",
"pexpect==4.8.0",
"pytest==6.2.5",
"pytest==8.3.3",
"pytest-cov==3.0.0",
"pytest-forked==1.4.0",
"pytest-forked==1.6.0",
"pytest-xdist==2.5.0",
"backoff==2.1.2",
"more-itertools==8.13.0",
Expand Down
64 changes: 2 additions & 62 deletions test/unit/_cli/test_autocomplete_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@
from __future__ import annotations

import contextlib
import importlib
import io
import os
import pickle
import sys
from typing import Any

import argcomplete
import pytest
Expand All @@ -30,6 +27,8 @@
import b2._internal.console_tool
from b2._internal._cli import autocomplete_cache

from .unpickle import unpickle

# We can't use pytest.mark.skipif to skip forked tests because with pytest-forked,
# there is an attempt to fork even if the test is marked as skipped.
# See https://github.com/pytest-dev/pytest-forked/issues/44
Expand Down Expand Up @@ -241,65 +240,6 @@ def test_complete_with_file_uri_suggestions(
assert output == argcomplete_output


def test_pickle_store(tmp_path):
dir = tmp_path
store = autocomplete_cache.HomeCachePickleStore(dir)

store.set_pickle('test_1', b'test_data_1')
assert store.get_pickle('test_1') == b'test_data_1'
assert store.get_pickle('test_2') is None
assert len(list(dir.rglob('*.pickle'))) == 1

store.set_pickle('test_2', b'test_data_2')
assert store.get_pickle('test_2') == b'test_data_2'
assert store.get_pickle('test_1') is None
assert len(list(dir.rglob('*.pickle'))) == 1


class Unpickler(pickle.Unpickler):
"""This Unpickler will raise an exception if loading the pickled object
imports any b2sdk module."""

_modules_to_load: set[str]

def load(self):
self._modules_to_load = set()

b2_modules = [module for module in sys.modules if 'b2sdk' in module]
for key in b2_modules:
del sys.modules[key]

result = super().load()

for module in self._modules_to_load:
importlib.import_module(module)
importlib.reload(sys.modules[module])

if any('b2sdk' in module for module in sys.modules):
raise RuntimeError("Loading the pickled object imported b2sdk module")
return result

def find_class(self, module: str, name: str) -> Any:
self._modules_to_load.add(module)
return super().find_class(module, name)


def unpickle(data: bytes) -> Any:
"""Unpickling function that raises RuntimeError if unpickled
object depends on b2sdk."""
return Unpickler(io.BytesIO(data)).load()


def test_unpickle():
"""This tests ensures that Unpickler works as expected:
prevents successful unpickling of objects that depend on loading
modules from b2sdk."""
from .fixtures.module_loading_b2sdk import function
pickled = pickle.dumps(function)
with pytest.raises(RuntimeError):
unpickle(pickled)


@forked
def test_that_autocomplete_cache_loading_does_not_load_b2sdk(autocomplete_runner, tmp_path):
cache = autocomplete_cache.AutocompleteCache(
Expand Down
41 changes: 41 additions & 0 deletions test/unit/_cli/test_pickle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
######################################################################
#
# File: test/unit/_cli/test_pickle.py
#
# Copyright 2023 Backblaze Inc. All Rights Reserved.
#
# License https://www.backblaze.com/using_b2_code.html
#
######################################################################
import pickle

import pytest

from b2._internal._cli import autocomplete_cache

from .unpickle import unpickle


def test_pickle_store(tmp_path):
dir = tmp_path
store = autocomplete_cache.HomeCachePickleStore(dir)

store.set_pickle('test_1', b'test_data_1')
assert store.get_pickle('test_1') == b'test_data_1'
assert store.get_pickle('test_2') is None
assert len(list(dir.rglob('*.pickle'))) == 1

store.set_pickle('test_2', b'test_data_2')
assert store.get_pickle('test_2') == b'test_data_2'
assert store.get_pickle('test_1') is None
assert len(list(dir.rglob('*.pickle'))) == 1


def test_unpickle():
"""This tests ensures that Unpickler works as expected:
prevents successful unpickling of objects that depend on loading
modules from b2sdk."""
from .fixtures.module_loading_b2sdk import function
pickled = pickle.dumps(function)
with pytest.raises(RuntimeError):
unpickle(pickled)
48 changes: 48 additions & 0 deletions test/unit/_cli/unpickle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
######################################################################
#
# File: test/unit/_cli/unpickle.py
#
# Copyright 2023 Backblaze Inc. All Rights Reserved.
#
# License https://www.backblaze.com/using_b2_code.html
#
######################################################################
import importlib
import io
import pickle
import sys
from typing import Any, Set


class Unpickler(pickle.Unpickler):
"""This Unpickler will raise an exception if loading the pickled object
imports any b2sdk module."""

_modules_to_load: Set[str]

def load(self):
self._modules_to_load = set()

b2_modules = [module for module in sys.modules if 'b2sdk' in module]
for key in b2_modules:
del sys.modules[key]

result = super().load()

for module in self._modules_to_load:
importlib.import_module(module)
importlib.reload(sys.modules[module])

if any('b2sdk' in module for module in sys.modules):
raise RuntimeError("Loading the pickled object imported b2sdk module")
return result

def find_class(self, module: str, name: str) -> Any:
self._modules_to_load.add(module)
return super().find_class(module, name)


def unpickle(data: bytes) -> Any:
"""Unpickling function that raises RuntimeError if unpickled
object depends on b2sdk."""
return Unpickler(io.BytesIO(data)).load()