-
Notifications
You must be signed in to change notification settings - Fork 0
Phase 3: core/decorators/input #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
69d13c0
Inicial structure
teresa-ortega c3d737f
add dynamic input hook registration
teresa-ortega ce00baf
Update documentation
teresa-ortega dfec3d3
Add test for input behaviour
teresa-ortega 3bded4d
add return value validation
teresa-ortega 459071e
add parameter validator
teresa-ortega c858ed6
remove the error class
teresa-ortega e3bd987
A possible temporary solution to benchmark
teresa-ortega 8a4de4f
Check test
teresa-ortega 795d1b8
Fixed typo errors
teresa-ortega 762fc1f
validate hook signature at register time instead of resolve
teresa-ortega 524b77a
warn about dummy ctx values available to input hooks at resolve time
teresa-ortega cf56115
verify input hooks are called exactly once per resolve
teresa-ortega File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|
teresa-ortega marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| # Copyright 2026 Ekumen, Inc. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Unit tests for the input decorator in lambkin.core.decorators.""" | ||
|
|
||
| import pytest | ||
|
|
||
| from lambkin.core.ctx import Context | ||
| from lambkin.core.decorators.benchmark import benchmark | ||
| from lambkin.core.decorators.input import InputRegistry | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def variant(): | ||
| """Base variants for testing.""" | ||
| return [ | ||
| {"sensor_model": "beam", "num_particles": 10}, | ||
| ] | ||
|
|
||
|
|
||
| def test_register_returns_original_function(): | ||
| """register() returns the original function unchanged.""" | ||
| registry = InputRegistry() | ||
|
|
||
| def dataset(ctx): | ||
| return "data.mcap" | ||
|
|
||
| assert registry.register(dataset) is dataset | ||
|
|
||
|
|
||
| def test_registered_hook_name_is_preserved(): | ||
| """The ctx.inputs attribute name is the hook's __name__.""" | ||
| registry = InputRegistry() | ||
|
|
||
| def my_dataset(ctx): | ||
| return "x" | ||
|
|
||
| registry.register(my_dataset) | ||
| assert registry._hooks[0].__name__ == "my_dataset" | ||
|
|
||
|
|
||
| def test_hook_with_no_parameters_raises(): | ||
| """A hook with no parameters raises ValueError at resolve time.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def bad_hook(): | ||
| return "value" | ||
|
|
||
| registry.register(bad_hook) | ||
| with pytest.raises(ValueError, match="exactly 1 parameter"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_hook_with_extra_parameters_raises(): | ||
| """A hook with more than 1 parameter raises ValueError at resolve time.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def bad_hook(ctx, extra): | ||
| return "value" | ||
|
|
||
| registry.register(bad_hook) | ||
| with pytest.raises(ValueError, match="exactly 1 parameter"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_hook_returning_none_raises(): | ||
| """A hook that returns None raises ValueError.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def dataset(ctx): | ||
| return None | ||
|
|
||
| registry.register(dataset) | ||
| with pytest.raises(ValueError, match="None"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_hook_with_no_return_raises(): | ||
| """A hook with no return statement raises ValueError.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def dataset(ctx): | ||
| pass | ||
|
|
||
| registry.register(dataset) | ||
| with pytest.raises(ValueError, match="None"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_hook_returning_empty_string_raises(): | ||
| """A hook that returns an empty string raises ValueError.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def dataset(ctx): | ||
| return "" | ||
|
|
||
| registry.register(dataset) | ||
| with pytest.raises(ValueError, match="empty"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_hook_returning_blank_string_raises(): | ||
| """A hook that returns a whitespace-only string raises ValueError.""" | ||
| registry = InputRegistry() | ||
| ctx = Context.__new__(Context) | ||
|
|
||
| def dataset(ctx): | ||
| return " " | ||
|
|
||
| registry.register(dataset) | ||
| with pytest.raises(ValueError, match="empty"): | ||
| registry.resolve(ctx) | ||
|
|
||
|
|
||
| def test_ctx_inputs_populated_before_fn_runs(variant): | ||
| """ctx.inputs.dataset is available inside the benchmark function after resolve.""" | ||
| seen = [] | ||
|
|
||
| @benchmark(variants=variant, num_iterations=1) | ||
| def nominal(ctx): | ||
| seen.append(ctx.inputs.dataset) | ||
|
|
||
| @nominal.input | ||
| def dataset(ctx): | ||
| return "path/to/dataset.mcap" | ||
|
|
||
| nominal(output_dir="/tmp") | ||
| assert seen == ["path/to/dataset.mcap"] | ||
|
|
||
|
|
||
| def test_multiple_inputs_all_injected(variant): | ||
| """All registered inputs are injected into ctx.inputs before the benchmark runs.""" | ||
| seen = [] | ||
|
|
||
| @benchmark(variants=variant, num_iterations=1) | ||
| def nominal(ctx): | ||
| seen.append((ctx.inputs.dataset, ctx.inputs.map)) | ||
|
|
||
| @nominal.input | ||
| def dataset(ctx): | ||
| return "path/to/dataset.mcap" | ||
|
|
||
| @nominal.input | ||
| def map(ctx): | ||
| return "path/to/map.yaml" | ||
|
|
||
| nominal(output_dir="/tmp") | ||
| assert seen == [("path/to/dataset.mcap", "path/to/map.yaml")] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.