From 40c5fcd789de40a620421edf9b7458abd59fabe5 Mon Sep 17 00:00:00 2001 From: Jerilyn Date: Wed, 10 Sep 2025 05:49:06 -0700 Subject: [PATCH 1/6] mypy test cleanups --- tests/gentrie/test_gentri.py | 9 +++++---- tests/gentrie/testspec.py | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/gentrie/test_gentri.py b/tests/gentrie/test_gentri.py index 6fbe15d..5e30a65 100755 --- a/tests/gentrie/test_gentri.py +++ b/tests/gentrie/test_gentri.py @@ -6,6 +6,7 @@ # pylint: disable=invalid-name # pylint: disable=wrong-import-order # pylint: disable=wrong-import-position +# mypy: disable=import-error, dict-item, list-item import unittest @@ -2155,8 +2156,8 @@ def test_keys(self) -> None: self.assertEqual(found_id, expect_id) with self.subTest(msg="[TK003] trie.keys()"): - expect_id_list: list[TrieId] = [TrieId(1)] - found_id_list: list[TrieId] = list(trie.keys()) + expect_id_list = [TrieId(1)] + found_id_list = list(trie.keys()) self.assertEqual(found_id_list, expect_id_list) with self.subTest(msg="[TK004] trie.add('abc')"): @@ -2314,8 +2315,8 @@ def test_iter(self) -> None: self.assertEqual(found_id, expect_id) with self.subTest(msg="[TITER005] for entry in trie:"): - expect_ids_list: list[TrieId] = [TrieId(1), TrieId(2)] - found_ids_list: list[TrieId] = [] + expect_ids_list = [TrieId(1), TrieId(2)] + found_ids_list = [] for entry in trie: found_ids_list.append(entry) self.assertEqual(sorted(found_ids_list), expect_ids_list) diff --git a/tests/gentrie/testspec.py b/tests/gentrie/testspec.py index 93a058f..2fbc842 100644 --- a/tests/gentrie/testspec.py +++ b/tests/gentrie/testspec.py @@ -95,8 +95,10 @@ def run_test(test_case: unittest.TestCase, spec: TestSpec) -> None: # pylint: d errors.append(f"failed object validation: obj={spec.obj}") if spec.expected is not NO_EXPECTED_VALUE and spec.expected != found: errors.append(f"expected={spec.expected}, found={found}") - if isinstance(spec.display_on_fail, Callable): + if callable(spec.display_on_fail): errors.append(spec.display_on_fail()) + elif isinstance(spec.display_on_fail, str): + errors.append(spec.display_on_fail) except Exception as err: # pylint: disable=broad-exception-caught if spec.exception is None: errors.append(f"Did not expect exception. Caught exception {repr(err)}") From e54bf50dfa5614242803df7584d2550245c06c1d Mon Sep 17 00:00:00 2001 From: Jerilyn Date: Wed, 10 Sep 2025 06:16:32 -0700 Subject: [PATCH 2/6] mypy linting cleanups for benchmark_gentri.py --- bench/benchmark_gentri.py | 26 ++++++++++++++++--------- pyproject.toml | 1 + uv.lock | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/bench/benchmark_gentri.py b/bench/benchmark_gentri.py index 50815f8..221147a 100755 --- a/bench/benchmark_gentri.py +++ b/bench/benchmark_gentri.py @@ -4,6 +4,14 @@ Benchmark for the Generalized Trie implementation. This script runs a series of tests to measure the performance of the Generalized Trie against a set of predefined test cases. + +The Generalized Trie is a data structure that allows for efficient storage and retrieval +of keys that can be composed of various types of tokens, not just strings. + + +The benchmark includes tests for insertion, search, and deletion operations, +as well as tests for different key depths and symbol sets. + ''' # pylint: disable=wrong-import-position, too-many-instance-attributes # pylint: disable=too-many-positional-arguments, too-many-arguments, too-many-locals @@ -636,7 +644,7 @@ class BenchCase: graph_y_starts_at_zero: bool = True graph_x_labels_rotation: float = 0.0 - def __post_init__(self): + def __post_init__(self) -> None: self.results: list[BenchResults] = [] @property @@ -650,7 +658,7 @@ def expanded_kwargs_variations(self) -> list[dict[str, Any]]: values = [self.kwargs_variations[key] for key in keys] return [dict(zip(keys, v)) for v in itertools.product(*values)] - def run(self): + def run(self) -> None: """Run the benchmark tests. This method will execute the benchmark for each combination of @@ -1042,7 +1050,7 @@ def default_runner( description=f'[green] Benchmarking {group} (iteration {iteration_pass:<6d}; ' f'time {0.00:<3.2f}s)') PROGRESS.start_task(TASKS[tasks_name]) - total_elapsed: float = 0 + total_elapsed: int = 0 iterations_list: list[BenchIteration] = [] while ((iteration_pass <= iterations_min or wall_time < min_stop_at) and wall_time < max_stop_at): @@ -1050,7 +1058,7 @@ def default_runner( iteration_result = BenchIteration() iteration_result.elapsed = 0 - if isinstance(setup, Callable): + if callable(setup): setup() # Timer for benchmarked code @@ -1058,7 +1066,7 @@ def default_runner( action() timer_end: int = DEFAULT_TIMER() - if isinstance(teardown, Callable): + if callable(teardown): teardown() if iteration_pass == 1: @@ -1724,13 +1732,13 @@ def run_benchmarks(args: Namespace): if case.results: if args.json or args.json_data: data_export.append(case.as_dict(args=args)) - + graph_file: Path if args.graph: if args.ops: - graph_file: Path = benchmark_run_dir.joinpath(f'benchmark_graph_ops_{case.group[:60]}.svg') + graph_file = benchmark_run_dir.joinpath(f'benchmark_graph_ops_{case.group[:60]}.svg') case.plot_ops_results(graph_file) if args.timing: - graph_file: Path = benchmark_run_dir.joinpath(f'benchmark_graph_timing_{case.group[:60]}.svg') + graph_file = benchmark_run_dir.joinpath(f'benchmark_graph_timing_{case.group[:60]}.svg') case.plot_timing_results(graph_file) if args.csv: @@ -1782,7 +1790,7 @@ def run_benchmarks(args: Namespace): PROGRESS.remove_task(task) -def main(): +def main() -> None: """Main entry point for running benchmarks.""" parser = ArgumentParser(description='Run GeneralizedTrie benchmarks.') parser.add_argument('--verbose', action='store_true', help='Enable verbose output') diff --git a/pyproject.toml b/pyproject.toml index 192aa73..fe9a643 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -148,6 +148,7 @@ dev = [ "pandas>=2.3.2", "matplotlib>=3.10.6", "seaborn>=0.13.2", + "types-seaborn>=0.13.2", "pytest-benchmark>=5.1.0", "rich>=14.1.0", "sphinx>=8.1.3", diff --git a/uv.lock b/uv.lock index ae9931c..8c93161 100644 --- a/uv.lock +++ b/uv.lock @@ -793,6 +793,7 @@ dev = [ { name = "sphinx-rtd-theme" }, { name = "testplan" }, { name = "twine" }, + { name = "types-seaborn" }, ] [package.metadata] @@ -823,6 +824,7 @@ dev = [ { name = "sphinx-rtd-theme", specifier = ">=3.0.2" }, { name = "testplan", specifier = ">=25.8.0" }, { name = "twine", specifier = ">=6.2.0" }, + { name = "types-seaborn", specifier = ">=0.13.2" }, ] [[package]] @@ -1772,6 +1774,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cd/d7/612123674d7b17cf345aad0a10289b2a384bff404e0463a83c4a3a59d205/pandas-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d2c3554bd31b731cd6490d94a28f3abb8dd770634a9e06eb6d2911b9827db370", size = 13186141, upload-time = "2025-08-21T10:28:05.377Z" }, ] +[[package]] +name = "pandas-stubs" +version = "2.3.2.250827" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "types-pytz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/7b/8d2076a76ddf35806319798037056e4bbdcacdc832fb7c95b517f4c03fb2/pandas_stubs-2.3.2.250827.tar.gz", hash = "sha256:bcc2d49a2766325e4a1a492c3eeda879e9521bb5e26e69e2bbf13e80e7ef569a", size = 100032, upload-time = "2025-08-27T23:18:12.802Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/b8/dc820157be5aa9527f1f7ffe81737ee4d1cf0924081e1bfbd680530dde41/pandas_stubs-2.3.2.250827-py3-none-any.whl", hash = "sha256:3d613013b4189147a9a6bb18d8bec1e5b137de091496e9b9ff9f137ec3e223a9", size = 157775, upload-time = "2025-08-27T23:18:11.083Z" }, +] + [[package]] name = "paramiko" version = "4.0.0" @@ -2754,6 +2770,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8", size = 42727, upload-time = "2025-09-04T15:43:15.994Z" }, ] +[[package]] +name = "types-pytz" +version = "2025.2.0.20250809" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/e2/c774f754de26848f53f05defff5bb21dd9375a059d1ba5b5ea943cf8206e/types_pytz-2025.2.0.20250809.tar.gz", hash = "sha256:222e32e6a29bb28871f8834e8785e3801f2dc4441c715cd2082b271eecbe21e5", size = 10876, upload-time = "2025-08-09T03:14:17.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d0/91c24fe54e565f2344d7a6821e6c6bb099841ef09007ea6321a0bac0f808/types_pytz-2025.2.0.20250809-py3-none-any.whl", hash = "sha256:4f55ed1b43e925cf851a756fe1707e0f5deeb1976e15bf844bcaa025e8fbd0db", size = 10095, upload-time = "2025-08-09T03:14:16.674Z" }, +] + +[[package]] +name = "types-seaborn" +version = "0.13.2.20250809" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas-stubs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/e7/213e88e625567e62eb3ba843ece9a4fa4cf7938ec7669f6214e2691dbbe7/types_seaborn-0.13.2.20250809.tar.gz", hash = "sha256:10bbdae691ecaddb9ec7c8358132216af671f4c83020fe14e9e5e75b3f142472", size = 29278, upload-time = "2025-08-09T03:17:21.489Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/f2d5f44a90b9932121dce254ddefebb075e83be94a503569e44ee23cd220/types_seaborn-0.13.2.20250809-py3-none-any.whl", hash = "sha256:311fe9a222fa646761d4e5193f28d74335d6aa81ea947bb01e70c3b2484d39ac", size = 40929, upload-time = "2025-08-09T03:17:20.729Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" From 87536811696ca26352bc64d2cb0368bd1f3fe706 Mon Sep 17 00:00:00 2001 From: Jerilyn Date: Wed, 10 Sep 2025 06:43:15 -0700 Subject: [PATCH 3/6] mypy linting cleanup for traversal.py and bench_performance.py --- bench/bench_performance.py | 112 +++++++++++++++++----------------- src/gentrie/trie/traversal.py | 14 +++-- 2 files changed, 65 insertions(+), 61 deletions(-) diff --git a/bench/bench_performance.py b/bench/bench_performance.py index 452948b..11ed3f5 100755 --- a/bench/bench_performance.py +++ b/bench/bench_performance.py @@ -176,7 +176,7 @@ def english_words(): @pytest.mark.benchmark(group="Build trie from English wordset using update()", **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) def test_organic_build_with_update_from_english_words_list( - benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] + benchmark, runtime_validation: bool): '''Benchmark the adding of a list of english words to the trie using update() @@ -189,9 +189,9 @@ def helper_create_dictionary(words: Sequence[str], runtime_validation: bool) -> return trie gc.collect() - benchmark.extra_info['number_of_words'] = len(TEST_ENGLISH_WORDS) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['number_of_words'] = len(TEST_ENGLISH_WORDS) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_ENGLISH_WORDS) / len(TEST_ENGLISH_WORDS) if TEST_ENGLISH_WORDS else 0) benchmark(helper_create_dictionary, words=TEST_ENGLISH_WORDS, @@ -201,7 +201,7 @@ def helper_create_dictionary(words: Sequence[str], runtime_validation: bool) -> @pytest.mark.benchmark(group="Microbenchmark update() building trie from English words", **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) def test_microbenchmarking_update_for_build_from_english_words_list( - benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] + benchmark, runtime_validation: bool): '''Benchmark the adding of keys to the trie using update() @@ -218,12 +218,12 @@ def setup(): rounds = len(TEST_ENGLISH_WORDS) # Rounds limited to prevent exhaustion gc.collect() - benchmark.extra_info['number_of_words'] = len(TEST_ENGLISH_WORDS) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['number_of_words'] = len(TEST_ENGLISH_WORDS) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_ENGLISH_WORDS) / len(TEST_ENGLISH_WORDS) if TEST_ENGLISH_WORDS else 0) - benchmark.pedantic(benchmark_trie.update, # pyright: ignore[reportUnknownMemberType] + benchmark.pedantic(benchmark_trie.update, setup=setup, rounds=rounds, iterations=1) @@ -234,7 +234,7 @@ def setup(): @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) def test_build_with_update( - benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] + benchmark, runtime_validation: bool, depth: int): '''Benchmark the adding of keys to the trie using update() @@ -249,12 +249,12 @@ def setup(): rounds = len(TEST_DATA[depth]) # Rounds limited to prevent exhaustion gc.collect() - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_DATA[depth]) / len(TEST_DATA[depth]) if TEST_DATA[depth] else 0) - benchmark.pedantic(benchmark_trie.update, # pyright: ignore[reportUnknownMemberType] + benchmark.pedantic(benchmark_trie.update, setup=setup, rounds=rounds, iterations=1) @@ -265,7 +265,7 @@ def setup(): @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) def test_build_with_add( - benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] + benchmark, runtime_validation: bool, depth: int): '''Benchmark the adding of keys to the trie using add() @@ -280,12 +280,12 @@ def setup(): rounds = len(TEST_DATA[depth]) gc.collect() - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_DATA[depth]) / len(TEST_DATA[depth]) if TEST_DATA[depth] else 0) - benchmark.pedantic(benchmark_trie.add, # pyright: ignore[reportUnknownMemberType] + benchmark.pedantic(benchmark_trie.add, setup=setup, rounds=rounds, iterations=1) @@ -296,7 +296,7 @@ def setup(): @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) def test_updating_trie( - benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] + benchmark, runtime_validation: bool, depth: int): '''Benchmark the update value for a key operation on a populated trie. @@ -317,7 +317,7 @@ def test_updating_trie( **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) -def test_key_in_trie(benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] +def test_key_in_trie(benchmark, runtime_validation: bool, depth: int) -> None: '''Benchmark using keys with the in operator for GeneralizedTrie. @@ -328,10 +328,10 @@ def test_key_in_trie(benchmark, # pyright: ignore[reportUnknownParameterType, r benchmark_key: str = TEST_DATA[depth][-1] # Use the last key for benchmarking gc.collect() benchmark_trie.runtime_validation = runtime_validation - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_DATA[depth]) / len(TEST_DATA[depth]) if TEST_DATA[depth] else 0) benchmark(benchmark_trie.__contains__, benchmark_key) @@ -339,7 +339,7 @@ def test_key_in_trie(benchmark, # pyright: ignore[reportUnknownParameterType, r @pytest.mark.benchmark(group="Microbenchmark __contains__() for missing keys using synthetic data", **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) -def test_key_not_in_trie(benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] +def test_key_not_in_trie(benchmark, runtime_validation: bool, depth: int) -> None: '''Benchmark missing keys with the in operator for GeneralizedTrie. @@ -350,10 +350,10 @@ def test_key_not_in_trie(benchmark, # pyright: ignore[reportUnknownParameterTyp benchmark_trie.runtime_validation = runtime_validation gc.collect() - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in TEST_DATA[depth]) / len(TEST_DATA[depth]) if TEST_DATA[depth] else 0) benchmark(benchmark_trie.__contains__, missing_key) @@ -361,7 +361,7 @@ def test_key_not_in_trie(benchmark, # pyright: ignore[reportUnknownParameterTyp @pytest.mark.benchmark(group="Microbenchmark remove() method using synthetic data", **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) -def test_remove_key_from_trie(benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] +def test_remove_key_from_trie(benchmark, runtime_validation: bool, depth: int) -> None: '''Benchmark remove() method for GeneralizedTrie. @@ -380,12 +380,12 @@ def setup(): rounds = len(test_data) # Rounds limited to prevent exhaustion gc.collect() - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in test_data) / len(test_data) if test_data else 0) - benchmark.pedantic(benchmark_trie.remove, # pyright: ignore[reportUnknownMemberType] + benchmark.pedantic(benchmark_trie.remove, setup=setup, rounds=rounds) @@ -394,7 +394,7 @@ def setup(): **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', TEST_DEPTHS) -def test_get(benchmark, # pyright: ignore[reportUnknownParameterType, reportMissingParameterType] +def test_get(benchmark, runtime_validation: bool, depth: int) -> None: '''Benchmark get() method for GeneralizedTrie. @@ -411,12 +411,12 @@ def setup(): rounds = len(test_data) # Rounds limited to prevent exhaustion gc.collect() - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['average_word_length'] = ( # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['depth'] = depth + benchmark.extra_info['number_of_words'] = len(TEST_DATA[depth]) + benchmark.extra_info['runtime_validation'] = runtime_validation + benchmark.extra_info['average_word_length'] = ( sum(len(word) for word in test_data) / len(test_data) if test_data else 0) - benchmark.pedantic(benchmark_trie.get, # pyright: ignore[reportUnknownMemberType] + benchmark.pedantic(benchmark_trie.get, setup=setup, rounds=rounds) @@ -424,7 +424,7 @@ def setup(): @pytest.mark.benchmark(group="Microbenchmark prefixes() using synthetic data", **BENCHMARK_CONFIG) @pytest.mark.parametrize('runtime_validation', [False, True]) @pytest.mark.parametrize('depth', [3, 4, 5, 6, 7, 8, 9]) -def test_prefixes(benchmark, # pyright: ignore[reportMissingParameterType, reportUnknownParameterType] +def test_prefixes(benchmark, runtime_validation: bool, depth: int): """Benchmark trie prefixes() method. @@ -453,10 +453,10 @@ def helper_prefixes(trie: GeneralizedTrie, search_key: GeneralizedKey) -> list[G # with additional overhead vs the generator approach. results: list[GeneralizedKey] = cast(list[GeneralizedKey], benchmark(helper_prefixes, trie, search_key)) - benchmark.extra_info['number_of_matches_per_query'] = len(results) # pyright: ignore - benchmark.extra_info['keys_in_trie'] = len(trie) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['depth'] = depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['number_of_matches_per_query'] = len(results) + benchmark.extra_info['keys_in_trie'] = len(trie) + benchmark.extra_info['depth'] = depth + benchmark.extra_info['runtime_validation'] = runtime_validation @pytest.mark.benchmark(group="Microbenchmark prefixed_by() using synthetic data", @@ -465,7 +465,7 @@ def helper_prefixes(trie: GeneralizedTrie, search_key: GeneralizedKey) -> list[G @pytest.mark.parametrize('trie_depth', [7]) @pytest.mark.parametrize('key_depth', [2, 3, 4]) # Focus on manageable depths @pytest.mark.parametrize('search_depth', [1, 2, 3]) # Focus on manageable depths -def test_prefixed_by(benchmark, # pyright: ignore[reportMissingParameterType, reportUnknownParameterType] +def test_prefixed_by(benchmark, runtime_validation: bool, trie_depth: int, key_depth: int, @@ -500,12 +500,12 @@ def helper_prefixed_by(trie: GeneralizedTrie, # with additional overhead vs the generator approach. results: list[GeneralizedKey] = cast(list[GeneralizedKey], benchmark(helper_prefixed_by, trie, search_key, search_depth)) - benchmark.extra_info['number_of_matches_per_query'] = len(results) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['keys_in_trie'] = len(trie) # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['trie_depth'] = trie_depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['search_depth'] = search_depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['key_depth'] = key_depth # pyright: ignore[reportUnknownMemberType] - benchmark.extra_info['runtime_validation'] = runtime_validation # pyright: ignore[reportUnknownMemberType] + benchmark.extra_info['number_of_matches_per_query'] = len(results) + benchmark.extra_info['keys_in_trie'] = len(trie) + benchmark.extra_info['trie_depth'] = trie_depth + benchmark.extra_info['search_depth'] = search_depth + benchmark.extra_info['key_depth'] = key_depth + benchmark.extra_info['runtime_validation'] = runtime_validation if __name__ == "__main__": diff --git a/src/gentrie/trie/traversal.py b/src/gentrie/trie/traversal.py index 8fd21fc..4de8d27 100644 --- a/src/gentrie/trie/traversal.py +++ b/src/gentrie/trie/traversal.py @@ -2,7 +2,7 @@ """Traversal operations for GeneralizedTrie.""" from collections import deque -from typing import Generator +from typing import Iterable, TYPE_CHECKING from ..exceptions import InvalidGeneralizedKeyError, ErrorTag, TrieTypeError, TrieValueError from ..protocols import GeneralizedKey @@ -11,6 +11,10 @@ from .trie_mixins import TrieMixinsInterface + +if TYPE_CHECKING: + from ..nodes import Node + # Disabled because pyright does not understand mixins # use of private attributes from the mixing class as declared # in the TrieMixinsInterface protocol. @@ -20,7 +24,7 @@ class TrieTraversalMixin: """Mixin providing traversal operations (prefixes, prefixed_by).""" - def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Generator[TrieEntry, None, None]: + def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Iterable[TrieEntry]: """Yields TrieEntry instances for all keys in the trie that are a prefix of the passed key. Searches the trie for all keys that are prefix matches @@ -71,7 +75,7 @@ def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Generator[TrieEn tag=ErrorTag.TRIE_PREFIXES_INVALID_GENERALIZED_KEY ) - current_node = self + current_node: TrieMixinsInterface | Node = self for token in key: if current_node.ident: @@ -85,7 +89,7 @@ def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Generator[TrieEn yield self._trie_entries[current_node.ident] def prefixed_by(self: TrieMixinsInterface, key: GeneralizedKey, depth: int = -1 - ) -> Generator[TrieEntry, None, None]: + ) -> Iterable[TrieEntry]: """Yields all entries in the trie that are prefixed by the given key, up to a specified depth. Searches the trie for all keys that start with the provided key and yields their @@ -156,7 +160,7 @@ def prefixed_by(self: TrieMixinsInterface, key: GeneralizedKey, depth: int = -1 tag=ErrorTag.TRIE_PREFIXED_BY_BAD_DEPTH_VALUE ) - current_node = self + current_node: TrieMixinsInterface | Node = self try: for token in key: current_node = current_node.children[token] From 97a9303c8b6bafa9fed202f289cfc4618788db0f Mon Sep 17 00:00:00 2001 From: Jerilyn Date: Wed, 10 Sep 2025 07:46:36 -0700 Subject: [PATCH 4/6] mypy types cleanup --- bench/bench_performance.py | 9 +++------ src/gentrie/trie/access.py | 8 ++++++-- src/gentrie/trie/base.py | 16 +++++++--------- src/gentrie/trie/collection.py | 1 - src/gentrie/trie/mutation.py | 1 - src/gentrie/trie/removal.py | 1 - src/gentrie/trie/storage.py | 1 - src/gentrie/trie/traversal.py | 7 +++---- src/gentrie/trie/trie_mixins.py | 7 ++++++- tests/gentrie/test_gentri.py | 20 ++++++++++---------- 10 files changed, 35 insertions(+), 36 deletions(-) diff --git a/bench/bench_performance.py b/bench/bench_performance.py index 11ed3f5..3184dd0 100755 --- a/bench/bench_performance.py +++ b/bench/bench_performance.py @@ -3,9 +3,6 @@ # pylint: disable=wrong-import-position, too-many-instance-attributes, line-too-long # pylint: disable=too-many-positional-arguments, too-many-arguments, too-many-locals # pyright: reportUnnecessaryTypeIgnoreComment=warning - -# Note: pytest-benchmark does not expose proper typing hence the many type -# ignores on lines related to benchmark and benchmark.info '''bench_performance.py Benchmark for the Generalized Trie implementation. @@ -27,7 +24,7 @@ import pytest -from gentrie import GeneralizedTrie, GeneralizedKey +from gentrie import GeneralizedTrie, GeneralizedKey, TrieEntry # More robust benchmark configuration BENCHMARK_CONFIG: dict[str, Any] = { @@ -443,7 +440,7 @@ def test_prefixes(benchmark, trie.runtime_validation = runtime_validation search_key = TEST_DATA[depth][0] - def helper_prefixes(trie: GeneralizedTrie, search_key: GeneralizedKey) -> list[GeneralizedKey]: + def helper_prefixes(trie: GeneralizedTrie, search_key: GeneralizedKey) -> list[TrieEntry]: return list(trie.prefixes(search_key)) gc.collect() @@ -490,7 +487,7 @@ def test_prefixed_by(benchmark, def helper_prefixed_by(trie: GeneralizedTrie, search_key: GeneralizedKey, - search_depth: int) -> list[GeneralizedKey]: + search_depth: int) -> list[TrieEntry]: return list(trie.prefixed_by(search_key, search_depth)) gc.collect() diff --git a/src/gentrie/trie/access.py b/src/gentrie/trie/access.py index e2f54e1..4c4ddea 100644 --- a/src/gentrie/trie/access.py +++ b/src/gentrie/trie/access.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Data access operations for the trie.""" -from typing import Any, Optional +from typing import Any, Optional, TYPE_CHECKING from ..exceptions import ErrorTag, InvalidGeneralizedKeyError, TrieKeyError, TrieTypeError from ..types import TrieEntry, TrieId, GeneralizedKey @@ -15,6 +15,10 @@ # pyright: reportPrivateUsage=false +if TYPE_CHECKING: + from ..nodes import Node + + class TrieAccessMixin: """Mixin providing data access operations. @@ -44,7 +48,7 @@ def __contains__(self: TrieMixinsInterface, key_or_ident: GeneralizedKey | TrieI if self.runtime_validation and not is_generalizedkey(key_or_ident): return False - current_node = self + current_node: TrieMixinsInterface | Node = self for token in key_or_ident: if token not in current_node.children: return False diff --git a/src/gentrie/trie/base.py b/src/gentrie/trie/base.py index 15ea77f..bb0e7ad 100644 --- a/src/gentrie/trie/base.py +++ b/src/gentrie/trie/base.py @@ -1,16 +1,14 @@ # -*- coding: utf-8 -*- """Base trie functionality and initialization.""" - +from __future__ import annotations from copy import deepcopy from textwrap import indent -from typing import Any, Optional, TYPE_CHECKING +from typing import Any, Optional from ..nodes import Node from ..protocols import TrieKeyToken from ..types import TrieEntry, TrieId - -if TYPE_CHECKING: - from .trie_mixins import TrieMixinsInterface +from .trie_mixins import TrieMixinsInterface class TrieBase: @@ -20,7 +18,7 @@ class TrieBase: runtime_validation (bool): Whether to enable runtime validation of keys. """ - def __init__(self, runtime_validation: bool = True) -> None: + def __init__(self: TrieMixinsInterface, runtime_validation: bool = True) -> None: """Initializes a new TrieBase instance. By default, runtime validation of keys is enabled. If your code is well tested, @@ -48,7 +46,7 @@ def __init__(self, runtime_validation: bool = True) -> None: # Mapping of unique identifiers to their corresponding TrieEntry instances. self._trie_entries: dict[TrieId, TrieEntry] = {} - def clear(self) -> None: + def clear(self: TrieMixinsInterface) -> None: """Clears all keys from the trie.""" self.ident = None self.token = None @@ -60,7 +58,7 @@ def clear(self) -> None: # Reset the ident counter self._ident_counter = 0 - def __str__(self) -> str: + def __str__(self: TrieMixinsInterface) -> str: """Generates a stringified version of the trie for visual examination.""" output: list[str] = ["{"] output.append(f" trie number = {self._ident_counter}") @@ -73,7 +71,7 @@ def __str__(self) -> str: output.append("}") return "\n".join(output) - def _as_dict(self) -> dict[str, Any]: + def _as_dict(self: TrieMixinsInterface) -> dict[str, Any]: """Converts the trie to a dictionary representation.""" # pylint: disable=protected-access, no-member return deepcopy({ diff --git a/src/gentrie/trie/collection.py b/src/gentrie/trie/collection.py index 17e76bb..61766ba 100644 --- a/src/gentrie/trie/collection.py +++ b/src/gentrie/trie/collection.py @@ -4,7 +4,6 @@ from typing import Generator from ..types import TrieEntry, TrieId - from .trie_mixins import TrieMixinsInterface diff --git a/src/gentrie/trie/mutation.py b/src/gentrie/trie/mutation.py index 979992a..e3af938 100644 --- a/src/gentrie/trie/mutation.py +++ b/src/gentrie/trie/mutation.py @@ -5,7 +5,6 @@ from ..protocols import GeneralizedKey from ..types import TrieId - from .trie_mixins import TrieMixinsInterface diff --git a/src/gentrie/trie/removal.py b/src/gentrie/trie/removal.py index 0ceea15..ce07d26 100644 --- a/src/gentrie/trie/removal.py +++ b/src/gentrie/trie/removal.py @@ -6,7 +6,6 @@ from ..protocols import GeneralizedKey, TrieKeyToken from ..types import TrieId from ..validation import is_generalizedkey - from .trie_mixins import TrieMixinsInterface # Disabled because pyright does not understand mixins diff --git a/src/gentrie/trie/storage.py b/src/gentrie/trie/storage.py index 9b40f91..6866b82 100644 --- a/src/gentrie/trie/storage.py +++ b/src/gentrie/trie/storage.py @@ -11,7 +11,6 @@ from ..protocols import GeneralizedKey from ..types import TrieEntry, TrieId from ..validation import is_generalizedkey - from .trie_mixins import TrieMixinsInterface # Disabled because pyright does not understand mixins diff --git a/src/gentrie/trie/traversal.py b/src/gentrie/trie/traversal.py index 4de8d27..d3df186 100644 --- a/src/gentrie/trie/traversal.py +++ b/src/gentrie/trie/traversal.py @@ -2,13 +2,12 @@ """Traversal operations for GeneralizedTrie.""" from collections import deque -from typing import Iterable, TYPE_CHECKING +from typing import Iterator, TYPE_CHECKING from ..exceptions import InvalidGeneralizedKeyError, ErrorTag, TrieTypeError, TrieValueError from ..protocols import GeneralizedKey from ..types import TrieEntry from ..validation import is_generalizedkey - from .trie_mixins import TrieMixinsInterface @@ -24,7 +23,7 @@ class TrieTraversalMixin: """Mixin providing traversal operations (prefixes, prefixed_by).""" - def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Iterable[TrieEntry]: + def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Iterator[TrieEntry]: """Yields TrieEntry instances for all keys in the trie that are a prefix of the passed key. Searches the trie for all keys that are prefix matches @@ -89,7 +88,7 @@ def prefixes(self: TrieMixinsInterface, key: GeneralizedKey) -> Iterable[TrieEnt yield self._trie_entries[current_node.ident] def prefixed_by(self: TrieMixinsInterface, key: GeneralizedKey, depth: int = -1 - ) -> Iterable[TrieEntry]: + ) -> Iterator[TrieEntry]: """Yields all entries in the trie that are prefixed by the given key, up to a specified depth. Searches the trie for all keys that start with the provided key and yields their diff --git a/src/gentrie/trie/trie_mixins.py b/src/gentrie/trie/trie_mixins.py index 925ff6c..744dbef 100644 --- a/src/gentrie/trie/trie_mixins.py +++ b/src/gentrie/trie/trie_mixins.py @@ -1,5 +1,5 @@ """Protocol for all GeneralizedTrie trie mixins.""" - +from __future__ import annotations from typing import Any, Iterator, Optional, Protocol from ..nodes import Node @@ -30,6 +30,11 @@ class TrieMixinsInterface(Protocol): # pylint: disable=missing-function-docstring + # From base.py + def __init__(self, runtime_validation: bool = True) -> None: ... + def clear(self) -> None: ... + def __str__(self) -> str: ... + # From storage.py def add(self, key: GeneralizedKey, value: Optional[Any] = None) -> TrieId: ... def update(self, key: GeneralizedKey, value: Optional[Any] = None) -> TrieId: ... diff --git a/tests/gentrie/test_gentri.py b/tests/gentrie/test_gentri.py index 5e30a65..e2b605a 100755 --- a/tests/gentrie/test_gentri.py +++ b/tests/gentrie/test_gentri.py @@ -6,7 +6,6 @@ # pylint: disable=invalid-name # pylint: disable=wrong-import-order # pylint: disable=wrong-import-position -# mypy: disable=import-error, dict-item, list-item import unittest @@ -33,7 +32,7 @@ is_hashable) sys.path.append(os.path.dirname(os.path.abspath(__file__))) -from testspec import TestSpec, run_tests_list # noqa: E402 # pylint: disable=import-error +from testspec import TestSpec, run_tests_list # type: ignore[import-not-found] # noqa: E402, E501 # pylint: disable=import-error class MockDefaultTrieKeyToken: @@ -502,7 +501,7 @@ def test_add(self) -> None: expected={ 'ident': None, 'children': { - 'tree': { + 'tree': { # type: ignore[dict-item] 'ident': None, 'token': 'tree', 'value': None, @@ -545,7 +544,7 @@ def test_add(self) -> None: expected={ 'ident': None, 'children': { - 'tree': { + 'tree': { # type: ignore[dict-item] 'ident': None, 'token': 'tree', 'value': None, @@ -861,7 +860,7 @@ def test_update(self) -> None: expected={ 'ident': None, 'children': { - 'tree': { + 'tree': { # type: ignore[dict-item] 'ident': None, 'token': 'tree', 'value': None, @@ -904,7 +903,7 @@ def test_update(self) -> None: expected={ 'ident': None, 'children': { - 'tree': { + 'tree': { # type: ignore[dict-item] 'ident': None, 'token': 'tree', 'value': None, @@ -1140,7 +1139,7 @@ def test_update(self) -> None: expected={ 'ident': None, 'children': { - 'tree': { + 'tree': { # type: ignore[dict-item] 'ident': None, 'token': 'tree', 'value': None, @@ -1916,7 +1915,7 @@ def test_contains_dunder(self) -> None: # Test with different types of keys and a new trie trie = GeneralizedTrie() id_list_1: TrieId = trie.add([1]) - id_list_none: TrieId = trie.add([None]) + id_list_none: TrieId = trie.add([None]) # type: ignore[list-item] tests = [ TestSpec( name="[TGT_TC013] trie.__contains__(1) (false, int(1) not a valid key type)", @@ -2170,8 +2169,9 @@ def test_keys(self) -> None: found_id_list = list(sorted(trie.keys())) self.assertEqual(found_id_list, expect_id_list) - with self.assertRaises(TypeError, msg="[TK006] trie.remove('abc')"): - trie.remove(set('abc')) # type: ignore[reportGeneralTypeIssues] + with self.assertRaises(TypeError, msg="[TK006] trie.remove(set('abc')) (invalid key type)"): + # mypy: disable=arg-type + trie.remove(set('abc')) # type: ignore[reportGeneralTypeIssues, arg-type] with self.subTest(msg="[TK007] trie.remove(TrieId(1))"): trie.remove(TrieId(1)) From df8dd634c8093bed99640160241993ea3822ab69 Mon Sep 17 00:00:00 2001 From: Jerilyn Date: Wed, 10 Sep 2025 07:54:30 -0700 Subject: [PATCH 5/6] 0.9.6 release --- CHANGELOG.md | 1 + docs/html/_static/documentation_options.js | 2 +- docs/html/benchmarks.html | 14 +- docs/html/genindex.html | 16 +- docs/html/gentrie.html | 734 +++++++++------------ docs/html/gentrie.trie.html | 39 +- docs/html/index.html | 209 +++--- docs/html/modules.html | 225 +++---- docs/html/objects.inv | Bin 1290 -> 1295 bytes docs/html/py-modindex.html | 12 +- docs/html/reference.html | 18 +- docs/html/search.html | 14 +- docs/html/searchindex.js | 2 +- docs/html/usage.html | 18 +- docs/source/conf.py | 2 +- pyproject.toml | 3 +- uv.lock | 40 +- 17 files changed, 586 insertions(+), 763 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97213f8..4790e86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,3 +27,4 @@ * 0.9.3 - Addition of coverage support. Tests for traversal.py. pytest support. Test orchestration using pytest-order and pytest-dependency. Fixed TrieValueError export. * 0.9.4 - Addition of tests for is_triekeytoke(), is_hashable(), get() methods and for TrieEntry(). Fixed bugs in TrieEntry __eq__ and __hash__ dunder methods. Rewrote __getitem__ and __contains__ dunder tests, added __delitem__ dunder tests. Excluded test_play.py and testspec.py from coverage measurements. Changed Nodes class to use __slots__ for attributes. Added tuplization of keys when creating TrieEntrys' to aid in immutability preservation. * 0.9.5 - Benchmarking code, addition of py.typed for type support +* 0.9.6 - mypy types cleanup, addition of sphinxawesome-theme to \[dependency-groups.dev\] diff --git a/docs/html/_static/documentation_options.js b/docs/html/_static/documentation_options.js index bd9a7f8..df9d7e5 100644 --- a/docs/html/_static/documentation_options.js +++ b/docs/html/_static/documentation_options.js @@ -1,5 +1,5 @@ const DOCUMENTATION_OPTIONS = { - VERSION: '0.9.4', + VERSION: '0.9.6', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/docs/html/benchmarks.html b/docs/html/benchmarks.html index 9d4fa91..5d36a4d 100644 --- a/docs/html/benchmarks.html +++ b/docs/html/benchmarks.html @@ -7,9 +7,9 @@ -Benchmarks | gen-tries 0.9.4 documentation - - +Benchmarks | gen-tries 0.9.6 documentation + + @@ -34,7 +34,7 @@ Skip to content
-
-class gentrie.Hashable(*args, **kwargs)
+class gentrie.Hashable(*args, **kwargs)

