multiCMD 1.57__tar.gz → 1.58__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.
Files changed (36) hide show
  1. {multicmd-1.57 → multicmd-1.58}/PKG-INFO +11 -2
  2. {multicmd-1.57 → multicmd-1.58}/README.md +10 -1
  3. {multicmd-1.57 → multicmd-1.58}/multiCMD.egg-info/PKG-INFO +11 -2
  4. {multicmd-1.57 → multicmd-1.58}/multiCMD.egg-info/SOURCES.txt +2 -0
  5. {multicmd-1.57 → multicmd-1.58}/multiCMD.egg-info/entry_points.txt +0 -1
  6. {multicmd-1.57 → multicmd-1.58}/multiCMD.py +1 -1
  7. multicmd-1.58/scripts/multiCMD +6 -0
  8. {multicmd-1.57 → multicmd-1.58}/setup.py +3 -1
  9. multicmd-1.58/tests/test_packaging.py +26 -0
  10. {multicmd-1.57 → multicmd-1.58}/LICENSE +0 -0
  11. {multicmd-1.57 → multicmd-1.58}/multiCMD.egg-info/dependency_links.txt +0 -0
  12. {multicmd-1.57 → multicmd-1.58}/multiCMD.egg-info/top_level.txt +0 -0
  13. {multicmd-1.57 → multicmd-1.58}/setup.cfg +0 -0
  14. {multicmd-1.57 → multicmd-1.58}/tests/test_api.py +0 -0
  15. {multicmd-1.57 → multicmd-1.58}/tests/test_async_executor.py +0 -0
  16. {multicmd-1.57 → multicmd-1.58}/tests/test_cli.py +0 -0
  17. {multicmd-1.57 → multicmd-1.58}/tests/test_cli_input.py +0 -0
  18. {multicmd-1.57 → multicmd-1.58}/tests/test_cli_summary.py +0 -0
  19. {multicmd-1.57 → multicmd-1.58}/tests/test_display.py +0 -0
  20. {multicmd-1.57 → multicmd-1.58}/tests/test_env.py +0 -0
  21. {multicmd-1.57 → multicmd-1.58}/tests/test_expand_ranges.py +0 -0
  22. {multicmd-1.57 → multicmd-1.58}/tests/test_helpers.py +0 -0
  23. {multicmd-1.57 → multicmd-1.58}/tests/test_interrupts.py +0 -0
  24. {multicmd-1.57 → multicmd-1.58}/tests/test_parsing.py +0 -0
  25. {multicmd-1.57 → multicmd-1.58}/tests/test_ping.py +0 -0
  26. {multicmd-1.57 → multicmd-1.58}/tests/test_pool.py +0 -0
  27. {multicmd-1.57 → multicmd-1.58}/tests/test_process_groups.py +0 -0
  28. {multicmd-1.57 → multicmd-1.58}/tests/test_pty.py +0 -0
  29. {multicmd-1.57 → multicmd-1.58}/tests/test_reader.py +0 -0
  30. {multicmd-1.57 → multicmd-1.58}/tests/test_regressions.py +0 -0
  31. {multicmd-1.57 → multicmd-1.58}/tests/test_run_command.py +0 -0
  32. {multicmd-1.57 → multicmd-1.58}/tests/test_run_commands.py +0 -0
  33. {multicmd-1.57 → multicmd-1.58}/tests/test_sudo.py +0 -0
  34. {multicmd-1.57 → multicmd-1.58}/tests/test_supervision.py +0 -0
  35. {multicmd-1.57 → multicmd-1.58}/tests/test_task.py +0 -0
  36. {multicmd-1.57 → multicmd-1.58}/tests/test_windows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiCMD
3
- Version: 1.57
3
+ Version: 1.58
4
4
  Summary: Run commands simultaneously
5
5
  Home-page: https://github.com/yufei-pan/multiCMD
6
6
  Author: Yufei Pan
@@ -56,7 +56,7 @@ It works both as a command-line tool and as an importable wrapper around
56
56
  pip install multiCMD
57
57
  ```
58
58
 
59
- This installs the module and three equivalent console entry points:
59
+ This installs the module and three equivalent commands:
60
60
 
61
61
  ```bash
62
62
  mcmd
