Initial style formatting

This commit is contained in:
dogeystamp 2022-08-02 18:11:51 -04:00
parent be91215cc4
commit c12660ba06
Signed by: dogeystamp
GPG Key ID: 7225FE3592EFFA38
4 changed files with 106 additions and 50 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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"