Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 32 additions & 25 deletions examples/assigning_values_to_entries.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@
You can also retrieve all entries that are prefixes for or prefixed by
a given key:

- `trie.prefixed_by(key)` returns a set of `TrieEntry` objects that
- `trie.prefixed_by(key)` returns an Iterator of `TrieEntry` objects that
are prefixed_by of the given key.
- `trie.prefixes(key)` returns a set of `TrieEntry` objects that
- `trie.prefixes(key)` returns an Iterator of `TrieEntry` objects that
are prefixes of the given key.

These methods are useful for searching and retrieving entries
Expand All @@ -81,21 +81,22 @@
trie = GeneralizedTrie()

# Adding entries using the trie[key] = value syntax
entries: list[tuple[str, str | list[str]]] = [
entries = [
('abcdef', 'value1'),
('abc', 'value2'),
('abcd', 'value3'),
('qrf', 'value4'),
('xyz', ['lists', 'are', 'also', 'supported']),
('xy', 'value6'),
]

for key, value in entries:
trie[key] = value

prefixed_by: set[TrieEntry] = set(trie.prefixed_by('xy'))
prefixed_by: list[TrieEntry] = list(trie.prefixed_by('xy'))
print(f'prefixed_by = {prefixed_by}')

prefixes: set[TrieEntry] = set(trie.prefixes('abcdefg'))
prefixes: list[TrieEntry] = list(trie.prefixes('abcdefg'))
print(f'prefixes = {prefixes}')

# prefixed_by = {
Expand All @@ -111,22 +112,22 @@

# Adding using the add method
# This will throw an error if the key already exists.
more_entries: list[tuple[str | tuple[int, ...], str]] = [
more_entries = [
((128, 96, 160, 0), 'value5'),
((128, 90), 'value5b'),
('xy', 'value6'),
]
for key, value in more_entries:
for different_key, different_value in more_entries:
try:
trie.add(key, value)
print(f'Added entry: {key} -> {value}')
trie.add(different_key, different_value)
print(f'Added entry: {different_key} -> {different_value}')
except DuplicateKeyError:
print(f'DuplicateKeyError - entry already exists: {key}')
print(f'DuplicateKeyError - entry already exists: {different_key}')

prefixed_by: set[TrieEntry] = set(trie.prefixed_by([128]))
prefixed_by = list(trie.prefixed_by([128]))
print(f'prefixed_by = {prefixed_by}')

prefixes: set[TrieEntry] = set(trie.prefixes([128, 90]))
prefixes = list(trie.prefixes([128, 90]))
print(f'prefixes = {prefixes}')

# prefixed_by = {
Expand All @@ -149,20 +150,26 @@
for key, value in even_more_entries:
trie.update(key, value)

prefixed_by = set(trie.prefixed_by('abcd'))
prefixed_by = list(trie.prefixed_by('abcd'))
print(f'prefixed_by = {prefixed_by}')

prefixes = set(trie.prefixes('abcdefg'))
prefixes = list(trie.prefixes('abcdefg'))
print(f'prefixes = {prefixes}')

# prefixed_by = {
# TrieEntry(ident=3, key='abcd', value='value8'),
# TrieEntry(ident=9, key='abcdefghi', value='value7'),
# TrieEntry(ident=1, key='abcdef', value='value1')
# }
#
# prefixes = {
# TrieEntry(ident=2, key='abc', value='value2'),
# TrieEntry(ident=3, key='abcd', value='value8'),
# TrieEntry(ident=1, key='abcdef', value='value1')
# }
# prefixed_by = [TrieEntry(ident=TrieId(6), key='xy', value='value6'),
# TrieEntry(ident=TrieId(5), key='xyz', value=['lists', 'are', 'also', 'supported'])]
# prefixes = [TrieEntry(ident=TrieId(2), key='abc', value='value2'),
# TrieEntry(ident=TrieId(3), key='abcd', value='value3'),
# TrieEntry(ident=TrieId(1), key='abcdef', value='value1')]
# Added entry: (128, 96, 160, 0) -> value5
# Added entry: (128, 90) -> value5b
# DuplicateKeyError - entry already exists: xy
# prefixed_by = [TrieEntry(ident=TrieId(8), key=(128, 90), value='value5b'),
# TrieEntry(ident=TrieId(7), key=(128, 96, 160, 0), value='value5')]
# prefixes = [TrieEntry(ident=TrieId(8), key=(128, 90), value='value5b')]
# prefixed_by = [TrieEntry(ident=TrieId(3), key='abcd', value='value8'),
# TrieEntry(ident=TrieId(1), key='abcdef', value='value1'),
# TrieEntry(ident=TrieId(9), key='abcdefghi', value='value7')]
# prefixes = [TrieEntry(ident=TrieId(2), key='abc', value='value2'),
# TrieEntry(ident=TrieId(3), key='abcd', value='value8'),
# TrieEntry(ident=TrieId(1), key='abcdef', value='value1')]
4 changes: 2 additions & 2 deletions examples/prefixed_by_example.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
"""Example of using a GeneralizedTrie for indexing sequences of strings."""
from typing import Generator
from typing import Iterator
from gentrie import GeneralizedTrie, TrieEntry

trie = GeneralizedTrie()
keys: list[str] = ['abcdef', 'abc', 'a', 'abcd', 'qrs']
for entry in keys:
trie.add(entry)
matches: Generator[TrieEntry, None, None] = trie.prefixed_by('abcd')
matches: Iterator[TrieEntry] = trie.prefixed_by('abcd')

for trie_entry in sorted(list(matches)):
print(f'{trie_entry.ident}: {trie_entry.key}')
Expand Down
4 changes: 2 additions & 2 deletions examples/prefixes_example.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
"""Example of using prefixes() method"""
from typing import Generator
from typing import Iterator

from gentrie import GeneralizedTrie, TrieEntry

trie: GeneralizedTrie = GeneralizedTrie()
keys: list[str] = ['abcdef', 'abc', 'a', 'abcd', 'qrs']
for entry in keys:
trie.add(entry)
matches: Generator[TrieEntry, None, None] = trie.prefixes('abcd')
matches: Iterator[TrieEntry] = trie.prefixes('abcd')
for trie_entry in sorted(list(matches)):
print(f'{trie_entry.ident}: {trie_entry.key}')

Expand Down
6 changes: 3 additions & 3 deletions examples/url_suffixes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""Example of using a GeneralizedTrie for indexing website URLs by path"""
from typing import Generator
from typing import Iterator

from gentrie import GeneralizedTrie, TrieEntry

Expand All @@ -17,13 +17,13 @@

# Find https URLs with "example.com" domain or sub-domain
print("HTTPS URLs for domains or sub-domains of 'example.com'")
prefixed_by: Generator[TrieEntry, None, None] = url_trie.prefixed_by(["https", ":", "//", "com", "example"])
prefixed_by: Iterator[TrieEntry] = url_trie.prefixed_by(["https", ":", "//", "com", "example"])
for entry in prefixed_by:
print(f"Found URL: {entry.value}")

# Find ftp protocol URLs
print("FTP URLs")
prefixed_by: Generator[TrieEntry, None, None] = url_trie.prefixed_by(["ftp"])
prefixed_by = url_trie.prefixed_by(["ftp"])
for entry in prefixed_by:
print(f"Found URL: {entry.value}")

Expand Down
1 change: 1 addition & 0 deletions src/gentrie/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ def __eq__(self, other: object) -> bool:
other.key) and self.value == other.value

def __hash__(self) -> int:
print(f'Hashing TrieEntry: ident={self.ident}, key={self.key}, value={self.value}')
return hash((self.ident, tuple(self.key), self.value)) # pyright: ignore[reportUnknownArgumentType]
19 changes: 19 additions & 0 deletions tests/gentrie/test_gentri.py
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,25 @@ def test_prefixed_by(self) -> None:
]
run_tests_list(self, tests)

# New untouched trie for the next sequence of tests
# Not using clear() here to keep the clear() tests cleanly separated
# from the prefixed_by() tests.
trie = GeneralizedTrie()
entries = [
('abcdef', 'value1'),
('abc', 'value2'),
('abcd', 'value3'),
('qrf', 'value4'),
('xyz', ['lists', 'are', 'also', 'supported']),
('xy', 'value6'),
]
for key, value in entries:
trie.add(key, value)
with self.subTest(msg='[TGT_TPB013] trie.prefixed_by("xy")'):
expected = tuple([trie['xy'], trie['xyz']])
found = tuple(trie.prefixed_by('xy'))
self.assertEqual(expected, found, msg=f'Expected {expected}, found {found}')

@pytest.mark.order(after=['test_create_trie', 'test_add', 'test_trieid_class', 'test_contains_dunder'])
@pytest.mark.dependency(
name='test_deeply_nested_keys',
Expand Down