pystand 2.38__tar.gz → 2.40__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pystand
3
- Version: 2.38
3
+ Version: 2.40
4
4
  Summary: Install Python versions from python-build-standalone project
5
5
  Author-email: Mark Blakeney <mark.blakeney@bullet-systems.net>
6
6
  License-Expression: GPL-3.0-or-later
@@ -143,7 +143,7 @@ usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
143
143
  [-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
144
144
  [--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
145
145
  [--no-color] [--cert {system,certifi,none}] [-V]
146
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx} ...
146
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx} ...
147
147
 
148
148
  Command line tool to download, install, and update pre-built Python versions
149
149
  from the python-build-standalone project at https://github.com/astral-
@@ -183,7 +183,7 @@ options:
183
183
  -V, --version just show pystand version
184
184
 
185
185
  Commands:
186
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx}
186
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx}
187
187
  install (i) Install one, more, or all versions from a python-
188
188
  build-standalone release.
189
189
  update (u, up) Update one, more, or all versions to another release.
@@ -193,6 +193,7 @@ Commands:
193
193
  show (s) Show versions available from a release.
194
194
  path (p) Show path prefix to installed version base directory.
195
195
  cache (c) Show size of release download caches.
196
+ man (m) Show installed man page for latest or given version.
196
197
  uv Run a uv command using a version of python installed
197
198
  by pystand.
198
199
  uvx Run a program using uvx and a version of python
@@ -372,6 +373,22 @@ options:
372
373
  aliases: c
373
374
  ```
374
375
 
376
+ ### Command `man`
377
+
378
+ ```
379
+ usage: pystand man [-h] [version]
380
+
381
+ Show installed man page for latest or given version.
382
+
383
+ positional arguments:
384
+ version installed version to show man page for
385
+
386
+ options:
387
+ -h, --help show this help message and exit
388
+
389
+ aliases: m
390
+ ```
391
+
375
392
  ### Command `uv`
376
393
 
377
394
  ```
@@ -125,7 +125,7 @@ usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
125
125
  [-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
126
126
  [--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
127
127
  [--no-color] [--cert {system,certifi,none}] [-V]
128
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx} ...
128
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx} ...
129
129
 
130
130
  Command line tool to download, install, and update pre-built Python versions
131
131
  from the python-build-standalone project at https://github.com/astral-
@@ -165,7 +165,7 @@ options:
165
165
  -V, --version just show pystand version
166
166
 
167
167
  Commands:
168
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx}
168
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx}
169
169
  install (i) Install one, more, or all versions from a python-
170
170
  build-standalone release.
171
171
  update (u, up) Update one, more, or all versions to another release.
@@ -175,6 +175,7 @@ Commands:
175
175
  show (s) Show versions available from a release.
176
176
  path (p) Show path prefix to installed version base directory.
177
177
  cache (c) Show size of release download caches.
178
+ man (m) Show installed man page for latest or given version.
178
179
  uv Run a uv command using a version of python installed
179
180
  by pystand.
180
181
  uvx Run a program using uvx and a version of python
@@ -354,6 +355,22 @@ options:
354
355
  aliases: c
