Skip to content

Commit 221eb5f

Browse files
grondomergify[bot]
authored andcommitted
python: add shared class for flux-alloc and batch
Problem: There's duplicated code in the Python cli AllocCmd and BatchCmd classes because they do not share a common parent class. Add a shared BatchAllocCmd class for `flux batch` and `flux alloc`. Move the addition of common arguments to the class initializer, and add an init_common() method for both classes to perform common initialization after argument parsing for both cli utilities. Also add a currently empty update_jobspec_common() method for common updates to jobspec after it is created. Derive AllocCmd and BatchCmd from BatchAllocCmd. Remove duplicated code that has now moved into BatchAllocCmd.init_common(). Call BatchAllocCmd.update_jobspec_common() from both classes after jobspec creation.
1 parent 138f64b commit 221eb5f

File tree

3 files changed

+94
-96
lines changed

3 files changed

+94
-96
lines changed

src/bindings/python/flux/cli/alloc.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
from flux.uri import JobURI
2020

2121

22-
class AllocCmd(base.MiniCmd):
22+
class AllocCmd(base.BatchAllocCmd):
2323
def __init__(self, prog, usage=None, description=None):
24-
self.t0 = None
2524
super().__init__(prog, usage, description, exclude_io=True)
26-
base.add_batch_alloc_args(self.parser)
2725
self.parser.add_argument(
2826
"-v",
2927
"--verbose",
@@ -44,24 +42,14 @@ def __init__(self, prog, usage=None, description=None):
4442
)
4543

4644
def init_jobspec(self, args):
47-
# If number of slots not specified, then set it to node count
48-
# if set, otherwise raise an error.
49-
if not args.nslots:
50-
if not args.nodes:
51-
raise ValueError("Number of slots to allocate must be specified")
52-
args.nslots = args.nodes
53-
args.exclusive = True
45+
self.init_common(args)
5446

5547
# For --bg, do not run an rc2 (initial program) unless
5648
# the user explicitly specified COMMAND:
5749
if args.bg and not args.COMMAND:
5850
args.broker_opts = args.broker_opts or []
5951
args.broker_opts.append("-Sbroker.rc2_none=1")
6052

61-
if args.dump:
62-
args.broker_opts = args.broker_opts or []
63-
args.broker_opts.append("-Scontent.dump=" + args.dump)
64-
6553
jobspec = flux.job.JobspecV1.from_nest_command(
6654
command=args.COMMAND,
6755
num_slots=args.nslots,
@@ -73,6 +61,8 @@ def init_jobspec(self, args):
7361
conf=args.conf.config,
7462
)
7563

64+
self.update_jobspec_common(args, jobspec)
65+
7666
# For --bg, always allocate a pty, but not interactive,
7767
# since an interactive pty causes the job shell to hang around
7868
# until a pty client attaches, which may never happen.

src/bindings/python/flux/cli/base.py

Lines changed: 85 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,71 +1657,88 @@ def main(self, args):
16571657
self.run_and_exit()
16581658

16591659

