pbs-installer 2024.3.27__tar.gz → 2024.4.1__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,9 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pbs-installer
3
- Version: 2024.3.27
3
+ Version: 2024.4.1
4
4
  Summary: Installer for Python Build Standalone
5
5
  Author-Email: Frost Ming <me@frostming.com>
6
6
  License: MIT
7
+ Project-URL: Repository, https://github.com/frostming/pbs-installer
8
+ Project-URL: Documentation, http://pbs-installer.readthedocs.io
7
9
  Requires-Python: >=3.8
8
10
  Provides-Extra: download
9
11
  Provides-Extra: install
@@ -7,11 +7,15 @@ authors = [
7
7
  requires-python = ">=3.8"
8
8
  readme = "README.md"
9
9
  dynamic = []
10
- version = "2024.3.27"
10
+ version = "2024.4.1"
11
11
 
12
12
  [project.license]
13
13
  text = "MIT"
14
14
 
15
+ [project.urls]
16
+ Repository = "https://github.com/frostming/pbs-installer"
17
+ Documentation = "http://pbs-installer.readthedocs.io"
18
+
15
19
  [project.optional-dependencies]
16
20
  download = [
17
21
  "httpx<1,>=0.27.0",
@@ -33,6 +33,7 @@ def get_download_link(
33
33
  arch: str = THIS_ARCH,
34
34
  platform: str = THIS_PLATFORM,
35
35
  implementation: str = "cpython",
36
+ build_dir: bool = False,
36
37
  ) -> tuple[PythonVersion, PythonFile]:
37
38
  """Get the download URL matching the given requested version.
38
39
 
@@ -41,6 +42,7 @@ def get_download_link(
41
42
  arch: The architecture to install, e.g. x86_64, arm64
42
43
  platform: The platform to install, e.g. linux, macos
43
44
  implementation: The implementation of Python to install, allowed values are 'cpython' and 'pypy'
45
+ build_dir: Whether to include the `build/` directory from indygreg builds
44
46
 
45
47
  Returns:
46
48
  A tuple of the PythonVersion and the download URL
@@ -56,9 +58,11 @@ def get_download_link(
56
58
  if not py_ver.matches(request, implementation):
57
59
  continue
58
60
 
59
- matched = urls.get((platform, arch))
61
+ matched = urls.get((platform, arch, not build_dir))
60
62
  if matched is not None:
61
63
  return py_ver, matched
64
+ if build_dir and (matched := urls.get((platform, arch, False))) is not None:
65
+ return py_ver, matched
62
66
  raise ValueError(
63
67
  f"Could not find a version matching version={request!r}, implementation={implementation}"
64
68
  )
@@ -137,11 +141,11 @@ def install_file(
137
141
  original_filename,
138
142
  )
139
143
  if original_filename.endswith(".zst"):
140
- unpack_zst(filename, destination, build_dir)
144
+ unpack_zst(filename, destination)
141
145
  elif original_filename.endswith(".zip"):
142
- unpack_zip(filename, destination, build_dir)
146
+ unpack_zip(filename, destination)
143
147
  else:
144
- unpack_tar(filename, destination, build_dir)
148
+ unpack_tar(filename, destination)
145
149
 
146
150
 
147
151
  def install(
@@ -181,7 +185,7 @@ def install(
181
185
  arch = THIS_ARCH
182
186
 
183
187
  ver, python_file = get_download_link(
184
- request, arch=arch, platform=platform, implementation=implementation
188
+ request, arch=arch, platform=platform, implementation=implementation, build_dir=build_dir
185
189
  )
186
190
  if version_dir:
187
191
  destination = os.path.join(destination, str(ver))
@@ -53,36 +53,31 @@ def get_arch_platform() -> tuple[str, str]:
53
53
  return ARCH_MAPPING.get(arch, arch), PLATFORM_MAPPING.get(plat, plat)
54
54
 
55
55
 
56
- def _unpack_tar(tf: tarfile.TarFile, destination: StrPath, build_dir: bool = False) -> None:
56
+ def _unpack_tar(tf: tarfile.TarFile, destination: StrPath) -> None:
57
57
  """Unpack the tarfile to the destination, with the first skip_parts parts of the path removed"""
58
58
  members: list[tarfile.TarInfo] = []
59
- has_build = any(
60
- (p := fn.lstrip("/").split("/")) and len(p) > 1 and p[1] == "build" for fn in tf.getnames()
61
- )
62
59
  for member in tf.getmembers():
63
60
  parts = member.name.lstrip("/").split("/")
64
- if build_dir or not has_build:
65
- member.name = "/".join(parts[1:])
66
- elif len(parts) > 1 and parts[1] == "install":
67
- member.name = "/".join(parts[2:])
68
- else:
69
- continue
61
+ member.name = "/".join(parts[1:])
70
62
  if member.name:
71
63
  members.append(member)
72
64
  tf.extractall(destination, members=members)
73
65
 
74
66
 
75
- def unpack_tar(filename: str, destination: StrPath, build_dir: bool = False) -> None:
67
+ def unpack_tar(filename: str, destination: StrPath) -> None:
76
68
  """Unpack the tarfile to the destination"""
77
69
  with tarfile.open(filename) as z:
78
- _unpack_tar(z, destination, build_dir=build_dir)
70
+ _unpack_tar(z, destination)
79
71
 
80
72
 
81
- def unpack_zst(filename: str, destination: StrPath, build_dir: bool = False) -> None:
73
+ def unpack_zst(filename: str, destination: StrPath) -> None:
82
74
  """Unpack the zstd compressed tarfile to the destination"""
83
75
  import tempfile
84
76
 
85
- import zstandard as zstd
77
+ try:
78
+ import zstandard as zstd
79
+ except ModuleNotFoundError:
80
+ raise ModuleNotFoundError("zstandard is required to unpack .zst files") from None
86
81
 
87
82
  dctx = zstd.ZstdDecompressor()
88
83
  with tempfile.TemporaryFile(suffix=".tar") as ofh:
@@ -90,24 +85,18 @@ def unpack_zst(filename: str, destination: StrPath, build_dir: bool = False) ->
90
85
  dctx.copy_stream(ifh, ofh)
91
86
  ofh.seek(0)
92
87
  with tarfile.open(fileobj=ofh) as z:
93
- _unpack_tar(z, destination, build_dir=build_dir)
88
+ _unpack_tar(z, destination)
94
89
 
95
90
 
96
- def unpack_zip(filename: str, destination: StrPath, build_dir: bool = False) -> None:
91
+ def unpack_zip(filename: str, destination: StrPath) -> None:
97
92
  """Unpack the zip file to the destination"""
98
93
  import zipfile
99
94
 
100
95
  with zipfile.ZipFile(filename) as z:
101
96
  members: list[zipfile.ZipInfo] = []
102
- has_build = any(fn.lstrip("/").split("/")[1] == "build" for fn in z.namelist())
103
97
  for member in z.infolist():
104
98
  parts = member.filename.lstrip("/").split("/")
105
- if (build_dir or not has_build) and len(parts) > 1:
106
- member.filename = "/".join(parts[1:])
107
- elif len(parts) > 1 and parts[1] == "install":
108
- member.filename = "/".join(parts[2:])
109
- else:
110
- continue
99
+ member.filename = "/".join(parts[1:])
111
100
  if member.filename:
112
101
  members.append(member)
113
102