355
356
  ```
356
357
 
358
+ ### Command `man`
359
+
360
+ ```
361
+ usage: pystand man [-h] [version]
362
+
363
+ Show installed man page for latest or given version.
364
+
365
+ positional arguments:
366
+ version installed version to show man page for
367
+
368
+ options:
369
+ -h, --help show this help message and exit
370
+
371
+ aliases: m
372
+ ```
373
+
357
374
  ### Command `uv`
358
375
 
359
376
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pystand
3
- Version: 2.38
3
+ Version: 2.40
4
4
  Summary: Install Python versions from python-build-standalone project
5
5
  Author-email: Mark Blakeney <mark.blakeney@bullet-systems.net>
6
6
  License-Expression: GPL-3.0-or-later
@@ -143,7 +143,7 @@ usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
143
143
  [-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
144
144
  [--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
145
145
  [--no-color] [--cert {system,certifi,none}] [-V]
146
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx} ...
146
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx} ...
147
147
 
148
148
  Command line tool to download, install, and update pre-built Python versions
149
149
  from the python-build-standalone project at https://github.com/astral-
@@ -183,7 +183,7 @@ options:
183
183
  -V, --version just show pystand version
184
184
 
185
185
  Commands:
186
- {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,uv,uvx}
186
+ {install,i,update,u,up,remove,r,rm,list,l,show,s,path,p,cache,c,man,m,uv,uvx}
187
187
  install (i) Install one, more, or all versions from a python-
188
188
  build-standalone release.
189
189
  update (u, up) Update one, more, or all versions to another release.
@@ -193,6 +193,7 @@ Commands:
193
193
  show (s) Show versions available from a release.
194
194
  path (p) Show path prefix to installed version base directory.
195
195
  cache (c) Show size of release download caches.
196
+ man (m) Show installed man page for latest or given version.
196
197
  uv Run a uv command using a version of python installed
197
198
  by pystand.
198
199
  uvx Run a program using uvx and a version of python
@@ -372,6 +373,22 @@ options:
372
373
  aliases: c
373
374
  ```
374
375
 
376
+ ### Command `man`
377
+
378
+ ```
379
+ usage: pystand man [-h] [version]
380
+
381
+ Show installed man page for latest or given version.
382
+
383
+ positional arguments:
384
+ version installed version to show man page for
385
+
386
+ options:
387
+ -h, --help show this help message and exit
388
+
389
+ aliases: m
390
+ ```
391
+
375
392
  ### Command `uv`
376
393
 