1660-
def add_batch_alloc_args(parser):
1661-
"""
1662-
Add "batch"-specific resource allocation arguments to parser object
1663-
which deal in slots instead of tasks.
1664-
"""
1665-
parser.add_argument(
1666-
"--conf",
1667-
metavar="CONF",
1668-
default=BatchConfig(),
1669-
action=ConfAction,
1670-
help="Set configuration for a child Flux instance. CONF may be a "
1671-
+ "multiline string in JSON or TOML, a configuration key=value, a "
1672-
+ "path to a JSON or TOML file, or a configuration loaded by name "
1673-
+ "from a standard search path. This option may specified multiple "
1674-
+ "times, in which case the config is iteratively updated.",
1675-
)
1676-
parser.add_argument(
1677-
"--broker-opts",
1678-
metavar="OPTS",
1679-
default=None,
1680-
action="append",
1681-
help="Pass options to flux brokers",
1682-
)
1683-
parser.add_argument(
1684-
"--dump",
1685-
nargs="?",
1686-
const="flux-{{jobid}}-dump.tgz",
1687-
metavar="FILE",
1688-
help="Archive KVS on exit",
1689-
)
1690-
parser.add_argument(
1691-
"-n",
1692-
"--nslots",
1693-
type=int,
1694-
metavar="N",
1695-
help="Number of total resource slots requested."
1696-
+ " The size of a resource slot may be specified via the"
1697-
+ " -c, --cores-per-slot and -g, --gpus-per-slot options."
1698-
+ " The default slot size is 1 core.",
1699-
)
1700-
parser.add_argument(
1701-
"-c",
1702-
"--cores-per-slot",
1703-
type=int,
1704-
metavar="N",
1705-
default=1,
1706-
help="Number of cores to allocate per slot",
1707-
)
1708-
parser.add_argument(
1709-
"-g",
1710-
"--gpus-per-slot",
1711-
type=int,
1712-
metavar="N",
1713-
help="Number of GPUs to allocate per slot",
1714-
)
1715-
parser.add_argument(
1716-
"-N",
1717-
"--nodes",
1718-
type=int,
1719-
metavar="N",
1720-
help="Distribute allocated resource slots across N individual nodes",
1721-
)
1722-
parser.add_argument(
1723-
"-x",
1724-
"--exclusive",
1725-
action="store_true",
1726-
help="With -N, --nodes, allocate nodes exclusively",
1727-
)
1660+
class BatchAllocCmd(MiniCmd):
1661+
def __init__(self, prog, usage=None, description=None, exclude_io=True):
1662+
self.t0 = None
1663+
super().__init__(prog, usage, description, exclude_io)
1664+
self.parser.add_argument(
1665+
"--conf",
1666+
metavar="CONF",
1667+
default=BatchConfig(),
1668+
action=ConfAction,
1669+
help="Set configuration for a child Flux instance. CONF may be a "
1670+
+ "multiline string in JSON or TOML, a configuration key=value, a "
1671+
+ "path to a JSON or TOML file, or a configuration loaded by name "
1672+
+ "from a standard search path. This option may specified multiple "
1673+
+ "times, in which case the config is iteratively updated.",
1674+
)
1675+
self.parser.add_argument(
1676+
"--broker-opts",
1677+
metavar="OPTS",
1678+
default=None,
1679+
action="append",
1680+
help="Pass options to flux brokers",
1681+
)
1682+
self.parser.add_argument(
1683+
"--dump",
1684+
nargs="?",
1685+
const="flux-{{jobid}}-dump.tgz",
1686+
metavar="FILE",
1687+
help="Archive KVS on exit",
1688+
)
1689+
self.parser.add_argument(
1690+
"-n",
1691+
"--nslots",
1692+
type=int,
1693+
metavar="N",
1694+
help="Number of total resource slots requested."
1695+
+ " The size of a resource slot may be specified via the"
1696+
+ " -c, --cores-per-slot and -g, --gpus-per-slot options."
1697+
+ " The default slot size is 1 core.",
1698+
)
1699+
self.parser.add_argument(
1700+
"-c",
1701+
"--cores-per-slot",
1702+
type=int,
1703+
metavar="N",
1704+
default=1,
1705+
help="Number of cores to allocate per slot",
1706+
)
1707+
self.parser.add_argument(
1708+
"-g",
1709+
"--gpus-per-slot",
1710+
type=int,
1711+
metavar="N",
1712+
help="Number of GPUs to allocate per slot",
1713+
)
1714+
self.parser.add_argument(
1715+
"-N",
1716+
"--nodes",
1717+
type=int,
1718+
metavar="N",
1719+
help="Distribute allocated resource slots across N individual nodes",
1720+
)
1721+
self.parser.add_argument(
1722+
"-x",
1723+
"--exclusive",
1724+
action="store_true",
1725+
help="With -N, --nodes, allocate nodes exclusively",
1726+
)
1727+
1728+
def init_common(self, args):
1729+
"""Common initialization code for batch/alloc"""
1730+
# If number of slots not specified, then set it to node count
1731+
# if set, otherwise raise an error.
1732+
if not args.nslots:
1733+
if not args.nodes:
1734+
raise ValueError("Number of slots to allocate must be specified")
1735+
args.nslots = args.nodes
1736+
args.exclusive = True
1737+
1738+
if args.dump:
1739+
args.broker_opts = args.broker_opts or []
1740+
args.broker_opts.append("-Scontent.dump=" + args.dump)
1741+
1742+
def update_jobspec_common(self, args, jobspec):
1743+
"""Common jobspec update code for batch/alloc"""
1744+
pass

src/bindings/python/flux/cli/batch.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@
2020
LOGGER = logging.getLogger("flux-batch")
2121

2222

23-
class BatchCmd(base.MiniCmd):
23+
class BatchCmd(base.BatchAllocCmd):
2424
def __init__(self, prog, usage=None, description=None):
2525
super().__init__(prog, usage, description)
2626
self.parser.add_argument(
2727
"--wrap",
2828
action="store_true",
2929
help="Wrap arguments or stdin in a /bin/sh script",
3030
)
31-
base.add_batch_alloc_args(self.parser)
3231
self.parser.add_argument(
3332
"SCRIPT",
3433
nargs=argparse.REMAINDER,
@@ -87,21 +86,11 @@ def process_script(self, args):
8786
return self.parse_directive_args(name, batchscript)
8887

8988
def init_jobspec(self, args):
89+
self.init_common(args)
90+
9091
if args.wrap:
9192
self.script = f"#!/bin/sh\n{self.script}"
9293

93-
# If number of slots not specified, then set it to node count
94-
# if set, otherwise raise an error.
95-
if not args.nslots:
96-
if not args.nodes:
97-
raise ValueError("Number of slots to allocate must be specified")
98-
args.nslots = args.nodes
99-
args.exclusive = True
100-
101-
if args.dump:
102-
args.broker_opts = args.broker_opts or []
103-
args.broker_opts.append("-Scontent.dump=" + args.dump)
104-
10594
# If job name is not explicitly set in args, use the script name
10695
# if a script was provided, else the string "batch" to
10796
# indicate the script was set on flux batch stdin.
@@ -124,6 +113,8 @@ def init_jobspec(self, args):
124113
conf=args.conf.config,
125114
)
126115

116+
self.update_jobspec_common(args, jobspec)
117+
127118
# Default output is flux-{{jobid}}.out
128119
# overridden by either --output=none or --output=kvs
129120
if not args.output:

0 commit comments

Comments
 (0)