Closed2
pip downloadの挙動
% python
Python 3.11.10 (main, Oct 16 2024, 08:56:36) [Clang 18.1.8 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.run(["pip", "download", "literalai==0.1.201", "--only-binary=:all:"])
ERROR: Could not find a version that satisfies the requirement literalai==0.1.201 (from versions: 0.0.1, 0.0.101, 0.0.102)
ERROR: No matching distribution found for literalai==0.1.201
[notice] A new release of pip is available: 24.0 -> 25.1
[notice] To update, run: pip install --upgrade pip
CompletedProcess(args=['pip', 'download', 'literalai==0.1.201', '--only-binary=:all:'], returncode=1)
>>> res = subprocess.run(["pip", "download", "literalai==0.1.201", "--only-binary=:all:"], capture_output=True, text=True)
>>> res
CompletedProcess(args=['pip', 'download', 'literalai==0.1.201', '--only-binary=:all:'], returncode=1, stdout='', stderr='ERROR: Could not find a version that satisfies the requirement literalai==0.1.201 (from versions: 0.0.1, 0.0.101, 0.0.102)\nERROR: No matching distribution found for literalai==0.1.201\n\n[notice] A new release of pip is available: 24.0 -> 25.1\n[notice] To update, run: pip install --upgrade pip\n')
>>> res = subprocess.run(["pip", "download", "literalai==0.0.1", "--only-binary=:all:"], capture_output=True, text=True)
>>> res
CompletedProcess(args=['pip', 'download', 'literalai==0.0.1', '--only-binary=:all:'], returncode=0, stdout='Collecting literalai==0.0.1\n Using cached literalai-0.0.1-py3-none-any.whl.metadata (243 bytes)\nCollecting packaging>=23.0 (from literalai==0.0.1)\n Using cached packaging-25.0-py3-none-any.whl.metadata (3.3 kB)\nCollecting httpx<0.25.0,>=0.23.0 (from literalai==0.0.1)\n Using cached httpx-0.24.1-py3-none-any.whl.metadata (7.4 kB)\nCollecting pydantic<3,>=1 (from literalai==0.0.1)\n Using cached pydantic-2.11.3-py3-none-any.whl.metadata (65 kB)\nCollecting certifi (from httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Using cached certifi-2025.4.26-py3-none-any.whl.metadata (2.5 kB)\nCollecting httpcore<0.18.0,>=0.15.0 (from httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Downloading httpcore-0.17.3-py3-none-any.whl.metadata (18 kB)\nCollecting idna (from httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Using cached idna-3.10-py3-none-any.whl.metadata (10 kB)\nCollecting sniffio (from httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Using cached sniffio-1.3.1-py3-none-any.whl.metadata (3.9 kB)\nCollecting annotated-types>=0.6.0 (from pydantic<3,>=1->literalai==0.0.1)\n Using cached annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB)\nCollecting pydantic-core==2.33.1 (from pydantic<3,>=1->literalai==0.0.1)\n Using cached pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl.metadata (6.8 kB)\nCollecting typing-extensions>=4.12.2 (from pydantic<3,>=1->literalai==0.0.1)\n Using cached typing_extensions-4.13.2-py3-none-any.whl.metadata (3.0 kB)\nCollecting typing-inspection>=0.4.0 (from pydantic<3,>=1->literalai==0.0.1)\n Using cached typing_inspection-0.4.0-py3-none-any.whl.metadata (2.6 kB)\nCollecting h11<0.15,>=0.13 (from httpcore<0.18.0,>=0.15.0->httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Using cached h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)\nCollecting anyio<5.0,>=3.0 (from httpcore<0.18.0,>=0.15.0->httpx<0.25.0,>=0.23.0->literalai==0.0.1)\n Using cached anyio-4.9.0-py3-none-any.whl.metadata (4.7 kB)\nDownloading literalai-0.0.1-py3-none-any.whl (30 kB)\nDownloading httpx-0.24.1-py3-none-any.whl (75 kB)\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 75.4/75.4 kB 3.2 MB/s eta 0:00:00\nUsing cached packaging-25.0-py3-none-any.whl (66 kB)\nUsing cached pydantic-2.11.3-py3-none-any.whl (443 kB)\nUsing cached pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl (1.9 MB)\nUsing cached annotated_types-0.7.0-py3-none-any.whl (13 kB)\nDownloading httpcore-0.17.3-py3-none-any.whl (74 kB)\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 74.5/74.5 kB 5.9 MB/s eta 0:00:00\nUsing cached sniffio-1.3.1-py3-none-any.whl (10 kB)\nUsing cached typing_extensions-4.13.2-py3-none-any.whl (45 kB)\nUsing cached typing_inspection-0.4.0-py3-none-any.whl (14 kB)\nUsing cached certifi-2025.4.26-py3-none-any.whl (159 kB)\nUsing cached idna-3.10-py3-none-any.whl (70 kB)\nUsing cached anyio-4.9.0-py3-none-any.whl (100 kB)\nUsing cached h11-0.14.0-py3-none-any.whl (58 kB)\nSaved ./literalai-0.0.1-py3-none-any.whl\nSaved ./httpx-0.24.1-py3-none-any.whl\nSaved ./packaging-25.0-py3-none-any.whl\nSaved ./pydantic-2.11.3-py3-none-any.whl\nSaved ./pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl\nSaved ./annotated_types-0.7.0-py3-none-any.whl\nSaved ./httpcore-0.17.3-py3-none-any.whl\nSaved ./sniffio-1.3.1-py3-none-any.whl\nSaved ./typing_extensions-4.13.2-py3-none-any.whl\nSaved ./typing_inspection-0.4.0-py3-none-any.whl\nSaved ./certifi-2025.4.26-py3-none-any.whl\nSaved ./idna-3.10-py3-none-any.whl\nSaved ./anyio-4.9.0-py3-none-any.whl\nSaved ./h11-0.14.0-py3-none-any.whl\nSuccessfully downloaded literalai httpx packaging pydantic pydantic-core annotated-types httpcore sniffio typing-extensions typing-inspection certifi idna anyio h11\n', stderr='\n[notice] A new release of pip is available: 24.0 -> 25.1\n[notice] To update, run: pip install --upgrade pip\n')
動的にwheelをダウンロードしてビルドするスクリプト。不要になったので供養。
オリジナルは https://github.com/xhiroga/blender-mcp-senpai/blob/main/extension/build.py
import json
import os
import shutil
import subprocess
import tempfile
import tomllib
from dataclasses import dataclass
import bpy
import tomlkit
PLATFORMS = ["windows-x64", "linux-x64", "macos-arm64", "macos-x64"]
ZIP_TARGET_DIR = "mcp_senpai"
OUTPUT_DIR = "output"
DOCS_EXTENSIONS_DIR = "../docs/extensions"
@dataclass
class Platform:
pypi_suffix: str
metadata: str
windows_x64 = Platform(pypi_suffix="win_amd64", metadata="windows-x64")
linux_x64 = Platform(pypi_suffix="manylinux2014_x86_64", metadata="linux-x64")
macos_arm = Platform(pypi_suffix="macosx_12_0_arm64", metadata="macos-arm64")
macos_intel = Platform(pypi_suffix="macosx_10_16_x86_64", metadata="macos-x64")
platforms = [windows_x64, linux_x64, macos_arm, macos_intel]
def dependencies() -> list[str]:
try:
completed_proc = subprocess.run(
[
"uv",
"export",
"--package",
"extension",
"--no-annotate",
"--no-hashes",
"--no-header",
],
capture_output=True,
text=True,
check=True,
)
except subprocess.CalledProcessError as e:
print(f"{e.stderr=}")
return []
deps: list[str] = []
for line in completed_proc.stdout.splitlines():
if not line or line.startswith("#") or line.startswith((" ", "\t")):
continue
deps.append(line.split(";")[0].strip())
return deps
def get_version() -> str:
with open("pyproject.toml", mode="rb") as f:
pyproject = tomllib.load(f)
return pyproject["project"]["version"]
def get_pip() -> str:
return "pip" if shutil.which("pip") is not None else "pip3"
def get_git_commit_hash() -> str:
try:
result = subprocess.run(
["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return ""
def download_wheel(
dep: str,
python_version: str,
platform: Platform,
wheels_dest_dir: str,
):
print(f"{dep=}, {python_version=}, {platform=}, {wheels_dest_dir=}")
pip = get_pip()
download_bin_proc_completed = subprocess.run(
[
pip,
"download",
dep,
"-d",
wheels_dest_dir,
"--only-binary=:all:",
f"--python-version={python_version}",
f"--platform={platform.pypi_suffix}",
"--no-deps", # deps are resolved by uv export
],
capture_output=True,
text=True,
)
ERROR_MESSAGE = "ERROR: Could not find a version that satisfies the requirement"
if ERROR_MESSAGE in download_bin_proc_completed.stderr:
with tempfile.TemporaryDirectory() as temp_dir:
print(
f"{dep=} is not found in index. Downloading source and building wheel..."
)
try:
download_src_proc_completed = subprocess.run(
[
pip,
"download",
dep,
"--no-binary=:all:",
"-d",
temp_dir,
"--no-deps",
],
capture_output=True,
text=True,
check=True,
)
except subprocess.CalledProcessError as e:
print(f"{e.stderr=}")
return
tar_gz_file = None
for line in download_src_proc_completed.stdout.splitlines():
if "Saved" in line or "File was already downloaded" in line:
tar_gz_file = line.split("/")[-1]
if tar_gz_file is None:
print(f"{dep=} is not found in {temp_dir=}")
return
source_files = os.path.join(temp_dir, tar_gz_file)
try:
wheel_completed = subprocess.run(
[
pip,
"wheel",
"--no-deps",
"--wheel-dir",
wheels_dest_dir,
source_files,
],
capture_output=True,
text=True,
check=True,
)
print(f"{wheel_completed.stdout=}")
except subprocess.CalledProcessError as e:
print(f"{e.stderr=}")
return
def generate_blender_manifest():
with open("blender_manifest_template.toml", mode="r") as f:
manifest = tomlkit.load(f)
manifest["platforms"] = [platform.metadata for platform in platforms]
manifest["commit"] = get_git_commit_hash()
manifest["version"] = get_version()
manifest["wheels"] = [
f"./wheels/{f}"
for f in os.listdir(f"{ZIP_TARGET_DIR}/wheels")
if f.endswith(".whl")
]
with open(f"{ZIP_TARGET_DIR}/blender_manifest.toml", mode="w") as f:
tomlkit.dump(manifest, f)
def build():
os.makedirs(OUTPUT_DIR, exist_ok=True)
# On macOS or WSL, bpy.app.binary_path is empty.
blender_exe = os.environ.get("BLENDER_EXE") or bpy.app.binary_path
print(f"{blender_exe=}")
subprocess.run(
[
blender_exe,
"--factory-startup",
"--command",
"extension",
"build",
"--split-platforms",
"--source-dir",
ZIP_TARGET_DIR,
"--output-dir",
OUTPUT_DIR,
],
)
def index_json():
blender_exe = os.environ.get("BLENDER_EXE") or bpy.app.binary_path
print(f"{blender_exe=}")
subprocess.run(
[
blender_exe,
"--factory-startup",
"--command",
"extension",
"server-generate",
"--repo-dir",
OUTPUT_DIR,
],
)
def deploy_json():
os.makedirs(DOCS_EXTENSIONS_DIR, exist_ok=True)
with open(f"{OUTPUT_DIR}/index.json", "r") as f:
index_data = json.load(f)
version = get_version()
for item in index_data.get("data", []):
if "archive_url" in item:
filename = os.path.basename(item["archive_url"])
item["archive_url"] = (
f"https://github.com/xhiroga/blender-mcp-senpai/releases/download/v{version}/{filename}"
)
with open(f"{DOCS_EXTENSIONS_DIR}/index.json", "w") as f:
json.dump(index_data, f, indent=2)
def main():
wheels_dest_dir = f"{ZIP_TARGET_DIR}/wheels"
os.makedirs(wheels_dest_dir, exist_ok=True)
deps = dependencies()
python_version = "3.11"
for platform in platforms:
for dep in deps:
download_wheel(dep, python_version, platform, wheels_dest_dir)
generate_blender_manifest()
build()
index_json()
deploy_json()
if __name__ == "__main__":
main()
このスクラップは4ヶ月前にクローズされました