Skip to content

Commit 041cde2

Browse files
authored
Merge pull request #803 from DLWoodruff/console-scripts
Add console-script entry points for the main drivers
2 parents a105686 + 58e4e0f commit 041cde2

9 files changed

Lines changed: 88 additions & 14 deletions

File tree

README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ Here are two methods that seem to work well for installation, at least when cons
3535
```
3636
Run the line aborve after cloning and moving to the repo root directory.
3737

38-
To test your installation, cd to the directory where you installed mpi-sppy
39-
(it is called ``mpi-sppy``) and then give this command.
38+
To test your installation, give this command (once mpi-sppy is installed
39+
it works from any directory):
4040

4141
```
42-
mpirun -n 2 python -m mpi4py mpi_one_sided_test.py
42+
mpirun -n 2 mpi-sppy-one-sided-test
4343
```
4444

4545
If you don't see any error messages, you might have an MPI
@@ -55,6 +55,26 @@ Installing mpi-sppy
5555
It is possible to pip install mpi-sppy; however, most users are better off
5656
getting the software from Github because it is under active development.
5757

58+
Command-line programs
59+
---------------------
60+
61+
Installing mpi-sppy — whether with `pip install mpi-sppy` or with
62+
`pip install -e .` from a clone (the recommended way to work from source) —
63+
puts a few console scripts on your `PATH`, so you can run the main drivers
64+
without locating the files in your environment:
65+
66+
- `mpi-sppy-generic-cylinders` — the general-purpose driver, equivalent to
67+
`python -m mpisppy.generic_cylinders` (see the `generic_cylinders` docs).
68+
- `mpi-sppy-mrp-generic` — the sequential-sampling (MRP) driver, equivalent
69+
to `python -m mpisppy.mrp_generic`.
70+
- `mpi-sppy-one-sided-test` — the MPI one-sided diagnostic shown above.
71+
72+
For multi-rank parallel runs, the `python -m mpi4py` module form is still
73+
recommended (e.g. `mpiexec -np 3 python -m mpi4py -m
74+
mpisppy.generic_cylinders ...`) so that mpi4py installs its
75+
abort-on-exception handler; a bare `mpiexec -np 3 mpi-sppy-generic-cylinders
76+
...` runs, but a failure on one rank may leave the others hanging.
77+
5878
Citing mpi-sppy
5979
---------------
6080
If you find mpi-sppy useful in your work, we kindly request that you cite the following

doc/src/generic_cylinders.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ run mpi-sppy. It provides command-line access to the hub-and-spoke
88
system, the extensive form solver, confidence intervals, and many
99
other features without requiring you to write a driver program.
1010

11+
.. note::
12+
Installing mpi-sppy (with ``pip install mpi-sppy`` or with
13+
``pip install -e .`` from a clone) puts a console script named
14+
``mpi-sppy-generic-cylinders`` on your ``PATH``. It is equivalent to
15+
``python -m mpisppy.generic_cylinders``, so in every example below you
16+
can substitute ``mpi-sppy-generic-cylinders`` for the
17+
``python -m mpisppy.generic_cylinders`` prefix, e.g.::
18+
19+
mpi-sppy-generic-cylinders --module-name farmer --num-scens 3 --EF --EF-solver-name gurobi
20+
21+
For multi-rank parallel runs, prefer the ``python -m mpi4py`` module
22+
form shown below (``mpiexec -np 3 python -m mpi4py -m
23+
mpisppy.generic_cylinders ...``): mpi4py's runner aborts all ranks if
24+
one raises an exception, whereas a bare
25+
``mpiexec -np 3 mpi-sppy-generic-cylinders ...`` runs but may leave
26+
the other ranks hanging when one fails.
27+
1128
Your Model File (Module)
1229
------------------------
1330

doc/src/install_mpi.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ Here are two methods that seem to work well for installation, at least when cons
2020

2121
* ``pip install -e .[mpi]`` (after cloning and moving to the repo root directory)
2222

23-
To test
24-
your installation, cd to the directory where you installed mpi-sppy
25-
(it is called ``mpi-sppy``) and then give this command.
23+
To test your installation, give this command (once mpi-sppy is
24+
installed it works from any directory):
2625

27-
``mpirun -n 2 python -m mpi4py mpi_one_sided_test.py``
26+
``mpirun -n 2 mpi-sppy-one-sided-test``
2827

2928
If you don't see any error messages, you might have an MPI
3029
installation that will work well. Note that even if there is

doc/src/quick_start.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,13 @@ top of the cloned ``mpi-sppy`` repository; step 1 changes into
350350
You should see the solver print progress and the script print an
351351
optimal objective value. This check does *not* use MPI.
352352

353-
3. **MPI works** (only if you installed MPI and ``mpi4py``). Still in
354-
``examples/farmer``, run the bundled one-sided MPI test (its path is
355-
given relative to ``examples/farmer``):
353+
3. **MPI works** (only if you installed MPI and ``mpi4py``). Run the
354+
bundled one-sided MPI test (the console script is on your ``PATH``
355+
after installation, so no path is needed):
356356

357357
.. code-block:: text
358358
359-
mpiexec -n 2 python -m mpi4py ../../mpi_one_sided_test.py
359+
mpiexec -n 2 mpi-sppy-one-sided-test
360360
361361
If you see no error messages, your MPI installation should be
362362
suitable. Then confirm the full hub-and-spoke flow with a short PH

doc/src/seqsamp.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ The recommended way to run sequential sampling is with
1919
``mpisppy.mrp_generic``. Like ``generic_cylinders.py``, it takes
2020
a ``--module-name`` argument pointing to your model module.
2121

22+
.. note::
23+
Installing mpi-sppy (with ``pip install mpi-sppy`` or with
24+
``pip install -e .`` from a clone) puts the console script
25+
``mpi-sppy-mrp-generic`` on your ``PATH``; it is equivalent to
26+
``python -m mpisppy.mrp_generic`` and can be used in place of that
27+
prefix in the examples below. For the ``--xhat-method cylinders``
28+
(multi-rank) case, prefer the ``python -m mpi4py`` module form so
29+
that mpi4py's abort-on-exception handler is installed.
30+
2231
Your model module must provide the same functions required by
2332
``generic_cylinders``: ``scenario_creator``, ``scenario_names_creator``,
2433
``kw_creator``, ``inparser_adder``, and ``scenario_denouement``.

mpi_one_sided_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
def main():
2525
if mpi.COMM_WORLD.Get_size() == 1:
2626
print("ERROR: This script must be run with multiple MPI processes using mpirun or mpiexec, e.g.:", file=sys.stderr)
27-
print(" mpirun -n 2 python -m mpi4py mpi_one_sided_test.py", file=sys.stderr)
27+
print(" mpirun -n 2 mpi-sppy-one-sided-test", file=sys.stderr)
2828
sys.exit(2) # Exit status 2: command line usage error
2929

3030
rank = mpi.COMM_WORLD.Get_rank()

mpisppy/generic_cylinders.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828

2929
##########################################################################
30-
if __name__ == "__main__":
30+
def main():
3131
if len(sys.argv) == 1:
3232
print("The python model file module name (no .py) must be given.")
3333
print("usage, e.g.: python -m mpi4py ../../mpisppy/generic_cylinders.py --module-name farmer --help")
@@ -145,3 +145,7 @@ def scenario_denouement(rank, sname, s):
145145
scenario_denouement, bundle_wrapper=bundle_wrapper)
146146
if mmw_requested(cfg):
147147
do_mmw(fname, cfg, wheel=wheel)
148+
149+
150+
if __name__ == "__main__":
151+
main()

mpisppy/mrp_generic.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def parse_mrp_args(m):
7373

7474

7575
##########################################################################
76-
if __name__ == "__main__":
76+
def main():
7777
if len(sys.argv) == 1:
7878
print("The python model file module name (no .py) must be given.")
7979
print("usage, e.g.: python -m mpisppy.mrp_generic --module-name farmer"
@@ -101,3 +101,7 @@ def parse_mrp_args(m):
101101
root_nonants = np.array(xhat["ROOT"])
102102
np.save(f"{cfg.solution_base_name}.npy", root_nonants)
103103
print(f"Wrote xhat to {cfg.solution_base_name}.npy")
104+
105+
106+
if __name__ == "__main__":
107+
main()

pyproject.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ download = "https://github.com/Pyomo/mpi-sppy"
3434
documentation = "https://mpi-sppy.readthedocs.io"
3535
tracker = "https://github.com/Pyomo/mpi-sppy/issues"
3636

37+
# Console entry points: pip creates a launcher on the user's PATH for each,
38+
# so pip-installed users can run these drivers without knowing where the
39+
# files landed in site-packages. Each target is an importable module:callable.
40+
# For real multi-rank parallel runs the module form is still recommended so
41+
# the mpi4py runner installs its abort-on-exception handler, e.g.:
42+
# mpiexec -np 3 python -m mpi4py -m mpisppy.generic_cylinders --module-name farmer ...
43+
[project.scripts]
44+
mpi-sppy-generic-cylinders = "mpisppy.generic_cylinders:main"
45+
mpi-sppy-mrp-generic = "mpisppy.mrp_generic:main"
46+
mpi-sppy-one-sided-test = "mpi_one_sided_test:main"
47+
3748
[project.optional-dependencies]
3849
doc = [
3950
"sphinx",
@@ -52,3 +63,13 @@ pandas = [
5263
plot = [
5364
"matplotlib",
5465
]
66+
67+
# Explicit package/module declaration. Matches the previous find_packages()
68+
# result (only the mpisppy package and its subpackages) and additionally
69+
# installs the top-level mpi_one_sided_test.py so its console script can
70+
# import it.
71+
[tool.setuptools]
72+
py-modules = ["mpi_one_sided_test"]
73+
74+
[tool.setuptools.packages.find]
75+
include = ["mpisppy", "mpisppy.*"]

0 commit comments

Comments
 (0)