@@ -491,6 +491,15 @@ pytest -m "not slow" # skip intentional sleep-heavy cases
491
491
 
492
492
  `test_expand_ranges_perf.py` is a manual performance microbenchmark and is not collected by pytest.
493
493
 
494
+ ## Upgrading to 1.58 from 1.57
495
+
496
+ - The `multiCMD` command is now a script file, not an entry point, so `entry_points.txt` no longer has two names that differ only in case. All three commands still work the same way, except in the venv case below. From 1.58 on, stock pip 9 on EL7 and EL8 upgrades and uninstalls multiCMD without `configparser.DuplicateOptionError`.
497
+ - With pip 9, the pip of EL7 and EL8 (`pip3 --version`), upgrading from 1.57 or earlier and `pip3 uninstall multiCMD` of those releases stop with `configparser.DuplicateOptionError: ... option 'multicmd' in section 'console_scripts' already exists`, and nothing changes: the installed release keeps working. Run `pip3 install -U pip` once, then upgrade or uninstall.
498
+ - With `--user` the same happens, except that `pip3 install --user -U multiCMD` with no version does not stop: it installs the new release, which works, and leaves the old release's metadata behind. `pip3 list` then shows the old release after `pip3 uninstall multiCMD`, and the next uninstall stops with that error. To avoid this, run `pip3 install --user -U pip` once first. If it has already happened, run that, run `pip3 uninstall multiCMD` until it says multiCMD is not installed, and install again. From 1.58 on the same upgrade leaves the metadata too, but with no error: `pip3 uninstall multiCMD` takes one run per release left.
499
+ - Without `--user`, with multiCMD 1.57 or earlier installed, `pip3 install -U hpcp`, `statblk` or `statbtrfs` stops the same way once a newer multiCMD is out, because pip 9 upgrades dependencies too. `pip3 install -U --no-deps hpcp` gets past it.
500
+ - With pip 10 or later, in a venv whose path has a space or is too long for the kernel's `#!` line, the `multiCMD` spelling does not start (the error varies: "bad interpreter", `import: command not found`), because pip gives a script file a plain `#!` line: use `multicmd`. With pip 9 no spelling starts in such a venv, as in 1.57. uv and system or `--user` installs are not affected.
501
+ - An embedded copy made by the generator now falls back from any failure to import the installed multiCMD, not only the three errors it named.
502
+
494
503
  ## Upgrading to 1.57 from 1.56
495
504
 
496
505
  - Faster command starts on Python 3.6 - 3.10: the wrapper that puts a command in its own process group
@@ -30,7 +30,7 @@ It works both as a command-line tool and as an importable wrapper around
30
30
  pip install multiCMD
31
31
  ```
32
32
 
33
- This installs the module and three equivalent console entry points:
33
+ This installs the module and three equivalent commands:
34
34
 
35
35
  ```bash
36
36
  mcmd
@@ -465,6 +465,15 @@ pytest -m "not slow" # skip intentional sleep-heavy cases
465
465
 
466
466
  `test_expand_ranges_perf.py` is a manual performance microbenchmark and is not collected by pytest.
467
467
 
468
+ ## Upgrading to 1.58 from 1.57
469
+
470
+ - The `multiCMD` command is now a script file, not an entry point, so `entry_points.txt` no longer has two names that differ only in case. All three commands still work the same way, except in the venv case below. From 1.58 on, stock pip 9 on EL7 and EL8 upgrades and uninstalls multiCMD without `configparser.DuplicateOptionError`.
471
+ - With pip 9, the pip of EL7 and EL8 (`pip3 --version`), upgrading from 1.57 or earlier and `pip3 uninstall multiCMD` of those releases stop with `configparser.DuplicateOptionError: ... option 'multicmd' in section 'console_scripts' already exists`, and nothing changes: the installed release keeps working. Run `pip3 install -U pip` once, then upgrade or uninstall.
472
+ - With `--user` the same happens, except that `pip3 install --user -U multiCMD` with no version does not stop: it installs the new release, which works, and leaves the old release's metadata behind. `pip3 list` then shows the old release after `pip3 uninstall multiCMD`, and the next uninstall stops with that error. To avoid this, run `pip3 install --user -U pip` once first. If it has already happened, run that, run `pip3 uninstall multiCMD` until it says multiCMD is not installed, and install again. From 1.58 on the same upgrade leaves the metadata too, but with no error: `pip3 uninstall multiCMD` takes one run per release left.
473
+ - Without `--user`, with multiCMD 1.57 or earlier installed, `pip3 install -U hpcp`, `statblk` or `statbtrfs` stops the same way once a newer multiCMD is out, because pip 9 upgrades dependencies too. `pip3 install -U --no-deps hpcp` gets past it.
474
+ - With pip 10 or later, in a venv whose path has a space or is too long for the kernel's `#!` line, the `multiCMD` spelling does not start (the error varies: "bad interpreter", `import: command not found`), because pip gives a script file a plain `#!` line: use `multicmd`. With pip 9 no spelling starts in such a venv, as in 1.57. uv and system or `--user` installs are not affected.
475
+ - An embedded copy made by the generator now falls back from any failure to import the installed multiCMD, not only the three errors it named.
476
+
468
477
  ## Upgrading to 1.57 from 1.56