Bases: TrieKeyToken, Protocol

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

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

Use TrieKeyToken instead.

-
-exception gentrie.InvalidGeneralizedKeyError(msg: str, tag: ErrorTag)
+exception gentrie.InvalidGeneralizedKeyError(msg: str, tag: ErrorTag)

Bases: TrieTypeError

Raised when a key is not a valid GeneralizedKey object.

This is a sub-class of TrieTypeError.

-
-exception gentrie.InvalidTrieKeyTokenError(msg: str, tag: ErrorTag)
+exception gentrie.InvalidTrieKeyTokenError(msg: str, tag: ErrorTag)

Bases: TrieTypeError

Raised when a token in a key is not a valid TrieKeyToken object.

This is a sub-class of TrieTypeError.

-
-class gentrie.TrieEntry(ident: TrieId, key: Sequence[TrieKeyToken], value: Any | None = None)
+class gentrie.TrieEntry(ident: TrieId, key: Sequence[TrieKeyToken], value: Any | None = None)

Bases: NamedTuple

A TrieEntry is a NamedTuple containing the unique identifer and key for an entry in the trie.

-ident: TrieId
+ident: TrieId

TrieId Unique identifier for a key in the trie. Alias for field number 0.

-
-key: Sequence[TrieKeyToken]
+key: Sequence[TrieKeyToken]

