-
Notifications
You must be signed in to change notification settings - Fork 2
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
Add tests for model loading. #68
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #68 +/- ##
==========================================
+ Coverage 42.88% 43.55% +0.66%
==========================================
Files 9 9
Lines 534 535 +1
==========================================
+ Hits 229 233 +4
+ Misses 305 302 -3 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (1)
tests/test_model.py (1)
1-5
: Address TODO and review importsPlease review the imports and address the TODO comment:
- Determine which imports are actually required for the tests.
- Remove any unused imports.
- Consider if the commented-out
import mujoco
is necessary. If not, remove it; if it will be needed later, add a comment explaining why it's currently commented out.Once you've finalized the imports, remove the TODO comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Outside diff range and nitpick comments (3)
stac_mjx/controller.py (3)
214-214
: Improved model and data loading.The use of
op.mjx_load
simplifies the code and likely improves maintainability. This is a good refactoring.Consider adding a brief comment explaining what
op.mjx_load
does, especially if it's a custom utility function. This would enhance code readability for other developers.
311-311
: Consistent use of improved model and data loading.The use of
op.mjx_load
in both the main function and themjx_setup
helper function ensures consistency and simplifies the code. This refactoring aligns well with the changes made in thefit_offsets
method.For consistency, consider adding a brief comment explaining
op.mjx_load
here as well, similar to the suggestion for thefit_offsets
method.Also applies to: 323-323
214-214
: Overall improvement in code structure and maintainability.The changes in this file represent a positive refactoring effort. By introducing and consistently using
op.mjx_load
, the code becomes more standardized and easier to maintain. This refactoring aligns well with software engineering best practices and should make future modifications and debugging easier.Consider documenting the
op.mjx_load
function thoroughly in its implementation file, explaining its purpose, parameters, and return values. This will help maintain the clarity gained by this refactoring as the codebase evolves.Also applies to: 311-311, 323-323
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- stac_mjx/controller.py (3 hunks)
- stac_mjx/operations.py (1 hunks)
- tests/integration/test_model.py (1 hunks)
🧰 Additional context used
🪛 Ruff
tests/integration/test_model.py
4-4:
mujoco.mjx
imported but unusedRemove unused import:
mujoco.mjx
(F401)
🔇 Additional comments (3)
tests/integration/test_model.py (1)
1-35
: Overall assessment: Good start on model loading testsThis new file introduces tests for model loading, which aligns well with the PR objectives. The implementation provides a solid foundation for testing model loading functionality. Here's a summary of the suggestions for improvement:
- Remove the unused import of
mujoco.mjx
.- Enhance the
load_model
function by returning created objects and adding type hints.- Use a more robust way of specifying file paths in fixtures.
- Add more specific assertions in test functions for comprehensive validation.
These improvements will make the tests more robust, informative, and maintainable. Great job on adding these tests, as they will help ensure the reliability of model loading in the project!
🧰 Tools
🪛 Ruff
4-4:
mujoco.mjx
imported but unusedRemove unused import:
mujoco.mjx
(F401)
stac_mjx/operations.py (2)
Line range hint
1-17
: Summary of changes: New utility function addedThe addition of the
mjx_load
function enhances the module's functionality by providing a simple way to load MuJoCo models into the MJX framework. This change is well-integrated and doesn't disrupt existing code. It aligns with the module's purpose of providing utility functions for STAC.🧰 Tools
🪛 Ruff
8-8:
stac_mjx.utils
imported but unusedRemove unused import:
stac_mjx.utils
(F401)
11-17
: LGTM! Consider enhancing the docstring.The
mjx_load
function is a valuable addition to the module, providing a straightforward way to load MuJoCo models into MJX. The implementation is correct and aligns well with the module's purpose.Consider expanding the docstring to provide more details about the function's purpose, parameters, and return values. For example:
def mjx_load(mj_model): """ Load a MuJoCo model into MJX framework. This function takes a MuJoCo model and creates corresponding MJX model and data objects. These objects can be used for subsequent operations in the MJX framework. Args: mj_model: A MuJoCo model object to be loaded into MJX. Returns: tuple: A tuple containing: - mjx_model (mjx.Model): The created MJX model. - mjx_data (mjx.Data): The corresponding MJX data. """Let's verify the usage of this new function in the codebase:
✅ Verification successful
Function
mjx_load
usage verifiedThe
mjx_load
function is appropriately used instac_mjx/controller.py
andtests/integration/test_model.py
, ensuring correct integration within the codebase.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for usage of the new mjx_load function # Test: Search for mjx_load function calls rg --type python 'mjx_load\(' -A 5Length of output: 67
Script:
#!/bin/bash # Description: Check for usage of the new mjx_load function by searching Python files with the correct file type alias # Test: Search for mjx_load function calls using the correct file type rg --type py 'mjx_load\(' -A 5Length of output: 1754
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- tests/integration/test_model.py (1 hunks)
🧰 Additional context used
🪛 Ruff
tests/integration/test_model.py
7-7: Redefinition of unused
Path
from line 1Remove definition:
Path
(F811)
🔇 Additional comments (3)
tests/integration/test_model.py (3)
23-30
: LGTM: Robust file path handling implementedThe fixtures
rodent_model
andmouse_model
are well-implemented usingpathlib.Path
for robust file path handling. This approach addresses the previous suggestion and ensures that the paths will work correctly regardless of the current working directory when running the tests.
14-21
: 🛠️ Refactor suggestionReturn created objects and add type hints
To improve the usability and clarity of the
load_model
function, consider returning the created objects and adding type hints. This change will make the function more versatile and easier to use in various scenarios.Here's a suggested improvement:
from typing import Tuple from mujoco import MjModel, MjData def load_model(path: str) -> Tuple[MjModel, MjData]: root = mjcf.from_path(path) model = mjcf.Physics.from_mjcf_model(root).model.ptr mjx_model, mjx_data = mjx_load(model) assert mjx_model is not None assert mjx_data is not None return mjx_model, mjx_dataThis change allows the caller to use the created objects and provides clear type information.
32-38
: 🛠️ Refactor suggestionEnhance test assertions for more comprehensive validation
While the current tests verify that the models can be loaded without raising exceptions, they don't assert anything about the loaded models' properties or structure. To make the tests more robust and informative, consider adding more specific assertions.
Here's an example of how you could enhance the tests:
def test_rodent_load(rodent_model): mjx_model, mjx_data = load_model(rodent_model) assert mjx_model.nq > 0, "Model should have degrees of freedom" assert mjx_model.nv > 0, "Model should have velocities" assert len(mjx_data.qpos) == mjx_model.nq, "Data should match model dimensions" def test_mouse_load(mouse_model): mjx_model, mjx_data = load_model(mouse_model) assert mjx_model.nq > 0, "Model should have degrees of freedom" assert mjx_model.nv > 0, "Model should have velocities" assert len(mjx_data.qpos) == mjx_model.nq, "Data should match model dimensions" assert mjx_model.nmesh > 0, "Mouse model should include meshes"These additional assertions will provide more confidence that the models are loaded correctly and have the expected structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
tests/integration/test_model.py (1)
15-28
: Approve changes and suggest minor improvementThe
load_model
function looks good! It addresses the previous review comments by including more comprehensive assertions. These checks ensure that the model has degrees of freedom, velocities, and that the data dimensions match the model.One minor suggestion for improvement:
Consider returning the
mjx_model
andmjx_data
objects. This would allow tests to perform additional model-specific checks if needed. Here's a suggested modification:def load_model(path: str): # ... existing code ... assert len(mjx_data.qpos) == mjx_model.nq, "Data should match model dimensions" return mjx_model, mjx_dataThis change maintains the current functionality while providing more flexibility for future tests.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- tests/integration/test_model.py (1 hunks)
🧰 Additional context used
🪛 Ruff
tests/integration/test_model.py
1-1:
os
imported but unusedRemove unused import:
os
(F401)
9-9: Redefinition of unused
Path
from line 3Remove definition:
Path
(F811)
🔇 Additional comments (4)
tests/integration/test_model.py (4)
29-38
: Approve fixtures implementationGreat job on implementing the fixtures! This approach addresses the previous review comment about using more robust file paths. By using
PROJECT_ROOT
, you ensure that the paths are relative to the project directory, making the tests more resilient to changes in the directory structure or the location from which tests are run.The fixtures provide a clean and maintainable way to manage model paths, which can be easily reused across multiple tests.
40-43
: Approve test_rodent_load implementationThe
test_rodent_load
function is well-implemented. It effectively uses therodent_model
fixture and relies on the assertions within theload_model
function. This approach keeps the test concise and avoids code duplication, addressing the previous review comment.By leveraging the comprehensive checks in
load_model
, this test ensures that the rodent model can be loaded correctly and meets the basic requirements without unnecessary repetition of assertions.
45-46
: Approve test_mouse_load implementationThe
test_mouse_load
function is implemented consistently withtest_rodent_load
. It uses themouse_model
fixture and relies on the assertions within theload_model
function. This approach maintains a clean and consistent testing structure across different models.By keeping the tests concise and leveraging the comprehensive checks in
load_model
, you've created a maintainable and extensible testing framework for model loading.
1-46
: Summary of the reviewOverall, this new test file is well-implemented and successfully addresses the PR objectives of adding tests for model loading. Here's a summary of the key points:
- The code structure is clean and maintainable.
- Previous review comments have been addressed effectively:
- Robust file paths are used via
Path
andPROJECT_ROOT
.- Enhanced assertions are included in the
load_model
function.- Code duplication is minimized by centralizing checks in
load_model
.- Minor issues were found with imports (unused
os
and duplicatePath
).- A suggestion was made to return objects from
load_model
for potential future use.The implementation provides a solid foundation for testing model loading, with room for easy extension to cover additional models or specific model properties in the future.
🧰 Tools
🪛 Ruff
1-1:
os
imported but unusedRemove unused import:
os
(F401)
9-9: Redefinition of unused
Path
from line 3Remove definition:
Path
(F811)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
tests/integration/test_model.py (2)
17-27
: LGTM! Consider returning created objects.The
load_model
function looks good and includes appropriate assertions as suggested in previous reviews. Great job implementing the common checks!As a minor suggestion, consider returning the
mjx_model
andmjx_data
objects. This would allow the test functions to perform additional model-specific checks if needed in the future.Here's a suggested modification:
def load_model(path: str): # ... existing code ... assert len(mjx_data.qpos) == mjx_model.nq, "Data should match model dimensions" return mjx_model, mjx_data
42-47
: LGTM! Concise and effective tests.The test functions
test_rodent_load
andtest_mouse_load
are well-implemented and follow the DRY principle as suggested in previous reviews. They effectively test the loading of both models using theload_model
function.For future consideration: If you decide to return the
mjx_model
andmjx_data
from theload_model
function as suggested earlier, you could add model-specific assertions in these test functions. For example:def test_mouse_load(mouse_model): mjx_model, mjx_data = load_model(mouse_model) assert mjx_model.nmesh > 0, "Mouse model should include meshes"This would allow for more specific testing of each model's unique properties.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- tests/integration/test_model.py (1 hunks)
🧰 Additional context used
🪛 Ruff
tests/integration/test_model.py
1-1:
os
imported but unusedRemove unused import:
os
(F401)
9-9: Redefinition of unused
Path
from line 3Remove definition:
Path
(F811)
🔇 Additional comments (1)
tests/integration/test_model.py (1)
31-38
: LGTM! Well-defined fixtures.The fixtures for
rodent_model
andmouse_model
are well-implemented. They correctly use thePROJECT_ROOT
path to construct the full path to the model XML files, and the use ofstr()
ensures compatibility with functions expecting string paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks for adding the tests :)
e8ba900
to
2c2cd1a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (7)
tests/unit/test_utils.py (4)
1-5
: Remove unused importThe
Path
import frompathlib
is not used in this file. Consider removing it to keep the imports clean and relevant.Apply this change:
from stac_mjx import io -from pathlib import Path import pytest import hydra
🧰 Tools
🪛 Ruff
2-2:
pathlib.Path
imported but unusedRemove unused import:
pathlib.Path
(F401)
27-36
: LGTM: Comprehensive test for .nwb file loadingThe
test_load_nwb
function effectively tests the loading of data from .nwb files. It verifies both the data shape and the number of keypoint names, which are crucial aspects of the loading process.Consider removing or uncommenting the commented-out assertion:
# params = utils._load_params(_BASE_PATH / rodent_config) # assert params is not NoneIf this assertion is no longer needed, remove it. If it's still relevant, uncomment and update it to fit the current testing strategy.
72-80
: LGTM: Thorough test for handling insufficient keypoint namesThe
test_load_mat_less_kp_names
function effectively tests another important edge case where the configuration has fewer keypoint names than expected. The use ofpytest.raises
to check for the expectedValueError
is consistent with good testing practices.Consider parameterizing this test along with
test_load_mat_no_kp_names
to reduce code duplication:@pytest.mark.parametrize("config_override", ["rodent_config_no_kp_names", "rodent_config_less_kp_names"]) def test_load_mat_invalid_kp_names(config, config_override, mocap_mat): cfg = load_config_with_overrides( config, stac_data_path_override=mocap_mat, model_override=config_override, ) with pytest.raises(ValueError): data, sorted_kp_names = io.load_data(cfg)This approach would test both scenarios while reducing code duplication.
83-97
: LGTM: Comprehensive test for .h5 file loadingThe
test_load_h5
function effectively tests the loading of data from .h5 files. It maintains consistency with previous test cases in structure while correctly asserting different expected values for data shape and number of keypoint names.Consider removing the empty line 87 for consistency with other test functions:
def test_load_h5(config, mouse_config, mocap_h5): """ Test loading data from a .h5 file """ - cfg = load_config_with_overrides( config, stac_data_path_override=mocap_h5, model_override=mouse_config, )
stac_mjx/op_utils.py (2)
23-29
: Good addition, but consider enhancing docstring and error handling.The
mjx_load
function is a valuable addition that centralizes the MJX model loading process. However, there are a couple of suggestions for improvement:
- Enhance the docstring to provide more information about the input and output:
def mjx_load(mj_model): """Load MuJoCo model into MJX framework. Args: mj_model: A MuJoCo model object to be loaded into MJX. Returns: tuple: A tuple containing: - mjx_model (mjx.Model): The loaded MJX model. - mjx_data (mjx.Data): The corresponding MJX data. Raises: ValueError: If the input model is invalid or cannot be loaded. """
- Consider adding error handling to catch potential issues during model loading:
def mjx_load(mj_model): """Load MuJoCo model into MJX framework. ... (docstring as above) ... """ try: mjx_model = mjx.put_model(mj_model) mjx_data = mjx.make_data(mjx_model) except Exception as e: raise ValueError(f"Failed to load MuJoCo model into MJX: {str(e)}") from e return mjx_model, mjx_dataThese changes will improve the function's usability and robustness.
Line range hint
1-22
: Consider organizing imports and adding a type hint.The integration of the
mjx_load
function is well-placed and doesn't interfere with existing code. To further improve the file organization, consider:
- Grouping related imports together. For example:
import os from typing import Tuple import numpy as np from jax import numpy as jp from jax import jit from jax.lib import xla_bridge from mujoco import mjx from mujoco.mjx._src import smooth from stac_mjx import io
- Adding a type hint for the
mj_model
parameter in themjx_load
function:def mjx_load(mj_model: 'mujoco.MjModel') -> Tuple[mjx.Model, mjx.Data]:These changes will enhance code readability and provide better type information.
stac_mjx/stac.py (1)
Line range hint
326-334
: Avoid loading the model within a vectorized function to prevent performance issuesWithin the
mjx_setup
function (lines 326-334), which is called insidejax.vmap
, you're loading the Mujoco model and data usingop.mjx_load(mj_model)
(line 326). Loading the model inside a vectorized function can lead to performance degradation due to multiple redundant loads. Consider loading the model once outside the vectorized function and passing it as an argument.Apply this diff to fix the issue:
def mjx_setup(kp_data, mjx_model, mjx_data): """Create mjx model and mjx data and set offsets. Args: kp_data (_type_): _description_ + mjx_model (_type_): Pre-loaded mjx model. + mjx_data (_type_): Pre-loaded mjx data. Returns: _type_: _description_ """ - mjx_model, mjx_data = op.mjx_load(mj_model) # Set the offsets. mjx_model = op.set_site_pos(mjx_model, offsets, self._body_site_idxs) # forward is used to calculate xpos and such mjx_data = mjx.kinematics(mjx_model, mjx_data) mjx_data = mjx.com_pos(mjx_model, mjx_data) return mjx_model, mjx_data # Adjust the vmap call accordingly: - mjx_model, mjx_data = jax.vmap(mjx_setup, in_axes=(0, None))( - batched_kp_data, self._mj_model - ) + mjx_model, mjx_data = op.mjx_load(self._mj_model) + mjx_model_vmap, mjx_data_vmap = jax.vmap(mjx_setup, in_axes=(0, None, None))( + batched_kp_data, mjx_model, mjx_data + )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (4)
- stac_mjx/op_utils.py (1 hunks)
- stac_mjx/stac.py (3 hunks)
- tests/integration/test_model.py (1 hunks)
- tests/unit/test_utils.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/integration/test_model.py
🧰 Additional context used
🪛 Ruff
tests/unit/test_utils.py
2-2:
pathlib.Path
imported but unusedRemove unused import:
pathlib.Path
(F401)
🔇 Additional comments (6)
tests/unit/test_utils.py (5)
11-24
: LGTM: Well-structured helper functionThe
load_config_with_overrides
function is well-implemented. It efficiently handles optional overrides for STAC data path and model, utilizing Hydra for configuration management. This approach promotes code reuse across multiple test cases.
39-46
: LGTM: Well-implemented test for .mat file loading without labelsThe
test_load_mat_no_label3d
function effectively tests the loading of data from .mat files without a labels file. It verifies both the data shape and the number of keypoint names, maintaining consistency with the previous test case.
49-58
: LGTM: Comprehensive test for .mat file loading with labelsThe
test_load_mat_w_label3d
function effectively tests the loading of data from .mat files with a labels file. It maintains consistency with previous test cases while demonstrating the flexibility of the testing setup by using both data path and model overrides.The good use of overrides in this test case enhances the coverage of different scenarios. Well done!
61-69
: LGTM: Well-implemented test for handling missing keypoint namesThe
test_load_mat_no_kp_names
function effectively tests an important edge case where the configuration lacks keypoint names. The use ofpytest.raises
to check for the expectedValueError
is a good practice in testing exception handling.This test ensures that the system properly validates input configurations, which is crucial for maintaining data integrity and preventing silent errors.
1-97
: Overall: Excellent test suite for data loading functionalityThis test suite provides comprehensive coverage for various data loading scenarios, including different file formats (.nwb, .mat, .h5) and edge cases. The tests are well-structured, consistent, and effectively use a helper function for configuration management.
Key strengths:
- Good balance between positive test cases and error handling scenarios.
- Consistent structure across test functions.
- Effective use of pytest features (e.g.,
pytest.raises
).- Clear and descriptive test function names.
The minor suggestions for improvement (removing unused import, parameterizing similar tests, and removing an empty line) will further enhance the already high-quality test suite.
Great job on creating a robust set of unit tests for the data loading functionality!
🧰 Tools
🪛 Ruff
2-2:
pathlib.Path
imported but unusedRemove unused import:
pathlib.Path
(F401)
stac_mjx/op_utils.py (1)
Line range hint
1-29
: Overall approval: Good addition with minor suggestions.The introduction of the
mjx_load
function is a valuable addition to theop_utils.py
module. It centralizes the MJX model loading process, which aligns well with the module's purpose. The function is well-placed and doesn't interfere with existing code.Summary of suggestions:
- Enhance the docstring for
mjx_load
to provide more detailed information.- Add error handling to
mjx_load
for improved robustness.- Consider organizing imports for better readability.
- Add a type hint for the
mj_model
parameter inmjx_load
.These minor improvements will further enhance the code quality and maintainability. Great work overall!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just had the one question!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious--what makes this an integration test?
unit
sub-directory in thetests
directory.