Initial style formatting
This commit is contained in:
parent
be91215cc4
commit
c12660ba06
@ -1,4 +1,4 @@
|
||||
# Copyright 2022 dogeystamp <dogeystamp@disroot.org>
|
||||
# See LICENSE file for more details.
|
||||
|
||||
from .bitmask import Bitmask
|
||||
from .bitmask import Bitmask # noqa: F401
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user