GeneralizedKey Key for an entry in the trie. Alias for field number 1.

-
-value: Any | None
+value: Any | None

Optional value for the entry in the trie. Alias for field number 2.

-
-
-class gentrie.TrieId(value: int)
+class gentrie.TrieId(value: int)

Bases: int

Unique identifier for a key in a trie.

-
-exception gentrie.TrieKeyError(msg: str, tag: ErrorTag)
+exception gentrie.TrieKeyError(msg: str, tag: ErrorTag)

Bases: KeyError

Base class for all trie-related key errors.

It differs from a standard KeyError by the addition of a @@ -1078,10 +962,9 @@

Example 3 - Entries prefixed by a key
-class gentrie.TrieKeyToken(*args, **kwargs)
+class gentrie.TrieKeyToken(*args, **kwargs)

Bases: Protocol

TrieKeyToken is a protocol that defines key tokens that are usable with a GeneralizedTrie.

The protocol requires that a token object be hashable. This means that it @@ -1103,9 +986,9 @@

Example 3 - Entries prefixed by a key2 3token = SomeTokenClass() 4if isinstance(token, TrieKeyToken): -5 print("supports the TrieKeyToken protocol") +5 print("supports the TrieKeyToken protocol") 6else: -7 print("does not support the TrieKeyToken protocol") +7 print("does not support the TrieKeyToken protocol")

