Coverage for src/gentrie/protocols.py: 100%

1# -*- coding: utf-8 -*-

2"""Protocols and type definitions for the gentrie package."""

3

4 from collections.abc import Sequence

5 from typing import Protocol, TypeAlias, runtime_checkable

6

7

8@runtime_checkable

9 class TrieKeyToken(Protocol):

10 """:class:`TrieKeyToken` is a protocol that defines key tokens that are usable with a :class:`GeneralizedTrie`.

11

12 The protocol requires that a token object be *hashable*. This means that it

13 implements both an ``__eq__()`` method and a ``__hash__()`` method.

14

15 Some examples of built-in types that are suitable for use as tokens in a key:

16

17 * :class:`str`

18 * :class:`bytes`

19 * :class:`int`

20 * :class:`float`

21 * :class:`complex`

22 * :class:`frozenset`

23 * :class:`tuple`

24 * :class:`None`

25

26 Note: frozensets and tuples are only hashable *if their contents are hashable*.

27

28 Usage:

29

30 .. code-block:: python

31 :linenos:

32

33 from gentrie import TrieKeyToken

34

35 token = SomeTokenClass()

36 if isinstance(token, TrieKeyToken):

37 print("supports the TrieKeyToken protocol")

38 else:

39 print("does not support the TrieKeyToken protocol")

40

41 .. warning:: **Using User Defined Classes As Tokens In Keys**

42

43 User-defined classes are hashable by default, but you should implement the

44 ``__eq__()`` and ``__hash__()`` dunder methods in a content-aware way (the hash and eq values

45 must depend on the content of the object) if you want to use them as tokens in a key. The default

46 implementation of ``__eq__()`` and ``__hash__()`` uses the memory address of the object, which

47 means that two different instances of the same class will not be considered equal.

48

49 """

50 def __eq__(self, value: object, /) -> bool: ...

51

52 def __hash__(self) -> int: ...

53

54

55@runtime_checkable

56 class Hashable(TrieKeyToken, Protocol):

57 """The Hashable protocol is deprecated and will be removed in a future version.

58

59 This protocol is a sub-class of :class:`TrieKeyToken` and is only provided for backward compatibility.

60

61 Use :class:`TrieKeyToken` instead.

62 """

63 def __eq__(self, value: object, /) -> bool: ...

64

65 def __hash__(self) -> int: ...

66

67

68 GeneralizedKey: TypeAlias = Sequence[TrieKeyToken]

69"""A :class:`GeneralizedKey` is an object of any class that is a :class:`Sequence` and

70 that when iterated returns tokens conforming to the :class:`TrieKeyToken` protocol.

71

72

73.. warning:: **Keys Must Be Immutable**

74

75 Once a key is added to the trie, neither the key sequence itself nor any of its

76 constituent tokens should be mutated. Modifying a key after it has been added

77 can corrupt the internal state of the trie, leading to unpredictable behavior

78 and making entries unreachable. The trie does not create a deep copy of keys

79 for performance reasons.

80

81 If you need to modify a key, you should remove the old key and add a new one

82 with the modified value.

83

84**Examples of valid :class:`GeneralizedKey` types**

85

86* :class:`str`

87* :class:`bytes`

88* :class:`list[bool]`

89* :class:`list[int]`

90* :class:`list[bytes]`

91* :class:`list[str]`

92* :class:`list[Optional[str]]`

93* :class:`tuple[int, int, str]`

94

95"""