mlcflow 1.2.6__tar.gz → 1.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mlcflow-1.2.6 → mlcflow-1.2.7}/PKG-INFO +1 -1
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/main.py +2 -2
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/repo_action.py +192 -31
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/script_action.py +2 -1
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/PKG-INFO +1 -1
- {mlcflow-1.2.6 → mlcflow-1.2.7}/pyproject.toml +1 -1
- mlcflow-1.2.7/tests/test_script_action_apptainer.py +54 -0
- mlcflow-1.2.6/tests/test_script_action_apptainer.py +0 -29
- {mlcflow-1.2.6 → mlcflow-1.2.7}/LICENSE.md +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/README.md +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/__init__.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/__main__.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/action.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/action_factory.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/cache_action.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/cfg_action.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/error_codes.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/experiment_action.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/index.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/item.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/logger.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/meta_schema.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/repo.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlc/utils.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/SOURCES.txt +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/dependency_links.txt +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/entry_points.txt +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/requires.txt +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/mlcflow.egg-info/top_level.txt +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/setup.cfg +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/tests/test_action_invalid_meta_entries.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/tests/test_cache_mark_tmp.py +0 -0
- {mlcflow-1.2.6 → mlcflow-1.2.7}/tests/test_mlcflow_unix_installer.py +0 -0
|
@@ -576,7 +576,7 @@ def main():
|
|
|
576
576
|
else:
|
|
577
577
|
pre_args.target, pre_args.action = pre_args.action, None
|
|
578
578
|
actions = get_action(pre_args.target, default_parent)
|
|
579
|
-
help_text += actions.__doc__
|
|
579
|
+
help_text += actions.__doc__ or ""
|
|
580
580
|
# iterate through every method
|
|
581
581
|
for method_name, method in inspect.getmembers(
|
|
582
582
|
actions.__class__, inspect.isfunction):
|
|
@@ -588,7 +588,7 @@ def main():
|
|
|
588
588
|
action_name = pre_args.action.replace("-", "_")
|
|
589
589
|
try:
|
|
590
590
|
method = getattr(actions, action_name)
|
|
591
|
-
help_text += actions.__doc__
|
|
591
|
+
help_text += actions.__doc__ or ""
|
|
592
592
|
if method.__doc__:
|
|
593
593
|
help_text += method.__doc__
|
|
594
594
|
except AttributeError:
|
|
@@ -40,11 +40,152 @@ class RepoAction(Action):
|
|
|
40
40
|
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
+
GIT_MISSING_BRANCH_PHRASE = "did not match any file(s) known to git"
|
|
44
|
+
GIT_FAST_FORWARD_FAILURE_PHRASE = "not possible to fast-forward"
|
|
45
|
+
|
|
43
46
|
def __init__(self, parent=None):
|
|
44
47
|
# super().__init__(parent)
|
|
45
48
|
self.parent = parent
|
|
46
49
|
self.__dict__.update(vars(parent))
|
|
47
50
|
|
|
51
|
+
def _build_pull_command(self, repo_path, branch=None, clone_depth=None,
|
|
52
|
+
fast_forward_only=False):
|
|
53
|
+
pull_command = ['git', '-C', repo_path, 'pull']
|
|
54
|
+
if fast_forward_only:
|
|
55
|
+
pull_command.append('--ff-only')
|
|
56
|
+
if clone_depth is not None:
|
|
57
|
+
if self._is_shallow_repo(repo_path):
|
|
58
|
+
pull_command.extend(['--depth', str(clone_depth)])
|
|
59
|
+
else:
|
|
60
|
+
logger.warning(
|
|
61
|
+
f"--depth/--shallow ignored for pull on non-shallow repo {repo_path}. "
|
|
62
|
+
"Re-clone with --shallow to create a shallow copy."
|
|
63
|
+
)
|
|
64
|
+
# Preserve the historical existing-repo behavior of a plain
|
|
65
|
+
# `git pull` by default. The branch argument is only forwarded to
|
|
66
|
+
# `git pull` when the internal strict path explicitly opts into
|
|
67
|
+
# fast-forward-only updates.
|
|
68
|
+
if branch and fast_forward_only:
|
|
69
|
+
pull_command.extend(['origin', branch])
|
|
70
|
+
return pull_command
|
|
71
|
+
|
|
72
|
+
def _checkout_pull_branch(self, repo_path, branch):
|
|
73
|
+
"""Ensure *branch* is checked out locally before a strict pull.
|
|
74
|
+
|
|
75
|
+
First tries to checkout an existing local branch. If that fails, fetches
|
|
76
|
+
the branch from origin and creates a new tracking branch. Raises
|
|
77
|
+
RuntimeError with contextual guidance when the branch cannot be prepared.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
repo_path: Local repository path.
|
|
81
|
+
branch: Branch name to prepare before pulling.
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
RuntimeError: If the branch cannot be fetched or checked out.
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
subprocess.run(
|
|
88
|
+
['git', '-C', repo_path, 'checkout', branch],
|
|
89
|
+
capture_output=True,
|
|
90
|
+
text=True,
|
|
91
|
+
check=True)
|
|
92
|
+
except subprocess.CalledProcessError as checkout_error:
|
|
93
|
+
checkout_error_text = self._subprocess_error_message(
|
|
94
|
+
checkout_error)
|
|
95
|
+
lowered_checkout_error = checkout_error_text.lower()
|
|
96
|
+
# Git uses the same exit code for many checkout failures, so we
|
|
97
|
+
# only fall back to fetch+track when stderr includes both
|
|
98
|
+
# "pathspec" and Git's usual missing-ref phrase
|
|
99
|
+
# "did not match any file(s) known to git".
|
|
100
|
+
missing_local_branch = (
|
|
101
|
+
"pathspec" in lowered_checkout_error
|
|
102
|
+
and self.GIT_MISSING_BRANCH_PHRASE in lowered_checkout_error
|
|
103
|
+
)
|
|
104
|
+
if not missing_local_branch:
|
|
105
|
+
raise RuntimeError(
|
|
106
|
+
f"Cannot switch to branch '{branch}' in {repo_path}: "
|
|
107
|
+
f"{checkout_error_text}"
|
|
108
|
+
) from checkout_error
|
|
109
|
+
try:
|
|
110
|
+
subprocess.run(
|
|
111
|
+
['git', '-C', repo_path, 'fetch', 'origin', branch],
|
|
112
|
+
capture_output=True,
|
|
113
|
+
text=True,
|
|
114
|
+
check=True)
|
|
115
|
+
except subprocess.CalledProcessError as fetch_error:
|
|
116
|
+
raise RuntimeError(
|
|
117
|
+
f"Failed to fetch branch '{branch}' in {repo_path}: "
|
|
118
|
+
f"{self._subprocess_error_message(fetch_error)}. "
|
|
119
|
+
"Ensure the branch exists on origin and that the repository is reachable."
|
|
120
|
+
) from fetch_error
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
subprocess.run(
|
|
124
|
+
['git', '-C', repo_path, 'checkout', '-b',
|
|
125
|
+
branch, '--track', f'origin/{branch}'],
|
|
126
|
+
capture_output=True,
|
|
127
|
+
text=True,
|
|
128
|
+
check=True)
|
|
129
|
+
except subprocess.CalledProcessError as tracking_error:
|
|
130
|
+
raise RuntimeError(
|
|
131
|
+
f"Initial checkout of '{branch}' failed in {repo_path}. "
|
|
132
|
+
"After fetching from origin, creating a tracking branch also failed. "
|
|
133
|
+
f"Initial error: {checkout_error_text}. "
|
|
134
|
+
f"Tracking branch error: {self._subprocess_error_message(tracking_error)}. "
|
|
135
|
+
"Check that the branch name is correct and that your local checkout can track origin."
|
|
136
|
+
) from tracking_error
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _format_stash_restore_guidance(repo_path):
|
|
140
|
+
return (
|
|
141
|
+
f"Local changes remain in stash. Please run `git -C {repo_path} stash apply` "
|
|
142
|
+
"after resolving pull issues."
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _format_pull_error(self, repo_path, error_message, stash_created=False,
|
|
146
|
+
force=False, failure_phase="git pull"):
|
|
147
|
+
"""Format a pull failure message.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
repo_path: Repository path being updated.
|
|
151
|
+
error_message: Original stderr/stdout-derived git failure text.
|
|
152
|
+
stash_created: Whether local changes were stashed for a force pull.
|
|
153
|
+
force: Whether the failure happened on a force-pull path.
|
|
154
|
+
failure_phase: Phase label such as ``git pull`` or
|
|
155
|
+
``branch checkout``.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
A user-facing error string with optional recovery guidance.
|
|
159
|
+
"""
|
|
160
|
+
prefix = "Force pull failed" if force else "Pull failed"
|
|
161
|
+
if failure_phase:
|
|
162
|
+
prefix = f"{prefix} during {failure_phase}"
|
|
163
|
+
|
|
164
|
+
resolution = ""
|
|
165
|
+
lowered_error = error_message.lower()
|
|
166
|
+
# Git reports ff-only failures via stderr text instead of a distinct
|
|
167
|
+
# exit code, so use this case-insensitive substring from the standard
|
|
168
|
+
# "Not possible to fast-forward, aborting." message to add guidance.
|
|
169
|
+
if self.GIT_FAST_FORWARD_FAILURE_PHRASE in lowered_error:
|
|
170
|
+
resolution = (
|
|
171
|
+
" Check whether the local and remote branches have diverged "
|
|
172
|
+
"and reconcile them manually before retrying."
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if stash_created:
|
|
176
|
+
return (
|
|
177
|
+
f"{prefix} for {repo_path}. "
|
|
178
|
+
f"{self._format_stash_restore_guidance(repo_path)} "
|
|
179
|
+
f"Details: {error_message}{resolution}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return f"{prefix} for {repo_path}: {error_message}{resolution}"
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def _subprocess_error_message(error):
|
|
186
|
+
"""Return the most helpful message from a subprocess-related error."""
|
|
187
|
+
return (error.stderr or error.stdout or str(error)).strip()
|
|
188
|
+
|
|
48
189
|
def add(self, run_args):
|
|
49
190
|
"""
|
|
50
191
|
####################################################################################################################
|
|
@@ -337,7 +478,7 @@ class RepoAction(Action):
|
|
|
337
478
|
|
|
338
479
|
def pull_repo(self, repo_url, branch=None, checkout=None, tag=None,
|
|
339
480
|
pat=None, ssh=None, ignore_on_conflict=False, repo_path=None, force=False,
|
|
340
|
-
shallow=False, depth=None, extra_git_args=None):
|
|
481
|
+
shallow=False, depth=None, extra_git_args=None, fast_forward_only=False):
|
|
341
482
|
|
|
342
483
|
# Determine the checkout path from environment or default
|
|
343
484
|
repo_base_path = self.repos_path # either the value will be from 'MLC_REPOS'
|
|
@@ -468,30 +609,33 @@ class RepoAction(Action):
|
|
|
468
609
|
logger.info(
|
|
469
610
|
"Pulling latest changes...")
|
|
470
611
|
try:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if self._is_shallow_repo(repo_path):
|
|
474
|
-
pull_command += ['--depth', str(clone_depth)]
|
|
475
|
-
else:
|
|
476
|
-
logger.warning(
|
|
477
|
-
f"--depth/--shallow ignored for pull on non-shallow repo {repo_path}. "
|
|
478
|
-
"Re-clone with --shallow to create a shallow copy."
|
|
479
|
-
)
|
|
612
|
+
if fast_forward_only and branch:
|
|
613
|
+
self._checkout_pull_branch(repo_path, branch)
|
|
480
614
|
subprocess.run(
|
|
481
|
-
|
|
615
|
+
self._build_pull_command(
|
|
616
|
+
repo_path, branch, clone_depth, fast_forward_only),
|
|
482
617
|
capture_output=True,
|
|
483
618
|
text=True,
|
|
484
619
|
check=True)
|
|
620
|
+
except RuntimeError as e:
|
|
621
|
+
return {
|
|
622
|
+
"return": 1,
|
|
623
|
+
"error": self._format_pull_error(
|
|
624
|
+
repo_path,
|
|
625
|
+
str(e),
|
|
626
|
+
stash_created=stash_created,
|
|
627
|
+
force=True,
|
|
628
|
+
failure_phase="branch checkout")
|
|
629
|
+
}
|
|
485
630
|
except subprocess.CalledProcessError as e:
|
|
486
|
-
pull_error =
|
|
487
|
-
if stash_created:
|
|
488
|
-
return {
|
|
489
|
-
"return": 1,
|
|
490
|
-
"error": f"Force pull failed during git pull for {repo_path}. Local changes remain in stash. Please run `git -C {repo_path} stash apply` after resolving pull issues. Details: {pull_error}"
|
|
491
|
-
}
|
|
631
|
+
pull_error = self._subprocess_error_message(e)
|
|
492
632
|
return {
|
|
493
633
|
"return": 1,
|
|
494
|
-
"error":
|
|
634
|
+
"error": self._format_pull_error(
|
|
635
|
+
repo_path,
|
|
636
|
+
pull_error,
|
|
637
|
+
stash_created=stash_created,
|
|
638
|
+
force=True)
|
|
495
639
|
}
|
|
496
640
|
logger.info("Repository successfully pulled.")
|
|
497
641
|
|
|
@@ -536,16 +680,28 @@ class RepoAction(Action):
|
|
|
536
680
|
else:
|
|
537
681
|
logger.info(
|
|
538
682
|
"No local changes detected. Pulling latest changes...")
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
)
|
|
548
|
-
|
|
683
|
+
try:
|
|
684
|
+
if fast_forward_only and branch:
|
|
685
|
+
self._checkout_pull_branch(repo_path, branch)
|
|
686
|
+
subprocess.run(
|
|
687
|
+
self._build_pull_command(
|
|
688
|
+
repo_path, branch, clone_depth, fast_forward_only),
|
|
689
|
+
capture_output=True,
|
|
690
|
+
text=True,
|
|
691
|
+
check=True)
|
|
692
|
+
except RuntimeError as e:
|
|
693
|
+
return {
|
|
694
|
+
"return": 1,
|
|
695
|
+
"error": self._format_pull_error(
|
|
696
|
+
repo_path, str(e), failure_phase="branch checkout")
|
|
697
|
+
}
|
|
698
|
+
except subprocess.CalledProcessError as e:
|
|
699
|
+
pull_error = self._subprocess_error_message(e)
|
|
700
|
+
return {
|
|
701
|
+
"return": 1,
|
|
702
|
+
"error": self._format_pull_error(
|
|
703
|
+
repo_path, pull_error)
|
|
704
|
+
}
|
|
549
705
|
logger.info("Repository successfully pulled.")
|
|
550
706
|
|
|
551
707
|
if tag:
|
|
@@ -585,6 +741,8 @@ class RepoAction(Action):
|
|
|
585
741
|
|
|
586
742
|
return {"return": 0}
|
|
587
743
|
|
|
744
|
+
except RuntimeError as e:
|
|
745
|
+
return {'return': 1, 'error': str(e)}
|
|
588
746
|
except subprocess.CalledProcessError as e:
|
|
589
747
|
return {'return': 1, 'error': f"Git command failed: {e}"}
|
|
590
748
|
except Exception as e:
|
|
@@ -610,7 +768,7 @@ class RepoAction(Action):
|
|
|
610
768
|
|
|
611
769
|
|
|
612
770
|
- `--checkout <commit_sha>`: Checks out a specific commit after cloning (applicable when the repository exists locally).
|
|
613
|
-
- `--branch <branch_name>`: Checks out a specific branch
|
|
771
|
+
- `--branch <branch_name>`: Checks out a specific branch while cloning a new repository. When strict fast-forward-only pulls are requested for an existing checkout, it also selects the local branch to switch to before pulling `origin/<branch>`.
|
|
614
772
|
- `--tag <release_tag>`: Checks out a particular release tag.
|
|
615
773
|
- `--pat <access_token>` or `--ssh`: Clones a private repository using a personal access token or SSH.
|
|
616
774
|
- `--force`: For existing repositories with local tracked changes, stashes changes before pull and reapplies them after pull.
|
|
@@ -651,7 +809,8 @@ class RepoAction(Action):
|
|
|
651
809
|
'force'),
|
|
652
810
|
shallow=run_args.get('shallow', False),
|
|
653
811
|
depth=run_args.get('depth'),
|
|
654
|
-
extra_git_args=run_args.get('extra_git_args')
|
|
812
|
+
extra_git_args=run_args.get('extra_git_args'),
|
|
813
|
+
fast_forward_only=run_args.get('fast_forward_only', False))
|
|
655
814
|
if res['return'] > 0:
|
|
656
815
|
return res
|
|
657
816
|
else:
|
|
@@ -666,6 +825,7 @@ class RepoAction(Action):
|
|
|
666
825
|
shallow = run_args.get('shallow', False)
|
|
667
826
|
depth = run_args.get('depth')
|
|
668
827
|
extra_git_args = run_args.get('extra_git_args')
|
|
828
|
+
fast_forward_only = run_args.get('fast_forward_only', False)
|
|
669
829
|
|
|
670
830
|
if sum(bool(var) for var in [branch, checkout, tag]) > 1:
|
|
671
831
|
return {
|
|
@@ -682,7 +842,8 @@ class RepoAction(Action):
|
|
|
682
842
|
force=force,
|
|
683
843
|
shallow=shallow,
|
|
684
844
|
depth=depth,
|
|
685
|
-
extra_git_args=extra_git_args
|
|
845
|
+
extra_git_args=extra_git_args,
|
|
846
|
+
fast_forward_only=fast_forward_only)
|
|
686
847
|
if res['return'] > 0:
|
|
687
848
|
return res
|
|
688
849
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import tempfile
|
|
2
|
+
import unittest
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
from mlc.script_action import ScriptAction
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _Parent:
|
|
9
|
+
def __init__(self, repos_path=None):
|
|
10
|
+
self.repos_path = repos_path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ScriptActionApptainerTest(unittest.TestCase):
|
|
14
|
+
def test_apptainer_delegates_to_script_module(self):
|
|
15
|
+
action = ScriptAction(_Parent(tempfile.gettempdir()))
|
|
16
|
+
run_args = {"tags": "detect,os"}
|
|
17
|
+
expected = {"return": 0}
|
|
18
|
+
|
|
19
|
+
with patch.object(
|
|
20
|
+
ScriptAction,
|
|
21
|
+
"call_script_module_function",
|
|
22
|
+
return_value=expected) as call_script_module_function:
|
|
23
|
+
result = action.apptainer(run_args)
|
|
24
|
+
|
|
25
|
+
self.assertEqual(result, expected)
|
|
26
|
+
call_script_module_function.assert_called_once_with(
|
|
27
|
+
"apptainer", run_args)
|
|
28
|
+
|
|
29
|
+
def test_auto_pull_uses_fast_forward_only_for_mlperf_automations(self):
|
|
30
|
+
with tempfile.TemporaryDirectory() as repos_path:
|
|
31
|
+
action = ScriptAction(_Parent(repos_path))
|
|
32
|
+
|
|
33
|
+
with patch.object(
|
|
34
|
+
ScriptAction,
|
|
35
|
+
"find_target_folder",
|
|
36
|
+
return_value=None), \
|
|
37
|
+
patch.object(
|
|
38
|
+
ScriptAction,
|
|
39
|
+
"access",
|
|
40
|
+
return_value={"return": 1, "error": "pull failed"}) as access:
|
|
41
|
+
result = action.call_script_module_function("run", {})
|
|
42
|
+
|
|
43
|
+
self.assertEqual(result["return"], 1)
|
|
44
|
+
access.assert_called_once_with({
|
|
45
|
+
"automation": "repo",
|
|
46
|
+
"action": "pull",
|
|
47
|
+
"repo": "mlcommons@mlperf-automations",
|
|
48
|
+
"branch": "dev",
|
|
49
|
+
"fast_forward_only": True
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
unittest.main()
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from unittest.mock import patch
|
|
3
|
-
|
|
4
|
-
from mlc.script_action import ScriptAction
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class _Parent:
|
|
8
|
-
pass
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class ScriptActionApptainerTest(unittest.TestCase):
|
|
12
|
-
def test_apptainer_delegates_to_script_module(self):
|
|
13
|
-
action = ScriptAction(_Parent())
|
|
14
|
-
run_args = {"tags": "detect,os"}
|
|
15
|
-
expected = {"return": 0}
|
|
16
|
-
|
|
17
|
-
with patch.object(
|
|
18
|
-
ScriptAction,
|
|
19
|
-
"call_script_module_function",
|
|
20
|
-
return_value=expected) as call_script_module_function:
|
|
21
|
-
result = action.apptainer(run_args)
|
|
22
|
-
|
|
23
|
-
self.assertEqual(result, expected)
|
|
24
|
-
call_script_module_function.assert_called_once_with(
|
|
25
|
-
"apptainer", run_args)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if __name__ == "__main__":
|
|
29
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|