From c12660ba066e6fcc5fc84f026cbf10d589861921 Mon Sep 17 00:00:00 2001 From: dogeystamp Date: Tue, 2 Aug 2022 18:11:51 -0400 Subject: [PATCH] Initial style formatting --- bitmask/__init__.py | 2 +- bitmask/bitmask.py | 48 +++++++++++--------- bitmask/util.py | 6 ++- tests/test_bitmask.py | 100 +++++++++++++++++++++++++++++++----------- 4 files changed, 106 insertions(+), 50 deletions(-) diff --git a/bitmask/__init__.py b/bitmask/__init__.py index 318c42c..bb2f689 100644 --- a/bitmask/__init__.py +++ b/bitmask/__init__.py @@ -1,4 +1,4 @@ # Copyright 2022 dogeystamp # See LICENSE file for more details. -from .bitmask import Bitmask +from .bitmask import Bitmask # noqa: F401 diff --git a/bitmask/bitmask.py b/bitmask/bitmask.py index dcf34bc..f2cfdd9 100644 --- a/bitmask/bitmask.py +++ b/bitmask/bitmask.py @@ -5,6 +5,7 @@ from bitmask.util import type_name, fullname + class Bitmask: """Generic bitmask, which represents multiple Enum values. @@ -14,7 +15,7 @@ class Bitmask: Examples: Initialise bitmask:: - + from bitmask import Bitmask from enum import IntFlag @@ -39,7 +40,7 @@ class Bitmask: bmask.add(Desc.ROUND) Remove flag from bitmask:: - + bmask.discard(Desc.ROUND) """ @@ -65,21 +66,23 @@ class Bitmask: @value.setter def value(self, value): if not issubclass(type(value), int): - raise TypeError(f"value must be an integer") + raise TypeError("value must be an integer") self._value = value - + def __contains__(self, item): """Determine if a mask is enabled.""" if issubclass(type(item), type(self)): for flag in item: - if not flag in self: + if flag not in self: return False else: return True elif issubclass(type(item), self.AllFlags): return bool(self.value & item) else: - raise TypeError(f"item must be {type_name(self)} or {type_name(self.AllFlags)}") + raise TypeError( + f"item must be {type_name(self)} or {type_name(self.AllFlags)}" + ) def __iter__(self): """Return list of enabled flags.""" @@ -94,14 +97,11 @@ class Bitmask: return int(self) def __str__(self): - return '|'.join([flag.name for flag in self]) or "0" + return "|".join([flag.name for flag in self]) or "0" def __repr__(self): enum_name = fullname(self.AllFlags(0)) - args = ', '.join( - [enum_name] + - [f"{enum_name}.{flag.name}" for flag in self] - ) + args = ", ".join([enum_name] + [f"{enum_name}.{flag.name}" for flag in self]) return f"{fullname(self)}({args})" @@ -123,7 +123,9 @@ class Bitmask: bitmask, given the initial value and the flag. """ if not issubclass(type(flag), self.AllFlags): - raise TypeError(f"can only apply {type_name(self.AllFlags)} to {type_name(self)}") + raise TypeError( + f"can only apply {type_name(self.AllFlags)} to {type_name(self)}" + ) self.value = op(self.value, flag) def __mask_op(self, other, op): @@ -142,17 +144,19 @@ class Bitmask: elif issubclass(type(other), self.AllFlags): new_bitmask._flag_op(other, op) else: - raise TypeError(f"can only apply {type_name(self)} or {type_name(self.AllFlags)} to {type_name(self)}") + raise TypeError( + f"can only apply {type_name(self)} or {type_name(self.AllFlags)} to {type_name(self)}" + ) return new_bitmask def add(self, other): """Add single flag to the bitmask.""" - self._flag_op(other, lambda a, b : a | b) + self._flag_op(other, lambda a, b: a | b) def __add__(self, other): """Implement + operator.""" - return self.__mask_op(other, lambda a, b : a | b) + return self.__mask_op(other, lambda a, b: a | b) def __radd__(self, other): """Alias the + operator in reverse.""" @@ -168,7 +172,7 @@ class Bitmask: def __xor__(self, other): """Implement ^ operator.""" - return self.__mask_op(other, lambda a, b : a ^ b) + return self.__mask_op(other, lambda a, b: a ^ b) def __rxor__(self, other): """Alias the ^ operator in reverse.""" @@ -176,7 +180,7 @@ class Bitmask: def __and__(self, other): """AND bitmasks/flags together.""" - return self.__mask_op(other, lambda a, b : a & b) + return self.__mask_op(other, lambda a, b: a & b) def __rand__(self, other): """Alias the & operator in reverse.""" @@ -184,7 +188,7 @@ class Bitmask: def __sub__(self, other): """Subtract by bitmask/flag.""" - return self.__mask_op(other, lambda a, b : a & ~b) + return self.__mask_op(other, lambda a, b: a & ~b) def discard(self, flag): """Remove flag bitmask if present. @@ -195,9 +199,11 @@ class Bitmask: TypeError: `flag` is not a single Enum value. """ if not issubclass(type(flag), self._AllFlags): - raise TypeError(f"can only discard {type_name(self._AllFlags)} from {type_name(self)}") + raise TypeError( + f"can only discard {type_name(self._AllFlags)} from {type_name(self)}" + ) - return self._flag_op(flag, lambda a, b : a & ~b) + return self._flag_op(flag, lambda a, b: a & ~b) def remove(self, flag): """Remove `flag` from the bitmask. @@ -207,7 +213,7 @@ class Bitmask: Raises: KeyError: flag is not in bitmask. """ - if not flag in self: + if flag not in self: raise KeyError(type(flag), self.AllFlags) self.discard(flag) diff --git a/bitmask/util.py b/bitmask/util.py index 6c4cf30..2e6e5dc 100644 --- a/bitmask/util.py +++ b/bitmask/util.py @@ -5,6 +5,7 @@ import enum + def fullname(obj): """Get the full class name of an object, including module. @@ -13,14 +14,15 @@ def fullname(obj): """ return f"{obj.__class__.__qualname__}" + def type_name(obj): """Get the short type of an object. Returns: String with human-readable type of the object. - + Example: - + import bitmask.util as util util.type_name(1) >>> int diff --git a/tests/test_bitmask.py b/tests/test_bitmask.py index b1ea889..305f927 100644 --- a/tests/test_bitmask.py +++ b/tests/test_bitmask.py @@ -5,24 +5,31 @@ from bitmask import Bitmask from enum import IntFlag import pytest + class Desc(IntFlag): SMALL = 1 ROUND = 1 << 1 FUNKY = 1 << 2 SONAR = 1 << 4 + class Colors(IntFlag): TEAL = 1 PINK = 1 << 1 BLUE = 1 << 2 + def test_eq(): """Test equality checks.""" # Equality assert Bitmask(Desc) == Bitmask(Desc) assert Bitmask(Desc, Desc.SMALL) == Bitmask(Desc, Desc.SMALL) - assert Bitmask(Desc, Desc.SMALL, Desc.ROUND) == Bitmask(Desc, Desc.SMALL, Desc.ROUND) - assert Bitmask(Desc, Desc.ROUND, Desc.SMALL) == Bitmask(Desc, Desc.SMALL, Desc.ROUND) + assert Bitmask(Desc, Desc.SMALL, Desc.ROUND) == Bitmask( + Desc, Desc.SMALL, Desc.ROUND + ) + assert Bitmask(Desc, Desc.ROUND, Desc.SMALL) == Bitmask( + Desc, Desc.SMALL, Desc.ROUND + ) # Inequality assert Bitmask(Desc, Desc.SMALL) != Bitmask(Desc, Desc.SMALL, Desc.ROUND) @@ -37,6 +44,7 @@ def test_eq(): assert Bitmask(Desc) != 0 assert Bitmask(Desc) != Bitmask(Colors) + def test_repr(): """Ensure evaluating __repr__ creates an identical object.""" mask = Bitmask(Desc, Desc.ROUND, Desc.FUNKY) @@ -45,6 +53,7 @@ def test_repr(): empty_mask = Bitmask(Desc) assert eval(repr(empty_mask)) == empty_mask + def test_add(): """Test Bitmask.add() method.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) @@ -57,11 +66,12 @@ def test_add(): mask.add(Desc.ROUND) assert mask == Bitmask(Desc, Desc.ROUND) - with pytest.raises(TypeError, match="can only apply Desc to Bitmask"): + with pytest.raises(TypeError, match=".* Desc .* Bitmask.*"): mask.add(1) - with pytest.raises(TypeError, match="can only apply Bitmask or Desc to Bitmask"): + with pytest.raises(TypeError, match=r".* Bitmask .* Desc .* Bitmask.*"): mask += 1 + def test_add_operator(): """Test + operator.""" # Individual flags @@ -72,12 +82,15 @@ def test_add_operator(): assert Bitmask(Desc) + Desc.ROUND == Bitmask(Desc, Desc.ROUND) # Union of bitmasks - assert Bitmask(Desc, Desc.SMALL) + Bitmask(Desc, Desc.FUNKY, Desc.ROUND) \ - == Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) - assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) + Bitmask(Desc, Desc.SMALL) \ - == Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) + assert Bitmask(Desc, Desc.SMALL) + Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask( + Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND + ) + assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) + Bitmask(Desc, Desc.SMALL) == Bitmask( + Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND + ) assert Bitmask(Desc) + Bitmask(Desc) == Bitmask(Desc) + def test_add_inline(): """Test += operator.""" # Individual flags @@ -92,6 +105,7 @@ def test_add_inline(): mask += Bitmask(Desc, Desc.ROUND, Desc.FUNKY) assert mask == Bitmask(Desc, Desc.FUNKY, Desc.ROUND) + def test_or_operator(): """Test | operator.""" # Individual flags @@ -102,10 +116,15 @@ def test_or_operator(): assert Bitmask(Desc) | Desc.ROUND == Bitmask(Desc, Desc.ROUND) # Union of bitmasks - assert Bitmask(Desc, Desc.SMALL) | Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) - assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) | Bitmask(Desc, Desc.SMALL) == Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) + assert Bitmask(Desc, Desc.SMALL) | Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask( + Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND + ) + assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) | Bitmask(Desc, Desc.SMALL) == Bitmask( + Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND + ) assert Bitmask(Desc) | Bitmask(Desc) == Bitmask(Desc) + def test_or_inline(): """Test |= operator.""" # Individual flags @@ -120,6 +139,7 @@ def test_or_inline(): mask |= Bitmask(Desc, Desc.ROUND, Desc.FUNKY) assert mask == Bitmask(Desc, Desc.FUNKY, Desc.ROUND) + def test_and_operator(): """Test & operator.""" # Individual flags @@ -130,10 +150,15 @@ def test_and_operator(): assert Bitmask(Desc) & Desc.ROUND == Bitmask(Desc) # AND of bitmasks - assert Bitmask(Desc, Desc.FUNKY, Desc.SONAR) & Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask(Desc, Desc.FUNKY) - assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) & Bitmask(Desc, Desc.SMALL) == Bitmask(Desc) + assert Bitmask(Desc, Desc.FUNKY, Desc.SONAR) & Bitmask( + Desc, Desc.FUNKY, Desc.ROUND + ) == Bitmask(Desc, Desc.FUNKY) + assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) & Bitmask(Desc, Desc.SMALL) == Bitmask( + Desc + ) assert Bitmask(Desc) & Bitmask(Desc) == Bitmask(Desc) + def test_and_inline(): """Test &= operator.""" # Individual flags @@ -147,7 +172,8 @@ def test_and_inline(): mask = Bitmask(Desc, Desc.ROUND, Desc.FUNKY) mask &= Bitmask(Desc, Desc.SMALL) assert mask == Bitmask(Desc) - + + def test_remove(): """Test the `Bitmask.remove()` method.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) @@ -160,6 +186,7 @@ def test_remove(): with pytest.raises(KeyError): empty_mask.remove(Desc.SMALL) + def test_discard(): """Test the `Bitmask.discard()` method.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) @@ -174,17 +201,25 @@ def test_discard(): with pytest.raises(TypeError, match="can only discard Desc from Bitmask"): empty_mask.discard(Bitmask(Desc, Desc.SMALL)) + def test_subtract(): """Test - operator.""" # Individual flag - assert Bitmask(Desc, Desc.SMALL, Desc.FUNKY) - Desc.SMALL == Bitmask(Desc, Desc.FUNKY) - assert Bitmask(Desc, Desc.FUNKY, Desc.SMALL) - Desc.SMALL == Bitmask(Desc, Desc.FUNKY) + assert Bitmask(Desc, Desc.SMALL, Desc.FUNKY) - Desc.SMALL == Bitmask( + Desc, Desc.FUNKY + ) + assert Bitmask(Desc, Desc.FUNKY, Desc.SMALL) - Desc.SMALL == Bitmask( + Desc, Desc.FUNKY + ) # Two bitmasks - assert Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) \ - - Bitmask(Desc, Desc.SMALL, Desc.ROUND) == Bitmask(Desc, Desc.FUNKY) - assert Bitmask(Desc, Desc.FUNKY, Desc.SMALL) \ - - Bitmask(Desc, Desc.SMALL, Desc.FUNKY) == Bitmask(Desc) + assert Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) - Bitmask( + Desc, Desc.SMALL, Desc.ROUND + ) == Bitmask(Desc, Desc.FUNKY) + assert Bitmask(Desc, Desc.FUNKY, Desc.SMALL) - Bitmask( + Desc, Desc.SMALL, Desc.FUNKY + ) == Bitmask(Desc) + def test_subtract_inline(): """Test -= operator.""" @@ -192,6 +227,7 @@ def test_subtract_inline(): mask -= Desc.SMALL assert mask == Bitmask(Desc, Desc.FUNKY) + def test_xor_operator(): """Test ^ operator.""" # Individual flags @@ -202,11 +238,15 @@ def test_xor_operator(): assert Bitmask(Desc) ^ Desc.ROUND == Bitmask(Desc, Desc.ROUND) # XOR bitmasks - assert Bitmask(Desc, Desc.SMALL) ^ Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) - assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) \ - ^ Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask(Desc) + assert Bitmask(Desc, Desc.SMALL) ^ Bitmask(Desc, Desc.FUNKY, Desc.ROUND) == Bitmask( + Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND + ) + assert Bitmask(Desc, Desc.FUNKY, Desc.ROUND) ^ Bitmask( + Desc, Desc.FUNKY, Desc.ROUND + ) == Bitmask(Desc) assert Bitmask(Desc) ^ Bitmask(Desc) == Bitmask(Desc) + def test_xor_inline(): """Test ^= operator.""" # Individual flags @@ -223,12 +263,13 @@ def test_xor_inline(): mask ^= Bitmask(Desc, Desc.ROUND, Desc.FUNKY) assert mask == Bitmask(Desc, Desc.FUNKY) + def test_value(): """Ensure Bitmask.value lines up with the state.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) assert mask.value == 5 mask.add(Desc.ROUND) - assert mask.value == 7 + assert mask.value == 7 assert Bitmask(Desc).value == 0 @@ -242,6 +283,7 @@ def test_value(): with pytest.raises(TypeError, match="value must be an integer"): mask.value = 2.5 + def test_contains(): """Test `flag in mask` check.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) @@ -259,11 +301,16 @@ def test_contains(): assert Bitmask(Desc, Desc.SMALL, Desc.FUNKY, Desc.ROUND) not in mask assert Bitmask(Desc, Desc.FUNKY) in mask with pytest.raises(TypeError, match="item must be Bitmask or Desc"): - x = 1 in mask + assert 1 in mask + def test_iter(): """Test iteration.""" - assert [i for i in Bitmask(Desc, Desc.SMALL, Desc.FUNKY)] == [Desc.SMALL, Desc.FUNKY] + assert [i for i in Bitmask(Desc, Desc.SMALL, Desc.FUNKY)] == [ + Desc.SMALL, + Desc.FUNKY, + ] + def test_str(): """Test string conversion.""" @@ -275,6 +322,7 @@ def test_str(): assert str(Bitmask(Desc, Desc.ROUND)) == "ROUND" assert str(Bitmask(Desc)) == "0" + def test_int(): """Test int conversion.""" mask = Bitmask(Desc, Desc.SMALL, Desc.FUNKY) @@ -282,9 +330,9 @@ def test_int(): mask.value = 4 assert int(mask) == mask.value + def test_hex(): """Test hexadecimal conversion.""" assert hex(Bitmask(Desc, Desc.SMALL)) == "0x1" assert hex(Bitmask(Desc)) == "0x0" assert hex(Bitmask(Desc, Desc.SONAR)) == "0x10" -