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

Coverage #101

Merged
merged 11 commits into from
Jun 6, 2024
12 changes: 9 additions & 3 deletions .github/workflows/build_primary_wheels.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Build primary wheels

on: [push, pull_request]
on:
push:
branches:
- main
pull_request:
paths:
- '**'

jobs:
build_wheels:
Expand Down Expand Up @@ -51,7 +57,7 @@ jobs:
python-version: "${{ matrix.version }}"

- name: Install dependencies
run: pip install -U pip setuptools wheel pytest
run: pip install -U pip setuptools wheel pytest pytest-cov

- name: Build module
run: FROZENDICT_PURE_PY=1 python setup.py bdist_wheel
Expand All @@ -63,7 +69,7 @@ jobs:
run: pip install dist/*

- name: Test with pytest
run: pytest
run: pytest --cov=frozendict --cov-report=term-missing --cov-branch --cov-fail-under=100

- uses: actions/upload-artifact@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_secondary_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- os: windows-latest
cibw_archs: "ARM64"
- os: macos-latest
cibw_archs: "native arm64"
cibw_archs: "native x86_64"

steps:
- name: Set up QEMU
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ test/core.*
.eggs/
.idea/
.vs/
.coverage
2 changes: 2 additions & 0 deletions build_py.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rm -rf build dist *.egg-info
FROZENDICT_PURE_PY=1 ./setup.py $*
16 changes: 9 additions & 7 deletions src/frozendict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Provides frozendict, a simple immutable dictionary.
"""

try:
try: # pragma: no cover
from ._frozendict import *
c_ext = True
# noinspection PyUnresolvedReferences
Expand All @@ -14,21 +14,25 @@
from .version import version as __version__
from . import monkeypatch
from .cool import *
from . import cool


def _getFrozendictJsonEncoder(BaseJsonEncoder = None):
if BaseJsonEncoder is None:
if BaseJsonEncoder is None: # pragma: no cover
from json.encoder import JSONEncoder

BaseJsonEncoder = JSONEncoder

class FrozendictJsonEncoderInternal(BaseJsonEncoder):
def default(self, obj):
if isinstance(obj, frozendict):
if isinstance(obj, frozendict): # pragma: no cover
# TODO create a C serializer
return dict(obj)

return BaseJsonEncoder.default(self, obj)
return BaseJsonEncoder.default(
self,
obj
) # pragma: no cover

return FrozendictJsonEncoderInternal

Expand All @@ -44,7 +48,7 @@ def default(self, obj):
del Mapping


if c_ext:
if c_ext: # pragma: no cover
__all__ = (frozendict.__name__, )
else:
__all__ = _frozendict_py.__all__
Expand All @@ -55,5 +59,3 @@ def default(self, obj):

__all__ += cool.__all__
__all__ += (FrozendictJsonEncoder.__name__, "FrozenOrderedDict")

del cool
2 changes: 1 addition & 1 deletion src/frozendict/_frozendict_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def frozendict_or(self, other, *_args, **_kwargs):
try:
# noinspection PyStatementEffect
frozendict.__reversed__
except AttributeError:
except AttributeError: # pragma: no cover
def frozendict_reversed(self, *_args, **_kwargs):
return reversed(tuple(self))

Expand Down
5 changes: 3 additions & 2 deletions src/frozendict/cool.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

# fix for python 3.9-

if not issubclass(array, MutableSequence):
# coverage does not work here!
if not issubclass(array, MutableSequence): # pragma: no cover
# noinspection PyUnresolvedReferences
MutableSequence.register(array)

Expand Down Expand Up @@ -301,7 +302,7 @@ def deepfreeze(
except KeyError:
if frozen_type:
freeze = type_o
else:
else: # pragma: no cover
raise

return freeze(o_copy)
Expand Down
16 changes: 10 additions & 6 deletions src/frozendict/monkeypatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def checkCExtension(*, warn, warn_c = False):
res = cool.c_ext

if warn and res == warn_c:
if warn_c:
if warn_c: # pragma: no cover
msg = "C Extension version, monkeypatch will be not applied"
else:
msg = "Pure Python version, monkeypatch will be not applied"
Expand All @@ -25,7 +25,7 @@ def checkCExtension(*, warn, warn_c = False):
return res


def patchOrUnpatchJson(*, patch, warn = True):
def patchOrUnpatchJson(*, patch, warn = True): # pragma: no cover
if not checkCExtension(warn = warn):
return

Expand Down Expand Up @@ -78,7 +78,7 @@ def patchOrUnpatchJson(*, patch, warn = True):
json._default_encoder = default_json_encoder


def patchOrUnpatchOrjson(*, patch, warn = True):
def patchOrUnpatchOrjson(*, patch, warn = True): # pragma: no cover
if not checkCExtension(warn = warn):
return

Expand Down Expand Up @@ -118,7 +118,11 @@ def frozendictOrjsonDumps(obj, *args, **kwargs):
orjson.orjson.dumps = defaultOrjsonDumps


def patchOrUnpatchMutableMappingSubclasshook(*, patch, warn = True):
def patchOrUnpatchMutableMappingSubclasshook(
*,
patch,
warn = True
): # pragma: no cover
warn_c = True

if checkCExtension(warn = warn, warn_c = warn_c):
Expand Down Expand Up @@ -185,10 +189,10 @@ def patchOrUnpatchAll(*, patch, warn = True, raise_orjson = False):

try:
import orjson
except ImportError:
except ImportError: # pragma: no cover
if raise_orjson:
raise
else:
else: # pragma: no cover
patchOrUnpatchOrjson(patch = patch, warn = warn)

patchOrUnpatchMutableMappingSubclasshook(patch = patch, warn = warn)
Expand Down
46 changes: 44 additions & 2 deletions test/test_freeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import frozendict as cool
from frozendict import frozendict
from collections import OrderedDict
from collections.abc import MutableSequence, Sequence
from collections.abc import MutableSequence, Sequence, Iterable
from array import array
from types import MappingProxyType
from frozendict import FreezeError, FreezeWarning
Expand All @@ -14,6 +14,18 @@ def __init__(self, x):
self.x = x


class NoDictAndHash:
__slots__ = (
"x",
)

def __init__(self, x):
self.x = x

def __hash__(self):
raise TypeError()


class BaseSeq(Sequence):

def __init__(self, seq):
Expand Down Expand Up @@ -64,13 +76,25 @@ def after_cure_inverse():
return (frozendict(a=frozendict({1: 2}), y="mbuti"), )


@pytest.fixture
def no_cure_inverse():
return (frozendict(a=frozendict({1: 2})), )


@pytest.fixture
def a():
a = A(3)

return a


@pytest.fixture
def no_dict_and_hash():
res = NoDictAndHash(3)

return res


@pytest.fixture
def before_cure(a):
return {"x": [
Expand Down Expand Up @@ -170,7 +194,11 @@ def test_deepfreeze_inverse(before_cure_inverse, after_cure_inverse):
) == after_cure_inverse


def test_register_inverse(before_cure_inverse, after_cure_inverse):
def test_register_inverse(
before_cure_inverse,
after_cure_inverse,
no_cure_inverse,
):
with pytest.warns(FreezeWarning):
cool.register(
frozendict,
Expand All @@ -179,6 +207,10 @@ def test_register_inverse(before_cure_inverse, after_cure_inverse):
)

assert cool.deepfreeze(before_cure_inverse) == after_cure_inverse

cool.unregister(frozendict, inverse=True)

assert cool.deepfreeze(before_cure_inverse) == no_cure_inverse


def test_prefer_forward():
Expand All @@ -205,3 +237,13 @@ def test_original_immutate():

def test_enum(my_enum):
assert cool.deepfreeze(my_enum) is my_enum


def test_get_items():
with pytest.raises(TypeError):
cool.cool.getItems(5)


def test_no_dict_and_hash(no_dict_and_hash):
with pytest.raises(TypeError):
cool.deepfreeze(no_dict_and_hash)
48 changes: 48 additions & 0 deletions test/test_monkeypatch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import json

import frozendict as cool
import pytest
from frozendict import frozendict
from frozendict.monkeypatch import MonkeypatchWarning


class A:
pass


@pytest.fixture
def object_to_serialize():
return frozendict()


@pytest.fixture
def object_to_serialize_2():
return A()


@pytest.fixture
def serialized_object():
return "{}"


def test_get_json_encoder(
object_to_serialize,
object_to_serialize_2,
serialized_object,
):
if cool.c_ext:
cool.monkeypatch.patchOrUnpatchJson(patch=True)
else:
with pytest.warns(MonkeypatchWarning):
cool.monkeypatch.patchOrUnpatchJson(patch=True, warn=True)

assert json.dumps(object_to_serialize) == serialized_object

with pytest.raises(TypeError):
json.dumps(object_to_serialize_2)

cool.monkeypatch.patchOrUnpatchJson(patch=False, warn=False)

if cool.c_ext:
with pytest.raises(TypeError):
json.dumps(object_to_serialize)
Loading