pystand 1.2__py3-none-any.whl → 1.3__py3-none-any.whl
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.
- {pystand-1.2.dist-info → pystand-1.3.dist-info}/METADATA +9 -5
- pystand-1.3.dist-info/RECORD +6 -0
- pystand.py +46 -16
- pystand-1.2.dist-info/RECORD +0 -6
- {pystand-1.2.dist-info → pystand-1.3.dist-info}/WHEEL +0 -0
- {pystand-1.2.dist-info → pystand-1.3.dist-info}/entry_points.txt +0 -0
- {pystand-1.2.dist-info → pystand-1.3.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pystand
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3
|
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: GPLv3
|
@@ -117,7 +117,8 @@ Type `pystand` or `pystand -h` to view the usage summary:
|
|
117
117
|
|
118
118
|
```
|
119
119
|
usage: pystand [-h] [-D DISTRIBUTION] [-B BASE_DIR] [-C CACHE_MINUTES]
|
120
|
-
[--purge-days PURGE_DAYS]
|
120
|
+
[--purge-days PURGE_DAYS]
|
121
|
+
[--github-access-token GITHUB_ACCESS_TOKEN] [-V]
|
121
122
|
{install,update,remove,list,show,path} ...
|
122
123
|
|
123
124
|
Command line tool to download, install, and update pre-built Python versions
|
@@ -139,8 +140,11 @@ options:
|
|
139
140
|
before rechecking for latest. Default is 60 minutes
|
140
141
|
--purge-days PURGE_DAYS
|
141
142
|
cache release file lists for this number of days after
|
142
|
-
last version referencing it is removed. Default is
|
143
|
+
last version referencing it is removed. Default is 90
|
143
144
|
days
|
145
|
+
--github-access-token GITHUB_ACCESS_TOKEN
|
146
|
+
Optional Github access token. Can specify to reduce
|
147
|
+
rate limiting.
|
144
148
|
-V show pystand version
|
145
149
|
|
146
150
|
Commands:
|
@@ -333,8 +337,8 @@ anything after on a line) are ignored. Type `pystand` to see all
|
|
333
337
|
supported options.
|
334
338
|
|
335
339
|
The global options: `--distribution`, `--base-dir`, `--cache-minutes`,
|
336
|
-
`--purge-days` are the only sensible candidates
|
337
|
-
defaults.
|
340
|
+
`--purge-days`, `--github-access-token` are the only sensible candidates
|
341
|
+
to consider setting as defaults.
|
338
342
|
|
339
343
|
## Command Line Tab Completion
|
340
344
|
|
@@ -0,0 +1,6 @@
|
|
1
|
+
pystand.py,sha256=OI2SWREnCD8Hyu8Xk6z6FZqPDM6NfRtku_Djb6nJ7gM,27357
|
2
|
+
pystand-1.3.dist-info/METADATA,sha256=aXLnhaYuWDwnbWEbo5eZb2mzAOklpihUEuWuAzoaztk,14550
|
3
|
+
pystand-1.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
4
|
+
pystand-1.3.dist-info/entry_points.txt,sha256=DG4ps3I3nni1bubV1tXs6u8FARgkdbAYaEAzZD4RAo8,41
|
5
|
+
pystand-1.3.dist-info/top_level.txt,sha256=NoWUh19UQymAJLHTCdxMnVwV6Teftef5fzyF3OWLyNY,8
|
6
|
+
pystand-1.3.dist-info/RECORD,,
|
pystand.py
CHANGED
@@ -31,6 +31,13 @@ GITHUB_REPO = f'{REPO_OWNER}/{REPO}'
|
|
31
31
|
LATEST_RELEASE_URL = f'https://raw.githubusercontent.com/{GITHUB_REPO}'\
|
32
32
|
'/latest-release/latest-release.json'
|
33
33
|
|
34
|
+
# The following release is the first one that supports "install_only"
|
35
|
+
# builds so this tool does not support any releases before this.
|
36
|
+
FIRST_RELEASE = '20210724'
|
37
|
+
|
38
|
+
# The following regexp pattern is used to match the end of a release file name
|
39
|
+
ENDPAT = r'-install_only[-\dT]*.tar.gz$'
|
40
|
+
|
34
41
|
PROG = Path(__file__).stem
|
35
42
|
CNFFILE = platformdirs.user_config_path(f'{PROG}-flags.conf')
|
36
43
|
|
@@ -99,7 +106,14 @@ def get_gh(args: Namespace) -> Any:
|
|
99
106
|
return get_gh_handle
|
100
107
|
|
101
108
|
from github import Github
|
102
|
-
|
109
|
+
if args.github_access_token:
|
110
|
+
from github import Auth
|
111
|
+
auth = Auth.Token(args.github_access_token)
|
112
|
+
else:
|
113
|
+
auth = None
|
114
|
+
|
115
|
+
# Save this handle globally for future use
|
116
|
+
get_gh_handle = Github(auth=auth) # type: ignore
|
103
117
|
return get_gh_handle
|
104
118
|
|
105
119
|
def rm_path(path: Path) -> None:
|
@@ -169,8 +183,18 @@ def get_version_names(args: Namespace) -> list[str]:
|
|
169
183
|
return sorted(all_names - given, key=parse_version) \
|
170
184
|
if args.all else versions
|
171
185
|
|
172
|
-
def
|
173
|
-
'Return the latest
|
186
|
+
def get_release_tag(args: Namespace) -> str:
|
187
|
+
'Return the release tag, or latest if not specified'
|
188
|
+
if release := args.release:
|
189
|
+
if not release.isdigit() or len(release) != len(FIRST_RELEASE):
|
190
|
+
sys.exit('Release must be a YYYYMMDD string.')
|
191
|
+
if release < FIRST_RELEASE:
|
192
|
+
sys.exit(f'Releases before "{FIRST_RELEASE}" do not '
|
193
|
+
'include "*-install_only" builds so are '
|
194
|
+
'not supported.')
|
195
|
+
|
196
|
+
return release
|
197
|
+
|
174
198
|
if args._latest_release.exists():
|
175
199
|
stat = args._latest_release.stat()
|
176
200
|
if time.time() < (stat.st_mtime + int(args.cache_minutes * 60)):
|
@@ -193,6 +217,15 @@ def get_latest_release_tag(args: Namespace) -> str:
|
|
193
217
|
args._latest_release.write_text(tag + '\n')
|
194
218
|
return tag
|
195
219
|
|
220
|
+
def get_release_name(filename: str) -> Optional[str]:
|
221
|
+
'Search for and strip the release name from the file name'
|
222
|
+
if not (m := re.search(ENDPAT, filename)):
|
223
|
+
return None
|
224
|
+
|
225
|
+
# Strip of end of file name and also strip any +8 digit embedded
|
226
|
+
# release date
|
227
|
+
return re.sub(r'\+\d{8}', '', filename[:m.start()])
|
228
|
+
|
196
229
|
def get_release_files(args, tag, implementation: Optional[str] = None) -> dict:
|
197
230
|
'Return the release files for the given tag'
|
198
231
|
# Look for tag data in our release cache
|
@@ -212,17 +245,11 @@ def get_release_files(args, tag, implementation: Optional[str] = None) -> dict:
|
|
212
245
|
|
213
246
|
# Iterate over the release assets and store the files in a dict to
|
214
247
|
# return
|
215
|
-
end = '-install_only.tar.gz'
|
216
248
|
for file in release.get_assets():
|
217
|
-
name
|
218
|
-
if not name.endswith(end):
|
249
|
+
if not (name := get_release_name(file.name)):
|
219
250
|
continue
|
220
251
|
|
221
|
-
|
222
|
-
impl_ver, rest = name.split('+', maxsplit=1)
|
223
|
-
impl, ver = impl_ver.split('-', maxsplit=1)
|
224
|
-
rest = rest.split('-', maxsplit=1)[1]
|
225
|
-
|
252
|
+
impl, ver, rest = name.split('-', maxsplit=2)
|
226
253
|
if impl not in files:
|
227
254
|
files[impl] = defaultdict(dict)
|
228
255
|
|
@@ -384,10 +411,13 @@ def main() -> Optional[str]:
|
|
384
411
|
help='cache latest release tag fetch for this many '
|
385
412
|
'minutes, before rechecking for latest. '
|
386
413
|
'Default is %(default)d minutes')
|
387
|
-
opt.add_argument('--purge-days', default=
|
414
|
+
opt.add_argument('--purge-days', default=90, type=int,
|
388
415
|
help='cache release file lists for this number '
|
389
416
|
'of days after last version referencing it is removed. '
|
390
417
|
'Default is %(default)d days')
|
418
|
+
opt.add_argument('--github-access-token',
|
419
|
+
help='Optional Github access token. Can specify to reduce '
|
420
|
+
'rate limiting.')
|
391
421
|
opt.add_argument('-V', action='store_true',
|
392
422
|
help=f'show {PROG} version')
|
393
423
|
cmd = opt.add_subparsers(title='Commands', dest='cmdname')
|
@@ -475,7 +505,7 @@ class _install(COMMAND):
|
|
475
505
|
|
476
506
|
@staticmethod
|
477
507
|
def run(args: Namespace) -> Optional[str]:
|
478
|
-
release =
|
508
|
+
release = get_release_tag(args)
|
479
509
|
files = get_release_files(args, release, 'cpython')
|
480
510
|
if not files:
|
481
511
|
return f'Release "{release}" not found, or has no compatible files.'
|
@@ -519,7 +549,7 @@ class _update(COMMAND):
|
|
519
549
|
|
520
550
|
@staticmethod
|
521
551
|
def run(args: Namespace) -> Optional[str]:
|
522
|
-
release_target =
|
552
|
+
release_target = get_release_tag(args)
|
523
553
|
files = get_release_files(args, release_target, 'cpython')
|
524
554
|
if not files:
|
525
555
|
return f'Release "{release_target}" not found.'
|
@@ -602,7 +632,7 @@ class _list(COMMAND):
|
|
602
632
|
|
603
633
|
@staticmethod
|
604
634
|
def run(args: Namespace) -> Optional[str]:
|
605
|
-
release_target =
|
635
|
+
release_target = get_release_tag(args)
|
606
636
|
files = get_release_files(args, release_target, 'cpython')
|
607
637
|
if not files:
|
608
638
|
return f'Release "{release_target}" not found.'
|
@@ -656,7 +686,7 @@ class _show(COMMAND):
|
|
656
686
|
|
657
687
|
@staticmethod
|
658
688
|
def run(args: Namespace) -> None:
|
659
|
-
release =
|
689
|
+
release = get_release_tag(args)
|
660
690
|
files = get_release_files(args, release, 'cpython')
|
661
691
|
if not files:
|
662
692
|
sys.exit(f'Error: release "{release}" not found.')
|
pystand-1.2.dist-info/RECORD
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
pystand.py,sha256=5X--S1zNpaEauP4FkubSe9J5FM3qQ1OO92ZcPlk__4I,26248
|
2
|
-
pystand-1.2.dist-info/METADATA,sha256=V72dn_zsBb0W0ym4lYh3EljiaOqY0s2l9fuszbK_EFg,14304
|
3
|
-
pystand-1.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
4
|
-
pystand-1.2.dist-info/entry_points.txt,sha256=DG4ps3I3nni1bubV1tXs6u8FARgkdbAYaEAzZD4RAo8,41
|
5
|
-
pystand-1.2.dist-info/top_level.txt,sha256=NoWUh19UQymAJLHTCdxMnVwV6Teftef5fzyF3OWLyNY,8
|
6
|
-
pystand-1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|