-
Notifications
You must be signed in to change notification settings - Fork 7
All/task/devopsdsc 868 use work dir #530
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
base: main
Are you sure you want to change the base?
Conversation
5d0578d to
b2c5f10
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.
Pull request overview
This PR introduces a "_work" copy mechanism for test case input directories, separating the working directory used for test execution from the tracked DVC directory. This prevents test execution from modifying tracked files.
Changes:
- Added
DirectoryStatedataclass to capture directory snapshots using UTC timestamps instead of raw float values - Implemented
__copy_to_work_foldermethod to create and manage work directory copies of input directories - Modified path handling to use "_work" suffixed paths for test execution
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| test/deltares_testbench/src/suite/test_case.py | Refactored directory state tracking with DirectoryState dataclass and UTC timestamps |
| test/deltares_testbench/src/suite/test_set_runner.py | Added work folder copy logic and updated path handling to use "_work" suffix |
| test/deltares_testbench/test/suite/test_TestCase.py | Added test for runfile changes detection |
| test/deltares_testbench/test/suite/test_ComparisonRunner.py | Added comprehensive tests for work folder creation, copying, and overwriting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…irectory from the work directory
8e3898e to
84a2ff8
Compare
savente93
left a 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.
couple of questions and comments but nothing major
|
|
||
| def __copy_to_work_folder(self, local_path: str, logger: ILogger) -> None: | ||
| """Copy downloaded files to work folder if needed.""" | ||
| copy_path = local_path + "_work" |
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.
| copy_path = local_path + "_work" | |
| copy_path = Path(local_path) / "_work" |
| """Set absolute paths on the config based on location type.""" | ||
| if location_type == PathType.INPUT: | ||
| config.absolute_test_case_path = local_path | ||
| config.absolute_test_case_path = local_path + "_work" |
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.
I'd advie to use Path here as well if possible
| @dataclass | ||
| class DirectoryState: | ||
| """Snapshot of a directory's state used to detect added/changed files. | ||
|
|
||
| Attributes | ||
| ---------- | ||
| files : Dict[str, datetime] | ||
| Mapping of filename to last modification time (UTC). | ||
| size : int | ||
| Total size in bytes of all files in the directory at snapshot time. | ||
| """ | ||
|
|
||
| files: Dict[str, datetime] = field(default_factory=dict) | ||
| size: int = 0 | ||
|
|
||
|
|
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.
I'm not sure I understand the point of this class. I see the data gets collected, but I don't see it being used anywhere. Could you explain the thought process behind it?
| ) | ||
| logger = MagicMock(spec=ConsoleLogger) | ||
| runner = ComparisonRunner(settings, logger) | ||
| run_data = RunData(1, 10) |
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.
| run_data = RunData(1, 10) | |
| # get the data of test case nr 10 | |
| run_data = RunData(1, 10) |
For someone unfamiliar with the code base (like me) I think this comment, or something like it would be very useful
| runner.run_test_case(config=config, run_data=run_data) | ||
|
|
||
| # Assert | ||
| assert fs.exists(expected_work_path) |
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.
if you want to be thurough you might want to test that the coppied location also has the correct files, but this might be more work than it is worth, so I'll leave it up to you whether you want to do this.
| run_data = RunData(1, 1) | ||
|
|
||
| expected_local_input_path = "/cases/win64/Name_1" | ||
| expected_work_path = expected_local_input_path + "_work" |
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.
especially if these are windows cases (as I assume from the win64 in the path) then it's important to use Path objects here
| expected_local_input_path = "/cases/win64/Name_1" | ||
| expected_work_path = expected_local_input_path + "_work" |
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.
Again, use Path objects here
| shutil.copytree(local_path, copy_path, symlinks=False, ignore_dangling_symlinks=True) | ||
| else: | ||
| os.makedirs(os.path.dirname(copy_path) or ".", exist_ok=True) | ||
| shutil.copy2(local_path, copy_path) |
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.
why copy2? what's the difference with copytree?
…viour is captured.
6bd0885 to
0611086
Compare
| logger.debug(f"Copying input from {local_path} to {copy_path}") | ||
| if os.path.isdir(local_path): | ||
| shutil.copytree(local_path, copy_path, symlinks=False, ignore_dangling_symlinks=True) | ||
| else: |
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.
I think we can rule out that local_path is not a directory, right? The input of a case should always be a directory. Maybe do a check at the start of this method: local_path.is_dir() and raise the builtin NotADirectoryError. Then you can skip this edgecase.
| raise TestBenchError(error_message) from e | ||
|
|
||
| def __copy_to_work_folder(self, local_path: str, logger: ILogger) -> None: | ||
| """Copy downloaded files to work folder if needed.""" |
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.
I agree that local_path should be a Path instead of a str. What if there's a trailing slash in the string in some config files or something. Then you get <path>/_work, or maybe <path>\_work depending on the platform. The os.path functionality can all be replaced by Path methods. Path implements the PathLike protocol, which shutil.copytree accepts as arguments. So you don't even need to convert the Paths to str before passing them to shutil.copytree
| """Set absolute paths on the config based on location type.""" | ||
| if location_type == PathType.INPUT: | ||
| config.absolute_test_case_path = local_path | ||
| config.absolute_test_case_path = local_path + "_work" |
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.
config.absolute_test_case_path is a str for historical reasons, right? I suggest something like this to avoid problems with path separators.
local = Path(local_path)
config.absolute_test_case_path = str(local.parent / (local.name + "_work"))
This PR introduces the "_work" copy of the test case input directory, which is used for test execution. This will be used to separate the work dir that executes the tests from the tracked dvc directory. The method of interest is
__copy_to_work_folder. The rest are code improvements.