@@ -1118,10 +1001,9 @@

Example 3 - Entries prefixed by a key
-exception gentrie.TrieTypeError(msg: str, tag: ErrorTag)
+exception gentrie.TrieTypeError(msg: str, tag: ErrorTag)

Bases: TypeError

Base class for all trie-related type errors.

It differs from a standard TypeError by the addition of a @@ -1138,10 +1020,9 @@

Example 3 - Entries prefixed by a key
-exception gentrie.TrieValueError(msg: str, tag: ErrorTag)
+exception gentrie.TrieValueError(msg: str, tag: ErrorTag)

Bases: ValueError

Base class for all trie-related value errors.

It differs from a standard ValueError by the addition of a @@ -1158,10 +1039,9 @@

Example 3 - Entries prefixed by a key
-gentrie.is_generalizedkey(key: Any) bool
+gentrie.is_generalizedkey(key: Any) bool

Tests key for whether it is a valid GeneralizedKey.

A valid GeneralizedKey is a Sequence that returns TrieKeyToken protocol conformant objects when @@ -1178,18 +1058,16 @@

Example 3 - Entries prefixed by a key
-gentrie.is_hashable(token: Any) bool
+gentrie.is_hashable(token: Any) bool

is_hashable is deprecated and will be removed in a future version.

This function is a wrapper for is_triekeytoken() and is only provided for backward compatibility.

Use is_triekeytoken() instead.

-
-gentrie.is_triekeytoken(token: Any) bool
+gentrie.is_triekeytoken(token: Any) bool

Tests token for whether it is a valid TrieKeyToken.

A valid TrieKeyToken is a hashable object (implements both __eq__() and __hash__() methods).

Examples: @@ -1207,143 +1085,137 @@

Example 3 - Entries prefixed by a key -

- - - - + diff --git a/docs/html/reference.html b/docs/html/reference.html index 3774cdc..5aeae84 100644 --- a/docs/html/reference.html +++ b/docs/html/reference.html @@ -7,9 +7,9 @@ -API Reference | gen-tries 0.9.4 documentation - - +API Reference | gen-tries 0.9.6 documentation + + @@ -34,7 +34,7 @@ Skip to content