469
478
 
470
479
  - Faster command starts on Python 3.6 - 3.10: the wrapper that puts a command in its own process group
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multiCMD
3
- Version: 1.57
3
+ Version: 1.58
4
4
  Summary: Run commands simultaneously
5
5
  Home-page: https://github.com/yufei-pan/multiCMD
6
6
  Author: Yufei Pan
@@ -56,7 +56,7 @@ It works both as a command-line tool and as an importable wrapper around
56
56
  pip install multiCMD
57
57
  ```
58
58
 
59
- This installs the module and three equivalent console entry points:
59
+ This installs the module and three equivalent commands:
60
60
 
61
61
  ```bash
62
62
  mcmd
@@ -491,6 +491,15 @@ pytest -m "not slow" # skip intentional sleep-heavy cases
491
491
 
492
492
  `test_expand_ranges_perf.py` is a manual performance microbenchmark and is not collected by pytest.
493
493
 
494
+ ## Upgrading to 1.58 from 1.57
495
+
496
+ - The `multiCMD` command is now a script file, not an entry point, so `entry_points.txt` no longer has two names that differ only in case. All three commands still work the same way, except in the venv case below. From 1.58 on, stock pip 9 on EL7 and EL8 upgrades and uninstalls multiCMD without `configparser.DuplicateOptionError`.
497
+ - With pip 9, the pip of EL7 and EL8 (`pip3 --version`), upgrading from 1.57 or earlier and `pip3 uninstall multiCMD` of those releases stop with `configparser.DuplicateOptionError: ... option 'multicmd' in section 'console_scripts' already exists`, and nothing changes: the installed release keeps working. Run `pip3 install -U pip` once, then upgrade or uninstall.
498
+ - With `--user` the same happens, except that `pip3 install --user -U multiCMD` with no version does not stop: it installs the new release, which works, and leaves the old release's metadata behind. `pip3 list` then shows the old release after `pip3 uninstall multiCMD`, and the next uninstall stops with that error. To avoid this, run `pip3 install --user -U pip` once first. If it has already happened, run that, run `pip3 uninstall multiCMD` until it says multiCMD is not installed, and install again. From 1.58 on the same upgrade leaves the metadata too, but with no error: `pip3 uninstall multiCMD` takes one run per release left.
499
+ - Without `--user`, with multiCMD 1.57 or earlier installed, `pip3 install -U hpcp`, `statblk` or `statbtrfs` stops the same way once a newer multiCMD is out, because pip 9 upgrades dependencies too. `pip3 install -U --no-deps hpcp` gets past it.
500
+ - With pip 10 or later, in a venv whose path has a space or is too long for the kernel's `#!` line, the `multiCMD` spelling does not start (the error varies: "bad interpreter", `import: command not found`), because pip gives a script file a plain `#!` line: use `multicmd`. With pip 9 no spelling starts in such a venv, as in 1.57. uv and system or `--user` installs are not affected.
501
+ - An embedded copy made by the generator now falls back from any failure to import the installed multiCMD, not only the three errors it named.
502
+
494
503
  ## Upgrading to 1.57 from 1.56
495
504
 
496
505
  - Faster command starts on Python 3.6 - 3.10: the wrapper that puts a command in its own process group
