Skip to content

Commit

Permalink
upgrade to pytest 8
Browse files Browse the repository at this point in the history
  • Loading branch information
selfisekai committed Nov 13, 2024
1 parent ee53bba commit 750a90e
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 116 deletions.
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()

0 comments on commit 750a90e

Please sign in to comment.