pyenv-native 0.1.10__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.
@@ -0,0 +1,38 @@
1
+ /target/
2
+ /dist/
3
+ /python-package/dist/
4
+ /packaging/winget/manifests/
5
+ /packaging/homebrew/Formula/
6
+ /python-package/src/**/*.pyc
7
+ /python-package/tests/**/*.pyc
8
+ **/__pycache__/
9
+ /.tmp*/
10
+ /test-install/
11
+
12
+ # Compiled binaries and debug symbols
13
+ *.exe
14
+ *.pdb
15
+
16
+ # AI Memory
17
+ MEMORY.md
18
+ .gemini/
19
+
20
+ # IDEs
21
+ .vscode/
22
+ .idea/
23
+
24
+ # Rust
25
+ Cargo.lock
26
+
27
+ # OS Junk
28
+ .DS_Store
29
+ Thumbs.db
30
+
31
+ # Local publish script (operator-only, not for distribution)
32
+ /scripts/publish.ps1
33
+
34
+ # Reproduction and scratch scripts
35
+ /repro_*.rs
36
+ /temp_*.rs
37
+ /clippy_errors.txt
38
+ /walkthrough.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Roy Dawson IV
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyenv-native
3
+ Version: 0.1.10
4
+ Summary: Python install package for the native-first pyenv-native runtime bundles.
5
+ Project-URL: Homepage, https://github.com/imyourboyroy
6
+ Project-URL: Repository, https://github.com/imyourboyroy/pyenv-native
7
+ Project-URL: Issues, https://github.com/imyourboyroy/pyenv-native/issues
8
+ Author-email: Roy Dawson IV <Roy.Dawson.IV@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: bootstrap,pipx,pyenv,python,windows
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Software Development
26
+ Classifier: Topic :: System :: Installation/Setup
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+
30
+ # pyenv-native
31
+
32
+ ![PyPI Channel](https://img.shields.io/badge/channel-PyPI%20%2F%20pipx-3775A9?style=for-the-badge&logo=pypi&logoColor=white)
33
+ ![Runtime](https://img.shields.io/badge/runtime-install%20package%20for%20native%20bundles-2563eb?style=for-the-badge)
34
+ ![License](https://img.shields.io/badge/license-MIT-15803D?style=for-the-badge)
35
+
36
+ `pyenv-native` on PyPI is the Python convenience package for installing the native `pyenv-native` release bundles.
37
+
38
+ Those bundles install both:
39
+ - `pyenv`
40
+ - `pyenv-mcp`
41
+
42
+ It exists for users who:
43
+ - already have Python installed,
44
+ - want a `pip` or `pipx` entrypoint,
45
+ - still want the real runtime to remain native.
46
+
47
+ ## Important principle
48
+
49
+ > This package installs `pyenv-native`.
50
+ > It does **not** replace `pyenv-native` with a Python implementation.
51
+
52
+ ## Release selection behavior
53
+
54
+ By default, the package targets the **latest published GitHub release**.
55
+
56
+ ## What it does
57
+
58
+ - downloads native release bundles,
59
+ - verifies checksums,
60
+ - reads bundle metadata,
61
+ - extracts the bundle,
62
+ - runs the bundled installer,
63
+ - installs the companion `pyenv-mcp` server when the bundle provides it,
64
+ - supports GitHub Release-based installs,
65
+ - works with Windows ZIP bundles and Linux/macOS `.tar.gz` bundles.
66
+
67
+ ## Quick start
68
+
69
+ ### `pipx` latest release
70
+
71
+ ```powershell
72
+ pipx install pyenv-native
73
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
74
+ ```
75
+
76
+ ### `pip` latest release
77
+
78
+ ```powershell
79
+ python -m pip install pyenv-native
80
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
81
+ ```
82
+
83
+ ### POSIX latest release
84
+
85
+ ```sh
86
+ python -m pip install pyenv-native
87
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~/.pyenv
88
+ ```
89
+
90
+ ## Commands
91
+
92
+ ```text
93
+ pyenv-native verify <bundle-archive> [--checksum-path <bundle.sha256>]
94
+ pyenv-native download [--bundle-url <url> | --release-base-url <url> | --github-repo <owner/repo>] [--tag <tag>]
95
+ pyenv-native install [--bundle-path <bundle-archive> | --release-base-url <url> | --github-repo <owner/repo>] [--tag <tag>] [--install-root <dir>]
96
+ ```
97
+
98
+ ## Examples
99
+
100
+ Verify a local bundle:
101
+
102
+ ```powershell
103
+ pyenv-native verify .\dist\pyenv-native-windows-x64.zip --checksum-path .\dist\pyenv-native-windows-x64.zip.sha256
104
+ ```
105
+
106
+ Install from a local bundle:
107
+
108
+ ```powershell
109
+ pyenv-native install --bundle-path .\dist\pyenv-native-windows-x64.zip --checksum-path .\dist\pyenv-native-windows-x64.zip.sha256 --install-root ~\.pyenv
110
+ ```
111
+
112
+ Install from the latest GitHub release:
113
+
114
+ ```powershell
115
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
116
+ ```
117
+
118
+ Install a POSIX bundle:
119
+
120
+ ```sh
121
+ pyenv-native install --bundle-path ./dist/pyenv-native-linux-x64.tar.gz --checksum-path ./dist/pyenv-native-linux-x64.tar.gz.sha256 --install-root ~/.pyenv --shell bash
122
+ ```
123
+
124
+ ## Relationship to the main project
125
+
126
+ For the full project overview, install scripts, release-bundle flow, and command reference, see the main repository README:
127
+
128
+ - <https://github.com/imyourboyroy/pyenv-native>
@@ -0,0 +1,99 @@
1
+ # pyenv-native
2
+
3
+ ![PyPI Channel](https://img.shields.io/badge/channel-PyPI%20%2F%20pipx-3775A9?style=for-the-badge&logo=pypi&logoColor=white)
4
+ ![Runtime](https://img.shields.io/badge/runtime-install%20package%20for%20native%20bundles-2563eb?style=for-the-badge)
5
+ ![License](https://img.shields.io/badge/license-MIT-15803D?style=for-the-badge)
6
+
7
+ `pyenv-native` on PyPI is the Python convenience package for installing the native `pyenv-native` release bundles.
8
+
9
+ Those bundles install both:
10
+ - `pyenv`
11
+ - `pyenv-mcp`
12
+
13
+ It exists for users who:
14
+ - already have Python installed,
15
+ - want a `pip` or `pipx` entrypoint,
16
+ - still want the real runtime to remain native.
17
+
18
+ ## Important principle
19
+
20
+ > This package installs `pyenv-native`.
21
+ > It does **not** replace `pyenv-native` with a Python implementation.
22
+
23
+ ## Release selection behavior
24
+
25
+ By default, the package targets the **latest published GitHub release**.
26
+
27
+ ## What it does
28
+
29
+ - downloads native release bundles,
30
+ - verifies checksums,
31
+ - reads bundle metadata,
32
+ - extracts the bundle,
33
+ - runs the bundled installer,
34
+ - installs the companion `pyenv-mcp` server when the bundle provides it,
35
+ - supports GitHub Release-based installs,
36
+ - works with Windows ZIP bundles and Linux/macOS `.tar.gz` bundles.
37
+
38
+ ## Quick start
39
+
40
+ ### `pipx` latest release
41
+
42
+ ```powershell
43
+ pipx install pyenv-native
44
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
45
+ ```
46
+
47
+ ### `pip` latest release
48
+
49
+ ```powershell
50
+ python -m pip install pyenv-native
51
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
52
+ ```
53
+
54
+ ### POSIX latest release
55
+
56
+ ```sh
57
+ python -m pip install pyenv-native
58
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~/.pyenv
59
+ ```
60
+
61
+ ## Commands
62
+
63
+ ```text
64
+ pyenv-native verify <bundle-archive> [--checksum-path <bundle.sha256>]
65
+ pyenv-native download [--bundle-url <url> | --release-base-url <url> | --github-repo <owner/repo>] [--tag <tag>]
66
+ pyenv-native install [--bundle-path <bundle-archive> | --release-base-url <url> | --github-repo <owner/repo>] [--tag <tag>] [--install-root <dir>]
67
+ ```
68
+
69
+ ## Examples
70
+
71
+ Verify a local bundle:
72
+
73
+ ```powershell
74
+ pyenv-native verify .\dist\pyenv-native-windows-x64.zip --checksum-path .\dist\pyenv-native-windows-x64.zip.sha256
75
+ ```
76
+
77
+ Install from a local bundle:
78
+
79
+ ```powershell
80
+ pyenv-native install --bundle-path .\dist\pyenv-native-windows-x64.zip --checksum-path .\dist\pyenv-native-windows-x64.zip.sha256 --install-root ~\.pyenv
81
+ ```
82
+
83
+ Install from the latest GitHub release:
84
+
85
+ ```powershell
86
+ pyenv-native install --github-repo imyourboyroy/pyenv-native --install-root ~\.pyenv
87
+ ```
88
+
89
+ Install a POSIX bundle:
90
+
91
+ ```sh
92
+ pyenv-native install --bundle-path ./dist/pyenv-native-linux-x64.tar.gz --checksum-path ./dist/pyenv-native-linux-x64.tar.gz.sha256 --install-root ~/.pyenv --shell bash
93
+ ```
94
+
95
+ ## Relationship to the main project
96
+
97
+ For the full project overview, install scripts, release-bundle flow, and command reference, see the main repository README:
98
+
99
+ - <https://github.com/imyourboyroy/pyenv-native>
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pyenv-native"
7
+ version = "0.1.10"
8
+ description = "Python install package for the native-first pyenv-native runtime bundles."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Roy Dawson IV", email = "Roy.Dawson.IV@gmail.com" },
14
+ ]
15
+ keywords = ["pyenv", "python", "windows", "bootstrap", "pipx"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: Microsoft :: Windows",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: 3.8",
25
+ "Programming Language :: Python :: 3.9",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: Software Development",
31
+ "Topic :: System :: Installation/Setup",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/imyourboyroy"
36
+ Repository = "https://github.com/imyourboyroy/pyenv-native"
37
+ Issues = "https://github.com/imyourboyroy/pyenv-native/issues"
38
+
39
+ [project.scripts]
40
+ pyenv-native = "pyenv_native_bootstrap.cli:main"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/pyenv_native_bootstrap"]
44
+
45
+ [tool.hatch.build.targets.sdist]
46
+ include = [
47
+ "src/pyenv_native_bootstrap",
48
+ "tests",
49
+ "LICENSE",
50
+ "README.md",
51
+ "pyproject.toml",
52
+ ]
53
+
54
+
55
+
@@ -0,0 +1,6 @@
1
+ # ./python-package/src/pyenv_native_bootstrap/__init__.py
2
+ """Package metadata for the pyenv-native bootstrap helper."""
3
+
4
+ __all__ = ["__version__"]
5
+
6
+ __version__ = "0.1.10"
@@ -0,0 +1,8 @@
1
+ # ./python-package/src/pyenv_native_bootstrap/__main__.py
2
+ """Module runner for `python -m pyenv_native_bootstrap`."""
3
+
4
+ from .cli import main
5
+
6
+
7
+ if __name__ == "__main__":
8
+ raise SystemExit(main())
@@ -0,0 +1,163 @@
1
+ # ./python-package/src/pyenv_native_bootstrap/bundle.py
2
+ """Bundle metadata, checksum, and download helpers for pyenv-native release assets."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import json
8
+ import tarfile
9
+ import urllib.request
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+ from typing import Optional
13
+ from zipfile import ZipFile
14
+
15
+ from . import __version__
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class BundleManifest:
20
+ """Describes a built release bundle and the scripts it carries."""
21
+
22
+ bundle_name: str
23
+ bundle_version: str
24
+ platform: str
25
+ architecture: str
26
+ executable: str
27
+ install_script: str
28
+ uninstall_script: str
29
+
30
+
31
+ def sha256_file(path: Path) -> str:
32
+ """Return the SHA-256 digest for a file."""
33
+
34
+ digest = hashlib.sha256()
35
+ with path.open("rb") as handle:
36
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
37
+ digest.update(chunk)
38
+ return digest.hexdigest()
39
+
40
+
41
+ def parse_checksum_text(text: str, expected_file_name: Optional[str] = None) -> str:
42
+ """Extract a SHA-256 value from a checksum file or raw string."""
43
+
44
+ lines = [line.strip() for line in text.splitlines() if line.strip()]
45
+ if not lines:
46
+ raise ValueError("checksum text did not contain any usable lines")
47
+
48
+ for line in lines:
49
+ parts = line.split()
50
+ if len(parts) == 1 and len(parts[0]) == 64:
51
+ return parts[0].lower()
52
+ if len(parts) >= 2 and len(parts[0]) == 64:
53
+ candidate_name = parts[-1].lstrip("*")
54
+ if expected_file_name is None or candidate_name == expected_file_name:
55
+ return parts[0].lower()
56
+
57
+ raise ValueError("checksum text did not contain a valid SHA-256 entry")
58
+
59
+
60
+ def is_tar_bundle(bundle_path: Path) -> bool:
61
+ """Return true when a bundle path uses a tar-based archive format."""
62
+
63
+ suffixes = [suffix.lower() for suffix in bundle_path.suffixes]
64
+ return suffixes[-2:] == [".tar", ".gz"] or bundle_path.suffix.lower() == ".tgz"
65
+
66
+
67
+ def read_manifest_from_bundle(bundle_path: Path) -> BundleManifest:
68
+ """Read and parse the bundle manifest embedded inside a release archive."""
69
+
70
+ if is_tar_bundle(bundle_path):
71
+ with tarfile.open(bundle_path, "r:*") as archive:
72
+ member = next(
73
+ (
74
+ candidate
75
+ for candidate in archive.getmembers()
76
+ if Path(candidate.name).name == "bundle-manifest.json"
77
+ ),
78
+ None,
79
+ )
80
+ if member is None:
81
+ raise FileNotFoundError("bundle-manifest.json was not found in the bundle archive")
82
+ handle = archive.extractfile(member)
83
+ if handle is None:
84
+ raise FileNotFoundError("bundle-manifest.json could not be extracted")
85
+ payload = json.loads(handle.read().decode("utf-8-sig"))
86
+ else:
87
+ with ZipFile(bundle_path, "r") as archive:
88
+ with archive.open("bundle-manifest.json", "r") as handle:
89
+ payload = json.loads(handle.read().decode("utf-8-sig"))
90
+
91
+ return BundleManifest(
92
+ bundle_name=payload["bundle_name"],
93
+ bundle_version=payload["bundle_version"],
94
+ platform=payload["platform"],
95
+ architecture=payload["architecture"],
96
+ executable=payload["executable"],
97
+ install_script=payload["install_script"],
98
+ uninstall_script=payload["uninstall_script"],
99
+ )
100
+
101
+
102
+ def read_manifest_from_zip(bundle_path: Path) -> BundleManifest:
103
+ """Backward-compatible wrapper for zip-based bundle manifest reads."""
104
+
105
+ return read_manifest_from_bundle(bundle_path)
106
+
107
+
108
+ def download_file(url: str, destination: Path) -> Path:
109
+ """Download a file to a destination path, replacing any prior file."""
110
+
111
+ destination.parent.mkdir(parents=True, exist_ok=True)
112
+ request = urllib.request.Request(
113
+ url,
114
+ headers={"User-Agent": f"pyenv-native/{__version__}"},
115
+ )
116
+ with urllib.request.urlopen(request) as response, destination.open("wb") as handle: # noqa: S310
117
+ handle.write(response.read())
118
+ return destination
119
+
120
+
121
+ def load_checksum_text(
122
+ checksum: Optional[str],
123
+ checksum_path: Optional[Path],
124
+ checksum_url: Optional[str],
125
+ cache_path: Path,
126
+ ) -> Optional[str]:
127
+ """Load checksum content from an inline value, local file, or remote URL."""
128
+
129
+ if checksum:
130
+ return checksum.strip()
131
+ if checksum_path:
132
+ return checksum_path.read_text(encoding="utf-8")
133
+ if checksum_url:
134
+ checksum_target = cache_path.with_suffix(cache_path.suffix + ".sha256")
135
+ download_file(checksum_url, checksum_target)
136
+ return checksum_target.read_text(encoding="utf-8")
137
+ return None
138
+
139
+
140
+ def verify_bundle_checksum(
141
+ bundle_path: Path,
142
+ checksum: Optional[str] = None,
143
+ checksum_path: Optional[Path] = None,
144
+ checksum_url: Optional[str] = None,
145
+ ) -> str:
146
+ """Verify the bundle against a supplied checksum source and return the digest."""
147
+
148
+ checksum_text = load_checksum_text(
149
+ checksum=checksum,
150
+ checksum_path=checksum_path,
151
+ checksum_url=checksum_url,
152
+ cache_path=bundle_path,
153
+ )
154
+ actual = sha256_file(bundle_path)
155
+ if checksum_text is None:
156
+ return actual
157
+
158
+ expected = parse_checksum_text(checksum_text, bundle_path.name)
159
+ if actual.lower() != expected.lower():
160
+ raise ValueError(
161
+ f"checksum mismatch for {bundle_path}: expected {expected}, got {actual}"
162
+ )
163
+ return actual