@@ -7,6 +7,7 @@ multiCMD.egg-info/SOURCES.txt
7
7
  multiCMD.egg-info/dependency_links.txt
8
8
  multiCMD.egg-info/entry_points.txt
9
9
  multiCMD.egg-info/top_level.txt
10
+ scripts/multiCMD
10
11
  tests/test_api.py
11
12
  tests/test_async_executor.py
12
13
  tests/test_cli.py
@@ -17,6 +18,7 @@ tests/test_env.py
17
18
  tests/test_expand_ranges.py
18
19
  tests/test_helpers.py
19
20
  tests/test_interrupts.py
21
+ tests/test_packaging.py
20
22
  tests/test_parsing.py
21
23
  tests/test_ping.py
22
24
  tests/test_pool.py
@@ -1,4 +1,3 @@
1
1
  [console_scripts]
2
2
  mcmd = multiCMD:main
3
- multiCMD = multiCMD:main
4
3
  multicmd = multiCMD:main
@@ -27,7 +27,7 @@ import traceback
27
27
  from pprint import pformat
28
28
 
29
29
  #%% global vars
30
- version = '1.57'
30
+ version = '1.58'
31
31
  __version__ = version
32
32
  COMMIT_DATE = '2026-11-06'
33
33
  # fire-and-forget threads (run_commands with wait_for_return=False) that join_threads() waits on. multiCMD takes no
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env python3
2
+ # The mixed-case command, installed as a script and not as an entry point (see setup.py).
3
+ import sys
4
+ from multiCMD import main
5
+ if __name__ == '__main__':
6
+ sys.exit(main())
@@ -11,10 +11,12 @@ setup(
11
11
  author_email='pan@zopyr.us',
12
12
  url='https://github.com/yufei-pan/multiCMD',
13
13
  py_modules=['multiCMD'],
14
+ # The mixed-case command is a script file and not an entry point: pip 9 (stock on EL7 and EL8) reads entry_points.txt with a
15
+ # parser that folds case, so two commands that differ only in case make it fail to upgrade or uninstall the package.
16
+ scripts=['scripts/multiCMD'],
14
17
  entry_points={
15
18
  'console_scripts': [
16
19
  'mcmd=multiCMD:main',
17
- 'multiCMD=multiCMD:main',
18
20
  'multicmd=multiCMD:main',
19
21
  ],
20
22
  },
@@ -0,0 +1,26 @@
1
+ """The packaging: the commands setup.py installs."""
2
+ import os
3
+ import subprocess
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ import pytest
8
+
9
+ PACKAGE_ROOT = Path(__file__).resolve().parents[1]
10
+
11
+
12
+ def test_no_two_commands_differ_only_in_case(tmp_path):
13
+ pytest.importorskip("setuptools", reason="needs setuptools to run setup.py")
14
+ # pip 9 (stock on EL7 and EL8) reads entry_points.txt with a parser that folds case, so two commands that differ only
15
+ # in case make it fail to upgrade or uninstall the package. The mixed-case command is a script file (scripts=) instead.
16
+ result = subprocess.run([sys.executable, "setup.py", "-q", "egg_info", "--egg-base", str(tmp_path)],
17
+ cwd=str(PACKAGE_ROOT), env=dict(os.environ, PYTHONDONTWRITEBYTECODE="1"), stdout=subprocess.PIPE, stderr=subprocess.PIPE,
18
+ universal_newlines=True, timeout=120)
19
+ assert result.returncode == 0, result.stderr
20
+ egg_info = tmp_path / "multiCMD.egg-info"
21
+ entry_points = (egg_info / "entry_points.txt").read_text(encoding="utf-8")
22
+ names = [line.split("=")[0].strip() for line in entry_points.splitlines() if "=" in line]
23
+ assert sorted(names) == ["mcmd", "multicmd"]
24
+ # the mixed-case command ships in the sdist as a script, so the three spellings stay three commands
25
+ assert "scripts/multiCMD" in (egg_info / "SOURCES.txt").read_text(encoding="utf-8").splitlines()
26
+ assert (PACKAGE_ROOT / "scripts" / "multiCMD").read_text(encoding="utf-8").startswith("#!")
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