377
394
  ```
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.40",
3
+ "distance": 0,
4
+ "node": "g9abbd4e9ec899e5c4c00d23d30bba5a63cae906e",
5
+ "dirty": false,
6
+ "branch": "main",
7
+ "node_date": "2026-09-25"
8
+ }
@@ -37,11 +37,15 @@ LATEST_RELEASE_TAG = f'{GITHUB_SITE}/releases/latest'
37
37
  DOC = 'https://gregoryszorc.com/docs/python-build-standalone/main/'
38
38
  VER = f'{sys.version_info.major}.{sys.version_info.minor}'
39
39
 
40
+ # Seconds to wait for lock on prefix/cache dirs
41
+ LOCK_TIMEOUT = 5
42
+
40
43
  # Sample release tag for documentation/usage examples
41
44
  SAMPL_RELEASE = '20260807'
42
45
 
43
46
  PROG = Path(__file__).stem
44
47
  HOME = Path.home()
48
+ MANPATH = Path('share', 'man', 'man1', 'python.1')
45
49
 
46
50
  # Default distributions for various platforms
47
51
  DISTRIBUTIONS = {
@@ -117,9 +121,11 @@ class ColorDist(ColorTable):
117
121
 
118
122
 
119
123
  def unexpanduser(path: Path) -> Path:
120
- "Return path name, with $HOME replaced by ~ (opposite of Path.expanduser())"
121
- if path.parts[: len(HOME.parts)] == HOME.parts:
122
- return Path('~', *path.parts[len(HOME.parts) :])
124
+ "Return path name, with $HOME replaced by ~, i.e. opposite of Path.expanduser() for current user"
125
+ startlen = len(hparts := HOME.parts)
126
+ parts = path.parts
127
+ if parts[:startlen] == hparts:
128
+ path = Path('~', *parts[startlen:])
123
129
 
124
130
  return path
125
131
 
@@ -714,6 +720,18 @@ def compile_bytecode(srcdir: Path, tgtdir: Path) -> str | None:
714
720
  return None
715
721
 
716
722
 
723
+ def ensure_manpage_link(vdir: Path) -> None:
724
+ "Ensure a symlink to the man page for this version exists"
725
+ manpath = vdir / MANPATH
726
+ if manpath.is_file():
727
+ return
728
+
729
+ for path in manpath.parent.iterdir():
730
+ if not path.is_symlink() and path.name.startswith('python'):
731
+ manpath.symlink_to(path.name)
732
+ break
733
+
734
+
717
735
  def install_version(
718
736
  args: Namespace, vdir: Path, release: str, distribution: str, files: dict[str, Any]
719
737
  ) -> str | None:
@@ -721,9 +739,7 @@ def install_version(
721
739
  version = vdir.name
722
740
 
723
741
  if not (url := files[version].get(distribution)):
724
- return (
725
- f'Arch "{distribution}" not found for release {release} version {version}.'
726
- )
742
+ return f'Distribution "{distribution}" not found for release {release} version {version}.'
727
743
 
728
744
  tmpdir = args._versions / f'.{version}-tmp'
729
745
  rm_path(tmpdir)
@@ -748,6 +764,7 @@ def install_version(
748
764
  else:
749
765
  remove_version(args, version)
750
766
  tmpdir.replace(vdir)
767
+ ensure_manpage_link(vdir)
751
768
 
752
769
  return error
753
770
 
@@ -958,11 +975,14 @@ def main() -> str | None:
958
975
  args._latest_release = cache_dir / 'latest_release'
959
976
  args._cert = create_cert(args.cert)
960
977
 
961
- # Only allow one instance of this program to run (to read/write prefix and cache dirs)
962
- locks = [filelock.FileLock(d / '.lock') for d in (prefix_dir, cache_dir)]
978
+ def lock(path: Path) -> filelock.FileLock:
979
+ "Return a file lock for the given directory path"
980
+ return filelock.FileLock(path / '.lock', timeout=LOCK_TIMEOUT)
963
981
 
982
+ # Only allow one instance of this program to run (to avoid potential race
983
+ # condition on writtable dirs)
964
984
  try:
965
- with locks[0].acquire(blocking=False), locks[1].acquire(blocking=False):
985
+ with lock(cache_dir), lock(prefix_dir):
966
986
  args._release = get_release_tag(args)
967
987
  args._fmtrel = ColorRel(args._release, args.no_color).format
968
988
  result = args.func(args)
@@ -971,6 +991,15 @@ def main() -> str | None:
971
991
  except filelock.Timeout:
972
992
  return f'ERROR: Another instance of {PROG} is already running.'
973
993
 
994
+ # If the command returned a tuple, treat it as a subprocess command to run
995
+ if isinstance(result, tuple):
996
+ try:
997
+ subprocess.run(result)
998
+ except Exception as e:
999
+ result = f'Error running command: {e}'
1000
+ else:
1001
+ result = None
1002
+
974
1003
  return result
975
1004
 
976
1005
 
@@ -1542,6 +1571,34 @@ class cache:
1542
1571
  show_cache_size(args._downloads, args)
1543
1572
 
1544
1573
 
1574
+ @Command
1575
+ class man:
1576
+ "Show installed man page for latest or given version."
1577
+
1578
+ aliases = ('m',)
1579
+
1580
+ @staticmethod
1581
+ def init(parser: ArgumentParser) -> None:
1582
+ parser.add_argument(
1583
+ 'version', nargs='?', help='installed version to show man page for'
1584
+ )
1585
+
1586
+ @staticmethod
1587
+ def run(args: Namespace) -> str | tuple | None:
1588
+ if not (version := args.version):
1589
+ version = get_major_version(args)
1590
+
1591
+ vdir = (args._versions / version).resolve()
1592
+ if not vdir.exists():
1593
+ return f'Version {version} is not installed.'
1594
+
1595
+ man_path = (vdir / MANPATH).parent.parent
1596
+ if not man_path.is_dir():
1597
+ return f'No man page found for version {version}.'
1598
+
1599
+ return ('man', '-M', str(man_path), 'python')
1600
+
1601
+
1545
1602
  @Command
1546
1603
  class uv:
1547
1604
  __doc__ = f'Run a uv command using a version of python installed by {PROG}.'
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.38",
3
- "distance": 0,
4
- "node": "ge58d0185e364137af825c64bde9f335ca3f68030",
5
- "dirty": false,
6
- "branch": "main",
7
- "node_date": "2026-09-13"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes