Skip to content

Commit

Permalink
chore: implement the black formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
clintval committed Oct 17, 2023
1 parent 28e9c85 commit 37c7058
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 24 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![MyPy Checked](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

A caseless typed dictionary in Python.
A typed dictionary in Python with case-insensitive keys.

```console
pip install caseless
Expand Down
18 changes: 7 additions & 11 deletions caseless/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@
class CaselessDict(Mapping[K, V]):
"""A dictionary with case-insensitive string getters."""

def __init__(
self, *args: Union[Mapping[K, V], Collection[Tuple[K, V]]], **kwargs: Mapping[K, V]
) -> None:
def __init__(self, *args: Union[Mapping[K, V], Collection[Tuple[K, V]]], **kwargs: Mapping[K, V]) -> None:
self._map: Dict[K, V] = dict(*args, **kwargs)
self._caseless: Dict[str, str] = {
k.lower(): k for k, v in self._map.items() if isinstance(k, str)
}
self._caseless: Dict[str, str] = {k.lower(): k for k, v in self._map.items() if isinstance(k, str)}
self._hash: int = -1

def __contains__(self, key: object) -> bool:
Expand All @@ -46,10 +42,10 @@ def __copy__(self) -> "CaselessDict":

def __eq__(self, other: Any) -> bool:
"""Test if <other> is equal to this class instance."""
return (
isinstance(other, type(self))
and hasattr(other, "__hash__")) and (hash(self) == hash(other)
and hasattr(other, "__len__") and len(self) == len(other)
return (isinstance(other, type(self)) and hasattr(other, "__hash__")) and (
hash(self) == hash(other)
and hasattr(other, "__len__")
and len(self) == len(other)
and all([key in other and other[key] == value for key, value in self.items()])
)

Expand All @@ -64,7 +60,7 @@ def __hash__(self) -> int:
"""Return a hash of this dictionary using all key-value pairs."""
if self._hash == -1 and self:
current: int = 0
for (key, value) in self.items():
for key, value in self.items():
if isinstance(key, str):
current ^= hash((key.lower(), value))
else:
Expand Down
111 changes: 110 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 27 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
[tool.poetry]
name = "caseless"
version = "0.4.0"
description = "A caseless typed dictionary in Python"
authors = ["Clint Valentine <valentine.clint@gmail.com>"]
version = "0.5.0"
description = "A typed dictionary in Python with case-insensitive keys"
license = "MIT"
authors = ["Clint Valentine <valentine.clint@gmail.com>"]
readme = "README.md"
homepage = "https://github.com/clintval/caseless"
repository = "https://github.com/clintval/caseless"
documentation = "https://github.com/clintval/caseless"
keywords = ["caseless", "case-insensitive", "dictionary", "python"]
classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.group.dev.dependencies]
black = "23.10.0"
pytest = "^7.4.2"
pytest-black-ng = "^0.4.1"
pytest-mypy = "^0.10.3"
pytest-ruff = "^0.1.1"

[tool.poetry.urls]
"Bug Tracker" = "https://github.com/clintval/caseless/issues"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.black]
line-length = 120
target-version = ["py38"]

[tool.tox]
legacy_tox_ini = """
[tox]
Expand All @@ -41,7 +64,7 @@ commands =

[tool.pytest.ini_options]
minversion = "6.0"
addopts = ["--mypy", "--ruff"]
addopts = ["--black", "--mypy", "--ruff"]
testpaths = ["caseless", "tests"]

[tool.ruff]
Expand Down
12 changes: 5 additions & 7 deletions tests/test_caselessdict.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

T = TypeVar("T")


def round_trip_pickle(obj: T) -> T:
temp = NamedTemporaryFile("w", delete=False)
with open(temp.name, "wb") as handle:
Expand All @@ -21,6 +22,7 @@ def round_trip_pickle(obj: T) -> T:
os.remove(temp.name)
return rehydrated


class TestCaselessDict(object):
def test_isinstance(self):
assert isinstance(CaselessDict(), Mapping)
Expand Down Expand Up @@ -97,7 +99,7 @@ def test__hash__(self):
def test__iter__(self):
keyvalues = [(1, 2), (3, 4)]
mapping = CaselessDict(keyvalues)
for (actual_key, expected_key) in zip(mapping, dict(keyvalues).keys()):
for actual_key, expected_key in zip(mapping, dict(keyvalues).keys()):
assert actual_key == expected_key

def test__len__(self):
Expand Down Expand Up @@ -129,9 +131,7 @@ def test__str__(self):

def test_fromkeys(self):
assert CaselessDict.fromkeys([1, 2, 3], default=3) == CaselessDict({1: 3, 2: 3, 3: 3})
assert CaselessDict.fromkeys([1, 2, 3], default=None) == CaselessDict(
{1: None, 2: None, 3: None}
)
assert CaselessDict.fromkeys([1, 2, 3], default=None) == CaselessDict({1: None, 2: None, 3: None})

def test_copy(self):
mapping = CaselessDict({2: 3, 4: 5, "lower": "UPPER"})
Expand Down Expand Up @@ -163,9 +163,7 @@ def test_updated(self):
mapping = CaselessDict({2: 3, 4: 5, "lower": "UPPER"})
assert mapping.updated(4, 10) == CaselessDict({2: 3, 4: 10, "lower": "UPPER"})
assert mapping.updated(6, 7) == CaselessDict({2: 3, 4: 5, 6: 7, "lower": "UPPER"})
assert mapping.updated("LOWER", "UPDATED") == CaselessDict(
{2: 3, 4: 5, "lower": "UPDATED"}
)
assert mapping.updated("LOWER", "UPDATED") == CaselessDict({2: 3, 4: 5, "lower": "UPDATED"})

def test_values(self):
keyvalues = [(1, 2), (3, 4)]
Expand Down

0 comments on commit 37c7058

Please sign in to comment.