Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
fslpy
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Analyze
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
FSL
fslpy
Commits
c1a2c2e5
Commit
c1a2c2e5
authored
4 years ago
by
Michiel Cottaar
Browse files
Options
Downloads
Patches
Plain Diff
BUG: Make SubmitParams compatible with existing code
Also added test for add_to_parser
parent
651cd844
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
fsl/utils/fslsub.py
+55
-88
55 additions, 88 deletions
fsl/utils/fslsub.py
tests/test_fslsub.py
+41
-0
41 additions, 0 deletions
tests/test_fslsub.py
with
96 additions
and
88 deletions
fsl/utils/fslsub.py
+
55
−
88
View file @
c1a2c2e5
...
@@ -41,9 +41,7 @@ Example usage, building a short pipeline::
...
@@ -41,9 +41,7 @@ Example usage, building a short pipeline::
from
six
import
BytesIO
from
six
import
BytesIO
import
subprocess
as
sp
import
os.path
as
op
import
os.path
as
op
import
os
import
glob
import
glob
import
time
import
time
import
pickle
import
pickle
...
@@ -52,10 +50,9 @@ import tempfile
...
@@ -52,10 +50,9 @@ import tempfile
import
logging
import
logging
import
importlib
import
importlib
from
dataclasses
import
dataclass
,
asdict
from
dataclasses
import
dataclass
,
asdict
from
typing
import
Optional
,
Collection
,
Union
from
typing
import
Optional
,
Collection
,
Union
,
Tuple
import
argparse
import
argparse
import
warnings
import
warnings
from
subprocess
import
run
,
PIPE
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -76,9 +73,10 @@ class SubmitParams(object):
...
@@ -76,9 +73,10 @@ class SubmitParams(object):
ram
:
Optional
[
int
]
=
None
ram
:
Optional
[
int
]
=
None
logdir
:
Optional
[
str
]
=
None
logdir
:
Optional
[
str
]
=
None
mail_options
:
Optional
[
str
]
=
None
mail_options
:
Optional
[
str
]
=
None
flags
:
Optional
[
str
]
=
None
flags
:
bool
=
False
multi_threaded
:
Optional
[
Tuple
[
str
,
str
]]
=
None
verbose
:
bool
=
False
verbose
:
bool
=
False
env
ironment
:
dict
=
None
env
:
dict
=
None
cmd_line_flags
=
{
cmd_line_flags
=
{
'
-T
'
:
'
minutes
'
,
'
-T
'
:
'
minutes
'
,
...
@@ -90,12 +88,11 @@ class SubmitParams(object):
...
@@ -90,12 +88,11 @@ class SubmitParams(object):
'
-R
'
:
'
ram
'
,
'
-R
'
:
'
ram
'
,
'
-l
'
:
'
logdir
'
,
'
-l
'
:
'
logdir
'
,
'
-m
'
:
'
mail_options
'
,
'
-m
'
:
'
mail_options
'
,
'
-F
'
:
'
flags
'
,
}
}
def
__post_init__
(
self
):
def
__post_init__
(
self
):
if
self
.
env
ironment
is
None
:
if
self
.
env
is
None
:
self
.
env
ironment
=
{}
self
.
env
=
{}
def
as_flags
(
self
,
):
def
as_flags
(
self
,
):
"""
"""
...
@@ -111,32 +108,32 @@ class SubmitParams(object):
...
@@ -111,32 +108,32 @@ class SubmitParams(object):
res
.
extend
((
key
,
str
(
getattr
(
self
,
value
))))
res
.
extend
((
key
,
str
(
getattr
(
self
,
value
))))
if
self
.
verbose
:
if
self
.
verbose
:
res
.
append
(
'
-v
'
)
res
.
append
(
'
-v
'
)
if
self
.
flags
:
res
.
append
(
'
-F
'
)
if
self
.
multi_threaded
:
res
.
extend
((
"
-s
"
,
'
,
'
.
join
(
self
.
multi_threaded
)))
if
self
.
wait_for
is
not
None
and
len
(
_flatten_job_ids
(
self
.
wait_for
))
>
0
:
if
self
.
wait_for
is
not
None
and
len
(
_flatten_job_ids
(
self
.
wait_for
))
>
0
:
res
.
extend
((
'
-j
'
,
_flatten_job_ids
(
self
.
wait_for
)))
res
.
extend
((
'
-j
'
,
_flatten_job_ids
(
self
.
wait_for
)))
return
tuple
(
res
)
return
tuple
(
res
)
def
__str__
(
self
):
def
__str__
(
self
):
return
f
'
SubmitParams(
{
"
"
.
join
(
self
.
as_flags
())
}
)
'
return
'
SubmitParams({
})
'
.
format
(
"
"
.
join
(
self
.
as_flags
())
)
def
__call__
(
self
,
*
c
m
d
,
**
kwargs
):
def
__call__
(
self
,
*
c
omman
d
,
**
kwargs
):
"""
"""
Submits the command to the cluster.
Submits the command to the cluster.
:param c
m
d: string or tuple of strings with the command to submit
:param c
omman
d: string or tuple of strings with the command to submit
:param kwargs: Keyword arguments can override any parameters set in self
:param kwargs: Keyword arguments can override any parameters set in self
:return: job ID
:return: job ID
"""
"""
from
fsl.utils.run
import
prepareArgs
from
fsl.utils.run
import
prepareArgs
,
runfsl
runner
=
self
.
update
(
**
kwargs
)
runner
=
self
.
update
(
**
kwargs
)
cmd
=
prepareArgs
(
cmd
)
command
=
prepareArgs
(
command
)
log
.
debug
(
'
'
.
join
((
'
fsl_sub
'
,
)
+
tuple
(
runner
.
as_flags
())
+
tuple
(
cmd
)))
fsl_sub_cmd
=
'
'
.
join
((
'
fsl_sub
'
,
)
+
tuple
(
runner
.
as_flags
())
+
tuple
(
command
))
env
=
dict
(
os
.
environ
)
log
.
debug
(
fsl_sub_cmd
)
env
.
update
(
runner
.
environment
)
jobid
=
runfsl
(
fsl_sub_cmd
,
env
=
runner
.
env
).
strip
()
jobid
=
run
(
log
.
debug
(
'
Job submitted as {}
'
.
format
(
jobid
))
(
'
fsl_sub
'
,
)
+
tuple
(
runner
.
as_flags
())
+
tuple
(
cmd
),
stdout
=
PIPE
,
check
=
True
,
env
=
env
,
).
stdout
.
decode
().
strip
()
log
.
debug
(
f
'
Job submitted as
{
jobid
}
'
)
return
jobid
return
jobid
def
update
(
self
,
**
kwargs
):
def
update
(
self
,
**
kwargs
):
...
@@ -148,22 +145,24 @@ class SubmitParams(object):
...
@@ -148,22 +145,24 @@ class SubmitParams(object):
return
SubmitParams
(
**
values
)
return
SubmitParams
(
**
values
)
@classmethod
@classmethod
def
add_to_parser
(
cls
,
parser
:
argparse
.
ArgumentParser
,
as_group
=
'
fsl_sub commands
'
,
skip
=
()):
def
add_to_parser
(
cls
,
parser
:
argparse
.
ArgumentParser
,
as_group
=
'
fsl_sub commands
'
,
include
=
(
'
wait_for
'
,
'
logdir
'
,
'
email
'
,
'
mail_options
'
)):
"""
"""
Adds submission parameters to the parser
Adds submission parameters to the parser
:param parser: parser that should understand submission commands
:param parser: parser that should understand submission commands
:param as_group: add as a new group
:param as_group: add as a new group
:param skip: sequence of argument flags/names that should not be added to the parser
:param include: sequence of argument flags/names that should be added to the parser
(set to None to include everything)
:return: the group the arguments got added to
:return: the group the arguments got added to
"""
"""
from
fsl.utils.run
import
runfsl
,
prepareArgs
from
fsl.utils.run
import
runfsl
try
:
try
:
fsl_sub_run
=
runfsl
(
[
'
fsl_sub
'
]
)
fsl_sub_run
,
_
=
runfsl
(
'
fsl_sub
'
,
exitcode
=
True
)
except
FileNotFoundError
:
except
FileNotFoundError
:
warnings
.
warn
(
'
fsl_sub was not found
'
)
warnings
.
warn
(
'
fsl_sub was not found
'
)
return
return
doc_lines
=
fsl_sub_run
.
stdout
.
decode
().
splitlines
()
doc_lines
=
fsl_sub_run
.
splitlines
()
nspaces
=
1
nspaces
=
1
for
line
in
doc_lines
:
for
line
in
doc_lines
:
if
len
(
line
.
strip
())
>
0
:
if
len
(
line
.
strip
())
>
0
:
...
@@ -174,9 +173,8 @@ class SubmitParams(object):
...
@@ -174,9 +173,8 @@ class SubmitParams(object):
group
=
parser
.
add_argument_group
(
as_group
)
group
=
parser
.
add_argument_group
(
as_group
)
else
:
else
:
group
=
parser
group
=
parser
for
flag
,
value
in
cls
.
cmd_line_flags
.
items
():
if
value
in
skip
or
flag
in
skip
:
def
get_explanation
(
flag
):
continue
explanation
=
None
explanation
=
None
for
line
in
doc_lines
:
for
line
in
doc_lines
:
if
explanation
is
not
None
and
len
(
line
.
strip
())
>
0
and
line
.
strip
()[
0
]
!=
'
-
'
:
if
explanation
is
not
None
and
len
(
line
.
strip
())
>
0
and
line
.
strip
()[
0
]
!=
'
-
'
:
...
@@ -185,35 +183,38 @@ class SubmitParams(object):
...
@@ -185,35 +183,38 @@ class SubmitParams(object):
break
break
elif
line
.
strip
().
startswith
(
flag
):
elif
line
.
strip
().
startswith
(
flag
):
explanation
=
[
line
[
nspaces
:].
strip
()]
explanation
=
[
line
[
nspaces
:].
strip
()]
explanation
=
'
'
.
join
(
explanation
)
if
len
(
explanation
)
==
0
:
return
'
documentation not found
'
return
'
'
.
join
(
explanation
)
for
flag
,
value
in
cls
.
cmd_line_flags
.
items
():
if
include
is
not
None
and
value
not
in
include
and
flag
not
in
include
:
continue
as_type
=
{
'
minutes
'
:
float
,
'
priority
'
:
int
,
'
ram
'
:
int
,
'
verbose
'
:
None
}
as_type
=
{
'
minutes
'
:
float
,
'
priority
'
:
int
,
'
ram
'
:
int
,
'
verbose
'
:
None
}
action
=
'
store_true
'
if
value
==
'
verbose
'
else
'
store
'
action
=
'
store_true
'
if
value
==
'
verbose
'
else
'
store
'
group
.
add_argument
(
flag
,
dest
=
'
sub_
'
+
value
,
help
=
explanation
,
action
=
action
,
group
.
add_argument
(
flag
,
dest
=
'
_sub_
'
+
value
,
help
=
get_explanation
(
flag
),
action
=
action
,
type
=
as_type
[
value
]
if
value
in
as_type
else
str
)
metavar
=
'
<
'
+
value
+
'
>
'
,
type
=
as_type
.
get
(
value
,
str
))
group
.
add_argument
(
'
-F
'
,
dest
=
'
_sub_flags
'
,
help
=
get_explanation
(
'
-F
'
),
action
=
'
store_true
'
)
group
.
add_argument
(
'
-v
'
,
dest
=
'
_sub_verbose
'
,
help
=
get_explanation
(
'
-v
'
),
action
=
'
store_true
'
)
group
.
add_argument
(
'
-s
'
,
dest
=
'
_sub_multi_threaded
'
,
help
=
get_explanation
(
'
-s
'
),
metavar
=
'
<pename>,<threads>
'
)
group
.
add_argument
(
'
-j
'
,
dest
=
'
_sub_wait_for
'
,
help
=
get_explanation
(
'
-j
'
),
metavar
=
'
<jid>
'
)
return
group
return
group
@classmethod
@classmethod
def
from_args
(
cls
,
args
):
def
from_args
(
cls
,
args
):
as_dict
=
{
value
:
getattr
(
args
,
'
sub_
'
+
value
,
None
)
for
value
in
cls
.
cmd_line_flags
.
values
()}
as_dict
=
{
value
:
getattr
(
args
,
'
_sub_
'
+
value
,
None
)
for
value
in
cls
.
cmd_line_flags
.
values
()}
return
cls
(
**
as_dict
)
if
args
.
_sub_wait_for
is
not
None
:
as_dict
[
'
wait_for
'
]
=
args
.
_sub_wait_for
.
split
(
'
,
'
)
if
args
.
_sub_multi_threaded
is
not
None
:
def
submit
(
*
command
,
pename
,
threads
=
args
.
_sub_multi_threaded
.
split
(
'
,
'
)
minutes
=
None
,
as_dict
[
'
multi_threaded
'
]
=
pename
,
threads
queue
=
None
,
return
cls
(
verbose
=
args
.
_sub_verbose
,
flags
=
args
.
_sub_flags
,
**
as_dict
)
architecture
=
None
,
priority
=
None
,
email
=
None
,
def
submit
(
*
command
,
**
kwargs
):
wait_for
=
None
,
job_name
=
None
,
ram
=
None
,
logdir
=
None
,
mail_options
=
None
,
output
=
None
,
flags
=
False
,
multi_threaded
=
None
,
verbose
=
False
,
env
=
None
):
"""
"""
Submits a given command to the cluster
Submits a given command to the cluster
...
@@ -248,41 +249,7 @@ def submit(*command,
...
@@ -248,41 +249,7 @@ def submit(*command,
:return: string of submitted job id
:return: string of submitted job id
"""
"""
return
SubmitParams
(
**
kwargs
)(
*
command
)
from
fsl.utils.run
import
runfsl
,
prepareArgs
base_cmd
=
[
'
fsl_sub
'
]
for
flag
,
variable_name
in
[
(
'
-T
'
,
'
minutes
'
),
(
'
-q
'
,
'
queue
'
),
(
'
-a
'
,
'
architecture
'
),
(
'
-p
'
,
'
priority
'
),
(
'
-M
'
,
'
email
'
),
(
'
-N
'
,
'
job_name
'
),
(
'
-R
'
,
'
ram
'
),
(
'
-l
'
,
'
logdir
'
),
(
'
-m
'
,
'
mail_options
'
),
(
'
-z
'
,
'
output
'
)]:
variable
=
locals
()[
variable_name
]
if
variable
:
base_cmd
.
extend
([
flag
,
str
(
variable
)])
if
flags
:
base_cmd
.
append
(
'
-F
'
)
if
verbose
:
base_cmd
.
append
(
'
-v
'
)
if
wait_for
:
base_cmd
.
extend
([
'
-j
'
,
_flatten_job_ids
(
wait_for
)])
if
multi_threaded
:
base_cmd
.
append
(
'
-s
'
)
base_cmd
.
extend
(
multi_threaded
)
base_cmd
.
extend
(
prepareArgs
(
command
))
return
runfsl
(
*
base_cmd
,
env
=
env
).
strip
()
def
info
(
job_id
):
def
info
(
job_id
):
...
...
This diff is collapsed.
Click to expand it.
tests/test_fslsub.py
+
41
−
0
View file @
c1a2c2e5
...
@@ -12,6 +12,7 @@ import os.path as op
...
@@ -12,6 +12,7 @@ import os.path as op
import
sys
import
sys
import
textwrap
as
tw
import
textwrap
as
tw
import
contextlib
import
contextlib
import
argparse
from
fsl.utils
import
fslsub
from
fsl.utils
import
fslsub
from
fsl.utils.tempdir
import
tempdir
from
fsl.utils.tempdir
import
tempdir
...
@@ -125,6 +126,46 @@ def test_info():
...
@@ -125,6 +126,46 @@ def test_info():
assert
fslsub
.
info
(
'
12345
'
)
==
exp
assert
fslsub
.
info
(
'
12345
'
)
==
exp
def
test_add_to_parser
():
test_flags
=
[
(
'
-T
'
,
'
30.0
'
),
(
'
-q
'
,
'
short.q
'
),
(
'
-a
'
,
'
architecture
'
),
(
'
-p
'
,
'
3
'
),
(
'
-M
'
,
'
test@something.com
'
),
(
'
-N
'
,
'
job_name
'
),
(
'
-R
'
,
'
20
'
),
(
'
-l
'
,
'
logdir
'
),
(
'
-j
'
,
'
12345,67890
'
),
(
'
-m
'
,
'
mail_options
'
),
(
'
-v
'
,
),
(
'
-F
'
,
),
(
'
-s
'
,
'
pename,thread
'
)
]
for
flag
in
test_flags
:
for
include
in
(
None
,
[
flag
[
0
]]):
parser
=
argparse
.
ArgumentParser
(
"
test parser
"
)
fslsub
.
SubmitParams
.
add_to_parser
(
parser
,
include
=
include
)
args
=
parser
.
parse_args
(
flag
)
submitter
=
fslsub
.
SubmitParams
.
from_args
(
args
)
assert
submitter
.
as_flags
()
==
flag
parser
=
argparse
.
ArgumentParser
(
"
test parser
"
)
parser
.
add_argument
(
'
some_input
'
)
fslsub
.
SubmitParams
.
add_to_parser
(
parser
,
include
=
None
)
all_flags
=
tuple
(
part
for
flag
in
test_flags
for
part
in
flag
)
args
=
parser
.
parse_args
((
'
input
'
,
)
+
all_flags
)
assert
args
.
some_input
==
'
input
'
submitter
=
fslsub
.
SubmitParams
.
from_args
(
args
)
assert
len
(
all_flags
)
==
len
(
submitter
.
as_flags
())
for
flag
in
test_flags
:
res_flags
=
submitter
.
as_flags
()
assert
flag
[
0
]
in
res_flags
start_index
=
res_flags
.
index
(
flag
[
0
])
for
idx
,
part
in
enumerate
(
flag
):
assert
res_flags
[
idx
+
start_index
]
==
part
def
myfunc
():
def
myfunc
():
print
(
'
standard output
'
)
print
(
'
standard output
'
)
print
(
'
standard error
'
,
file
=
sys
.
stderr
)
print
(
'
standard error
'
,
file
=
sys
.
stderr
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment